diff options
author | Steven Bennetts <steve@lindenlab.com> | 2007-03-02 21:25:50 +0000 |
---|---|---|
committer | Steven Bennetts <steve@lindenlab.com> | 2007-03-02 21:25:50 +0000 |
commit | 4dabd9c0472deb49573fdafef2fa413e59703f19 (patch) | |
tree | 06c680d6a2047e03838d6548bccd26c7baf9d652 | |
parent | d4462963c6ba5db2088723bbedc7b60f1184c594 (diff) |
merge release@58699 beta-1-14-0@58707 -> release
238 files changed, 17290 insertions, 14541 deletions
diff --git a/doc/LICENSE-logos.txt b/doc/LICENSE-logos.txt index 53b417cab6..0ca7dfd491 100644 --- a/doc/LICENSE-logos.txt +++ b/doc/LICENSE-logos.txt @@ -6,7 +6,12 @@ Research, Inc. Other trademarks include (but are not limited to): the names Linden and Linden Research, as well as the Linden Lab Hexagon Design and the Second Life Hand Design logos. -Use of logos and trademarks are subject to the Linden Lab trademark -policy, available at: - +The copyrightable materials in this file that are owned by Linden Lab +are "Work" licensed under Creative Commons license Attribution-Share +Alike 2.5 (summarized at +http://creativecommons.org/licenses/by-sa/2.5/ , full text of license +at http://creativecommons.org/licenses/by-sa/2.5/legalcode); provided +however that all trademarks of Linden Lab are subject to the Linden +Lab trademark policy, available at http://secondlife.com/corporate/trademark/ + diff --git a/indra/llaudio/llaudiodecodemgr.cpp b/indra/llaudio/llaudiodecodemgr.cpp index a2a594f2eb..9d8d91a58e 100644 --- a/indra/llaudio/llaudiodecodemgr.cpp +++ b/indra/llaudio/llaudiodecodemgr.cpp @@ -33,9 +33,25 @@ LLAudioDecodeMgr *gAudioDecodeMgrp = NULL; static const S32 WAV_HEADER_SIZE = 44; -class LLVorbisDecodeState + +////////////////////////////////////////////////////////////////////////////// + + +class LLVorbisDecodeState : public LLRefCount { public: + class WriteResponder : public LLLFSThread::Responder + { + public: + WriteResponder(LLVorbisDecodeState* decoder) : mDecoder(decoder) {} + ~WriteResponder() {} + void completed(S32 bytes) + { + mDecoder->ioComplete(bytes); + } + LLPointer<LLVorbisDecodeState> mDecoder; + }; + LLVorbisDecodeState(const LLUUID &uuid, const LLString &out_filename); virtual ~LLVorbisDecodeState(); @@ -45,12 +61,14 @@ public: void flushBadFile(); + void ioComplete(S32 bytes) { mBytesRead = bytes; } BOOL isValid() const { return mValid; } BOOL isDone() const { return mDone; } const LLUUID &getUUID() const { return mUUID; } protected: BOOL mValid; BOOL mDone; + LLAtomicS32 mBytesRead; LLUUID mUUID; std::vector<U8> mWAVBuffer; @@ -64,172 +82,6 @@ protected: S32 mCurrentSection; }; -void LLVorbisDecodeState::flushBadFile() -{ - if (mInFilep) - { - llwarns << "Flushing bad vorbis file from VFS for " << mUUID << llendl; - mInFilep->remove(); - } -} - - -LLAudioDecodeMgr::LLAudioDecodeMgr() -{ - mCurrentDecodep = NULL; -} - -LLAudioDecodeMgr::~LLAudioDecodeMgr() -{ - delete mCurrentDecodep; - mCurrentDecodep = NULL; -} - - -void LLAudioDecodeMgr::processQueue(const F32 num_secs) -{ - LLUUID uuid; - - LLTimer decode_timer; - - BOOL done = FALSE; - while (!done) - { - if (mCurrentDecodep) - { - BOOL res; - - // Decode in a loop until we're done or have run out of time. - while(!(res = mCurrentDecodep->decodeSection()) && (decode_timer.getElapsedTimeF32() < num_secs)) - { - // decodeSection does all of the work above - } - - if (mCurrentDecodep->isDone() && !mCurrentDecodep->isValid()) - { - // We had an error when decoding, abort. - llwarns << mCurrentDecodep->getUUID() << " has invalid vorbis data, aborting decode" << llendl; - mCurrentDecodep->flushBadFile(); - LLAudioData *adp = gAudiop->getAudioData(mCurrentDecodep->getUUID()); - adp->setHasValidData(FALSE); - delete mCurrentDecodep; - mCurrentDecodep = NULL; - done = TRUE; - } - - if (!res) - { - // We've used up out time slice, bail... - done = TRUE; - } - else if (mCurrentDecodep) - { - if (mCurrentDecodep->finishDecode()) - { - // We finished! - if (mCurrentDecodep->isValid() && mCurrentDecodep->isDone()) - { - LLAudioData *adp = gAudiop->getAudioData(mCurrentDecodep->getUUID()); - adp->setHasDecodedData(TRUE); - adp->setHasValidData(TRUE); - - // At this point, we could see if anyone needs this sound immediately, but - // I'm not sure that there's a reason to - we need to poll all of the playing - // sounds anyway. - //llinfos << "Finished the vorbis decode, now what?" << llendl; - } - else - { - llinfos << "Vorbis decode failed!!!" << llendl; - } - delete mCurrentDecodep; - mCurrentDecodep = NULL; - } - done = TRUE; // done for now - } - } - - if (!done) - { - if (!mDecodeQueue.getLength()) - { - // Nothing else on the queue. - done = TRUE; - } - else - { - LLUUID uuid; - mDecodeQueue.pop(uuid); - if (gAudiop->hasDecodedFile(uuid)) - { - // This file has already been decoded, don't decode it again. - continue; - } - - lldebugs << "Decoding " << uuid << " from audio queue!" << llendl; - - char uuid_str[64]; /*Flawfinder: ignore*/ - char d_path[LL_MAX_PATH]; /*Flawfinder: ignore*/ - - LLTimer timer; - timer.reset(); - - uuid.toString(uuid_str); - snprintf(d_path, LL_MAX_PATH, "%s.dsf", gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_str).c_str()); /*Flawfinder: ignore*/ - - mCurrentDecodep = new LLVorbisDecodeState(uuid, d_path); - if (!mCurrentDecodep->initDecode()) - { - delete mCurrentDecodep; - mCurrentDecodep = NULL; - } - } - } - } -} - - -BOOL LLAudioDecodeMgr::addDecodeRequest(const LLUUID &uuid) -{ - if (gAudiop->hasDecodedFile(uuid)) - { - // Already have a decoded version, don't need to decode it. - return TRUE; - } - - if (gAssetStorage->hasLocalAsset(uuid, LLAssetType::AT_SOUND)) - { - // Just put it on the decode queue. - gAudioDecodeMgrp->mDecodeQueue.push(uuid); - return TRUE; - } - - return FALSE; -} - - -S32 LLAudioDecodeMgr::getRequestCount() -{ - /* - S32 count = 0; - if (mCurrentTransfer.notNull()) - { - count++; - } - - count += mRequestQueue.getLength(); - return count; - */ - return 0; -} - - - - - - - - size_t vfs_read(void *ptr, size_t size, size_t nmemb, void *datasource) { LLVFile *file = (LLVFile *)datasource; @@ -284,26 +136,21 @@ int vfs_seek(void *datasource, ogg_int64_t offset, int whence) int vfs_close (void *datasource) { LLVFile *file = (LLVFile *)datasource; - delete file; - return 0; } long vfs_tell (void *datasource) { LLVFile *file = (LLVFile *)datasource; - return file->tell(); } - - - LLVorbisDecodeState::LLVorbisDecodeState(const LLUUID &uuid, const LLString &out_filename) { mDone = FALSE; mValid = FALSE; + mBytesRead = -1; mUUID = uuid; mInFilep = NULL; mCurrentSection = 0; @@ -575,32 +422,27 @@ BOOL LLVorbisDecodeState::finishDecode() return TRUE; // we've finished } #if !defined(USE_WAV_VFILE) - mFileHandle = LLLFSThread::sLocal->write(mOutFilename, &mWAVBuffer[0], 0, data_length); + mBytesRead = -1; + mFileHandle = LLLFSThread::sLocal->write(mOutFilename, &mWAVBuffer[0], 0, data_length, + new WriteResponder(this)); #endif } if (mFileHandle != LLLFSThread::nullHandle()) { - LLLFSThread::status_t s = LLLFSThread::sLocal->getRequestStatus(mFileHandle); - if (s != LLLFSThread::STATUS_COMPLETE) - { - if (s != LLLFSThread::STATUS_QUEUED && s != LLLFSThread::STATUS_INPROGRESS) - { - llerrs << "Bad file status in LLVorbisDecodeState::finishDecode: " << s << llendl; - } - return FALSE; // not finished - } - else + if (mBytesRead >= 0) { - LLLFSThread::Request* req = (LLLFSThread::Request*)LLLFSThread::sLocal->getRequest(mFileHandle); - if (req->getBytesRead() == 0) //!= req->getBytes() // should be safe, but needs testing + if (mBytesRead == 0) { llwarns << "Unable to write file in LLVorbisDecodeState::finishDecode" << llendl; mValid = FALSE; return TRUE; // we've finished } } - LLLFSThread::sLocal->completeRequest(mFileHandle); + else + { + return FALSE; // not done + } } mDone = TRUE; @@ -614,3 +456,165 @@ BOOL LLVorbisDecodeState::finishDecode() return TRUE; } + +void LLVorbisDecodeState::flushBadFile() +{ + if (mInFilep) + { + llwarns << "Flushing bad vorbis file from VFS for " << mUUID << llendl; + mInFilep->remove(); + } +} + +////////////////////////////////////////////////////////////////////////////// + +class LLAudioDecodeMgr::Impl +{ + friend class LLAudioDecodeMgr; +public: + Impl() {}; + ~Impl() {}; + + void processQueue(const F32 num_secs = 0.005); + +protected: + LLLinkedQueue<LLUUID> mDecodeQueue; + LLPointer<LLVorbisDecodeState> mCurrentDecodep; +}; + + +void LLAudioDecodeMgr::Impl::processQueue(const F32 num_secs) +{ + LLUUID uuid; + + LLTimer decode_timer; + + BOOL done = FALSE; + while (!done) + { + if (mCurrentDecodep) + { + BOOL res; + + // Decode in a loop until we're done or have run out of time. + while(!(res = mCurrentDecodep->decodeSection()) && (decode_timer.getElapsedTimeF32() < num_secs)) + { + // decodeSection does all of the work above + } + + if (mCurrentDecodep->isDone() && !mCurrentDecodep->isValid()) + { + // We had an error when decoding, abort. + llwarns << mCurrentDecodep->getUUID() << " has invalid vorbis data, aborting decode" << llendl; + mCurrentDecodep->flushBadFile(); + LLAudioData *adp = gAudiop->getAudioData(mCurrentDecodep->getUUID()); + adp->setHasValidData(FALSE); + mCurrentDecodep = NULL; + done = TRUE; + } + + if (!res) + { + // We've used up out time slice, bail... + done = TRUE; + } + else if (mCurrentDecodep) + { + if (mCurrentDecodep->finishDecode()) + { + // We finished! + if (mCurrentDecodep->isValid() && mCurrentDecodep->isDone()) + { + LLAudioData *adp = gAudiop->getAudioData(mCurrentDecodep->getUUID()); + adp->setHasDecodedData(TRUE); + adp->setHasValidData(TRUE); + + // At this point, we could see if anyone needs this sound immediately, but + // I'm not sure that there's a reason to - we need to poll all of the playing + // sounds anyway. + //llinfos << "Finished the vorbis decode, now what?" << llendl; + } + else + { + llinfos << "Vorbis decode failed!!!" << llendl; + } + mCurrentDecodep = NULL; + } + done = TRUE; // done for now + } + } + + if (!done) + { + if (!mDecodeQueue.getLength()) + { + // Nothing else on the queue. + done = TRUE; + } + else + { + LLUUID uuid; + mDecodeQueue.pop(uuid); + if (gAudiop->hasDecodedFile(uuid)) + { + // This file has already been decoded, don't decode it again. + continue; + } + + lldebugs << "Decoding " << uuid << " from audio queue!" << llendl; + + char uuid_str[64]; /*Flawfinder: ignore*/ + char d_path[LL_MAX_PATH]; /*Flawfinder: ignore*/ + + LLTimer timer; + timer.reset(); + + uuid.toString(uuid_str); + snprintf(d_path, LL_MAX_PATH, "%s.dsf", gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_str).c_str()); /*Flawfinder: ignore*/ + + mCurrentDecodep = new LLVorbisDecodeState(uuid, d_path); + if (!mCurrentDecodep->initDecode()) + { + mCurrentDecodep = NULL; + } + } + } + } +} + +////////////////////////////////////////////////////////////////////////////// + +LLAudioDecodeMgr::LLAudioDecodeMgr() +{ + mImpl = new Impl; +} + +LLAudioDecodeMgr::~LLAudioDecodeMgr() +{ + delete mImpl; +} + +void LLAudioDecodeMgr::processQueue(const F32 num_secs) +{ + mImpl->processQueue(num_secs); +} + +BOOL LLAudioDecodeMgr::addDecodeRequest(const LLUUID &uuid) +{ + if (gAudiop->hasDecodedFile(uuid)) + { + // Already have a decoded version, don't need to decode it. + return TRUE; + } + + if (gAssetStorage->hasLocalAsset(uuid, LLAssetType::AT_SOUND)) + { + // Just put it on the decode queue. + mImpl->mDecodeQueue.push(uuid); + return TRUE; + } + + return FALSE; +} + + diff --git a/indra/llaudio/llaudiodecodemgr.h b/indra/llaudio/llaudiodecodemgr.h index ea1358b8e9..a72d63a228 100644 --- a/indra/llaudio/llaudiodecodemgr.h +++ b/indra/llaudio/llaudiodecodemgr.h @@ -19,7 +19,6 @@ class LLVFS; class LLVorbisDecodeState; - class LLAudioDecodeMgr { public: @@ -27,19 +26,12 @@ public: ~LLAudioDecodeMgr(); void processQueue(const F32 num_secs = 0.005); - - LLLinkedQueue<LLUUID> mDecodeQueue; - - LLVorbisDecodeState *mCurrentDecodep; - BOOL addDecodeRequest(const LLUUID &uuid); void addAudioRequest(const LLUUID &uuid); - - S32 getRequestCount(); protected: - LLLinkedQueue<LLUUID> mDownloadQueue; - LLFrameTimer mCurrentTransferAge; + class Impl; + Impl* mImpl; }; extern LLAudioDecodeMgr *gAudioDecodeMgrp; diff --git a/indra/llcharacter/llcharacter.cpp b/indra/llcharacter/llcharacter.cpp index ecca9a2526..583f01cf91 100644 --- a/indra/llcharacter/llcharacter.cpp +++ b/indra/llcharacter/llcharacter.cpp @@ -19,13 +19,7 @@ LLStringTable LLCharacter::sVisualParamNames(1024); -// helper functions -BOOL larger_screen_area( LLCharacter* data_new, LLCharacter* data_tested ) -{ - return data_new->getPixelArea() > data_tested->getPixelArea(); -} - -LLLinkedList< LLCharacter > LLCharacter::sInstances( larger_screen_area ); +std::vector< LLCharacter* > LLCharacter::sInstances; //----------------------------------------------------------------------------- @@ -40,7 +34,7 @@ LLCharacter::LLCharacter() mSkeletonSerialNum( 0 ) { mMotionController.setCharacter( this ); - sInstances.addData(this); + sInstances.push_back(this); mPauseRequest = new LLPauseRequestHandle(); } @@ -57,7 +51,11 @@ LLCharacter::~LLCharacter() { delete param; } - sInstances.removeData(this); + std::vector<LLCharacter*>::iterator iter = std::find(sInstances.begin(), sInstances.end(), this); + if (iter != sInstances.end()) + { + sInstances.erase(iter); + } } @@ -66,7 +64,7 @@ LLCharacter::~LLCharacter() //----------------------------------------------------------------------------- LLJoint *LLCharacter::getJoint( const std::string &name ) { - LLJoint *joint = NULL; + LLJoint* joint = NULL; LLJoint *root = getRootJoint(); if (root) @@ -183,7 +181,7 @@ void LLCharacter::flushAllMotions() //----------------------------------------------------------------------------- // dumpCharacter() //----------------------------------------------------------------------------- -void LLCharacter::dumpCharacter( LLJoint *joint ) +void LLCharacter::dumpCharacter( LLJoint* joint ) { // handle top level entry into recursion if (joint == NULL) @@ -198,11 +196,11 @@ void LLCharacter::dumpCharacter( LLJoint *joint ) llinfos << "DEBUG: " << joint->getName() << " (" << (joint->getParent()?joint->getParent()->getName():std::string("ROOT")) << ")" << llendl; // recurse - for ( LLJoint *j = joint->mChildren.getFirstData(); - j != NULL; - j = joint->mChildren.getNextData() ) + for (LLJoint::child_list_t::iterator iter = joint->mChildren.begin(); + iter != joint->mChildren.end(); ++iter) { - dumpCharacter(j); + LLJoint* child_joint = *iter; + dumpCharacter(child_joint); } } diff --git a/indra/llcharacter/llcharacter.h b/indra/llcharacter/llcharacter.h index f2f106f360..0ed22f81f7 100644 --- a/indra/llcharacter/llcharacter.h +++ b/indra/llcharacter/llcharacter.h @@ -21,6 +21,7 @@ #include "linked_lists.h" #include "string_table.h" #include "llmemory.h" +#include "llthread.h" class LLPolyMesh; @@ -90,7 +91,7 @@ public: virtual F32 getTimeDilation() = 0; // gets current pixel area of this character - virtual F32 getPixelArea() = 0; + virtual F32 getPixelArea() const = 0; // gets the head mesh of the character virtual LLPolyMesh* getHeadMesh() = 0; @@ -223,7 +224,7 @@ public: U32 getSkeletonSerialNum() const { return mSkeletonSerialNum; } void setSkeletonSerialNum( U32 num ) { mSkeletonSerialNum = num; } - static LLLinkedList< LLCharacter > sInstances; + static std::vector< LLCharacter* > sInstances; protected: LLMotionController mMotionController; diff --git a/indra/llcharacter/lljoint.cpp b/indra/llcharacter/lljoint.cpp index 3924c06adc..3797b06aa1 100644 --- a/indra/llcharacter/lljoint.cpp +++ b/indra/llcharacter/lljoint.cpp @@ -50,8 +50,9 @@ LLJoint::LLJoint(const std::string &name, LLJoint *parent) setName(name); if (parent) + { parent->addChild( this ); - + } touch(); } @@ -61,6 +62,10 @@ LLJoint::LLJoint(const std::string &name, LLJoint *parent) //----------------------------------------------------------------------------- LLJoint::~LLJoint() { + if (mParent) + { + mParent->removeChild( this ); + } removeAllChildren(); } @@ -72,7 +77,9 @@ void LLJoint::setup(const std::string &name, LLJoint *parent) { setName(name); if (parent) + { parent->addChild( this ); + } } //----------------------------------------------------------------------------- @@ -90,11 +97,11 @@ void LLJoint::touch(U32 flags) { child_flags |= POSITION_DIRTY; } - - for ( LLJoint *joint = mChildren.getFirstData(); - joint != NULL; - joint = mChildren.getNextData() ) + + for (child_list_t::iterator iter = mChildren.begin(); + iter != mChildren.end(); ++iter) { + LLJoint* joint = *iter; joint->touch(child_flags); } } @@ -121,13 +128,15 @@ LLJoint *LLJoint::findJoint( const std::string &name ) if (name == getName()) return this; - for ( LLJoint *j = mChildren.getFirstData(); - j != NULL; - j = mChildren.getNextData() ) + for (child_list_t::iterator iter = mChildren.begin(); + iter != mChildren.end(); ++iter) { - LLJoint *found = j->findJoint(name); + LLJoint* joint = *iter; + LLJoint *found = joint->findJoint(name); if (found) + { return found; + } } return NULL; @@ -137,12 +146,12 @@ LLJoint *LLJoint::findJoint( const std::string &name ) //-------------------------------------------------------------------- // addChild() //-------------------------------------------------------------------- -void LLJoint::addChild(LLJoint *joint) +void LLJoint::addChild(LLJoint* joint) { if (joint->mParent) joint->mParent->removeChild(joint); - mChildren.addDataAtEnd(joint); + mChildren.push_back(joint); joint->mXform.setParent(&mXform); joint->mParent = this; joint->touch(); @@ -152,9 +161,13 @@ void LLJoint::addChild(LLJoint *joint) //-------------------------------------------------------------------- // removeChild() //-------------------------------------------------------------------- -void LLJoint::removeChild(LLJoint *joint) +void LLJoint::removeChild(LLJoint* joint) { - this->mChildren.removeData(joint); + child_list_t::iterator iter = std::find(mChildren.begin(), mChildren.end(), joint); + if (iter != mChildren.end()) + { + this->mChildren.erase(iter); + } joint->mXform.setParent(NULL); joint->mParent = NULL; joint->touch(); @@ -166,11 +179,15 @@ void LLJoint::removeChild(LLJoint *joint) //-------------------------------------------------------------------- void LLJoint::removeAllChildren() { - for ( LLJoint *joint = mChildren.getFirstData(); - joint != NULL; - joint = mChildren.getNextData() ) + for (child_list_t::iterator iter = mChildren.begin(); + iter != mChildren.end();) { - removeChild(joint); + child_list_t::iterator curiter = iter++; + LLJoint* joint = *curiter; + mChildren.erase(curiter); + joint->mXform.setParent(NULL); + joint->mParent = NULL; + joint->touch(); } } @@ -189,8 +206,11 @@ const LLVector3& LLJoint::getPosition() //-------------------------------------------------------------------- void LLJoint::setPosition( const LLVector3& pos ) { - mXform.setPosition(pos); - touch(MATRIX_DIRTY | POSITION_DIRTY); +// if (mXform.getPosition() != pos) + { + mXform.setPosition(pos); + touch(MATRIX_DIRTY | POSITION_DIRTY); + } } @@ -257,8 +277,11 @@ void LLJoint::setRotation( const LLQuaternion& rot ) { if (rot.isFinite()) { - mXform.setRotation(rot); - touch(MATRIX_DIRTY | ROTATION_DIRTY); + // if (mXform.getRotation() != rot) + { + mXform.setRotation(rot); + touch(MATRIX_DIRTY | ROTATION_DIRTY); + } } } @@ -320,8 +343,12 @@ const LLVector3& LLJoint::getScale() //-------------------------------------------------------------------- void LLJoint::setScale( const LLVector3& scale ) { - mXform.setScale(scale); - touch(); +// if (mXform.getScale() != scale) + { + mXform.setScale(scale); + touch(); + } + } @@ -393,14 +420,18 @@ void LLJoint::updateWorldPRSParent() // updateWorldMatrixChildren() //----------------------------------------------------------------------------- void LLJoint::updateWorldMatrixChildren() -{ +{ + if (!this->mUpdateXform) return; + if (mDirtyFlags & MATRIX_DIRTY) { updateWorldMatrix(); } - for (LLJoint *child = mChildren.getFirstData(); child; child = mChildren.getNextData()) + for (child_list_t::iterator iter = mChildren.begin(); + iter != mChildren.end(); ++iter) { - child->updateWorldMatrixChildren(); + LLJoint* joint = *iter; + joint->updateWorldMatrixChildren(); } } @@ -475,8 +506,10 @@ void LLJoint::clampRotation(LLQuaternion old_rot, LLQuaternion new_rot) { LLVector3 main_axis(1.f, 0.f, 0.f); - for (LLJoint* joint = mChildren.getFirstData(); joint; joint = mChildren.getNextData()) + for (child_list_t::iterator iter = mChildren.begin(); + iter != mChildren.end(); ++iter) { + LLJoint* joint = *iter; if (joint->isAnimatable()) { main_axis = joint->getPosition(); diff --git a/indra/llcharacter/lljoint.h b/indra/llcharacter/lljoint.h index 2fc86e87df..6399d0a429 100644 --- a/indra/llcharacter/lljoint.h +++ b/indra/llcharacter/lljoint.h @@ -76,7 +76,8 @@ public: LLDynamicArray<LLVector3> mConstraintSilhouette; // child joints - LLLinkedList<LLJoint> mChildren; + typedef std::list<LLJoint*> child_list_t; + child_list_t mChildren; // debug statics static S32 sNumTouches; diff --git a/indra/llcharacter/llkeyframemotion.cpp b/indra/llcharacter/llkeyframemotion.cpp index bfa4b637e1..ea77126aca 100644 --- a/indra/llcharacter/llkeyframemotion.cpp +++ b/indra/llcharacter/llkeyframemotion.cpp @@ -1892,28 +1892,26 @@ void LLKeyframeMotion::onLoadComplete(LLVFS *vfs, void* user_data, S32 status) { LLUUID* id = (LLUUID*)user_data; + + std::vector<LLCharacter* >::iterator char_iter = LLCharacter::sInstances.begin(); - LLCharacter* character = NULL; + while(char_iter != LLCharacter::sInstances.end() && + (*char_iter)->getID() != *id) + { + ++char_iter; + } - for(character = LLCharacter::sInstances.getFirstData(); - character; - character = LLCharacter::sInstances.getNextData()) - { - if (character->getID() == *id) - { - break; - } - } - delete id; - if (!character) + if (char_iter == LLCharacter::sInstances.end()) { return; } + LLCharacter* character = *char_iter; + // create an instance of this motion (it may or may not already exist) - LLKeyframeMotion* motionp = (LLKeyframeMotion*)character->createMotion(asset_uuid); + LLKeyframeMotion* motionp = (LLKeyframeMotion*) character->createMotion(asset_uuid); if (0 == status && motionp) { diff --git a/indra/llcommon/imageids.h b/indra/llcommon/imageids.h index 8147183bec..9f57ec84c2 100644 --- a/indra/llcommon/imageids.h +++ b/indra/llcommon/imageids.h @@ -31,7 +31,7 @@ const LLUUID IMG_CLEAR ("11ee27f5-43c0-414e-afd5-d7f5688c351f"); // VIEWER const LLUUID IMG_SMOKE ("b4ba225c-373f-446d-9f7e-6cb7b5cf9b3d"); // VIEWER -const LLUUID IMG_DEFAULT ("b4ba225c-373f-446d-9f7e-6cb7b5cf9b3d"); // VIEWER +const LLUUID IMG_DEFAULT ("d2114404-dd59-4a4d-8e6c-49359e91bbf0"); // VIEWER //const LLUUID IMG_SAND ("0ff70ead-4562-45f9-9e8a-52b1a3286868"); // VIEWER 1.5k //const LLUUID IMG_GRASS ("5ab48dd5-05d0-4f1a-ace6-efd4e2fb3508"); // VIEWER 1.2k diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp index a7fc6a40a7..bf6a4d1b21 100644 --- a/indra/llcommon/llapr.cpp +++ b/indra/llcommon/llapr.cpp @@ -103,11 +103,13 @@ void ll_apr_assert_status(apr_status_t status) llassert(ll_apr_warn_status(status) == false); } -apr_file_t* ll_apr_file_open(const LLString& filename, apr_int32_t flags, S32* sizep) +// File I/O +apr_file_t* ll_apr_file_open(const LLString& filename, apr_int32_t flags, S32* sizep, apr_pool_t* pool) { apr_file_t* apr_file; apr_status_t s; - s = apr_file_open(&apr_file, filename.c_str(), flags, APR_OS_DEFAULT, gAPRPoolp); + if (pool == NULL) pool = gAPRPoolp; + s = apr_file_open(&apr_file, filename.c_str(), flags, APR_OS_DEFAULT, pool); if (s != APR_SUCCESS) { if (sizep) @@ -123,6 +125,7 @@ apr_file_t* ll_apr_file_open(const LLString& filename, apr_int32_t flags, S32* s apr_off_t offset = 0; if (apr_file_seek(apr_file, APR_END, &offset) == APR_SUCCESS) { + llassert_always(offset <= 0x7fffffff); file_size = (S32)offset; offset = 0; apr_file_seek(apr_file, APR_SET, &offset); @@ -132,6 +135,18 @@ apr_file_t* ll_apr_file_open(const LLString& filename, apr_int32_t flags, S32* s return apr_file; } +apr_file_t* ll_apr_file_open(const LLString& filename, apr_int32_t flags, S32* sizep) +{ + return ll_apr_file_open(filename, flags, sizep, NULL); +} +apr_file_t* ll_apr_file_open(const LLString& filename, apr_int32_t flags, apr_pool_t* pool) +{ + return ll_apr_file_open(filename, flags, NULL, pool); +} +apr_file_t* ll_apr_file_open(const LLString& filename, apr_int32_t flags) +{ + return ll_apr_file_open(filename, flags, NULL, NULL); +} S32 ll_apr_file_read(apr_file_t* apr_file, void *buf, S32 nbytes) { @@ -143,10 +158,37 @@ S32 ll_apr_file_read(apr_file_t* apr_file, void *buf, S32 nbytes) } else { + llassert_always(sz <= 0x7fffffff); return (S32)sz; } } +S32 ll_apr_file_read_ex(const LLString& filename, apr_pool_t* pool, void *buf, S32 offset, S32 nbytes) +{ + if (pool == NULL) pool = gAPRPoolp; + apr_file_t* filep = ll_apr_file_open(filename, APR_READ|APR_BINARY, pool); + if (!filep) + { + return 0; + } + S32 off; + if (offset < 0) + off = ll_apr_file_seek(filep, APR_END, 0); + else + off = ll_apr_file_seek(filep, APR_SET, offset); + S32 bytes_read; + if (off < 0) + { + bytes_read = 0; + } + else + { + bytes_read = ll_apr_file_read(filep, buf, nbytes ); + } + apr_file_close(filep); + + return bytes_read; +} S32 ll_apr_file_write(apr_file_t* apr_file, const void *buf, S32 nbytes) { @@ -158,28 +200,73 @@ S32 ll_apr_file_write(apr_file_t* apr_file, const void *buf, S32 nbytes) } else { + llassert_always(sz <= 0x7fffffff); return (S32)sz; } } +S32 ll_apr_file_write_ex(const LLString& filename, apr_pool_t* pool, void *buf, S32 offset, S32 nbytes) +{ + if (pool == NULL) pool = gAPRPoolp; + apr_int32_t flags = APR_CREATE|APR_WRITE|APR_BINARY; + if (offset < 0) + { + flags |= APR_APPEND; + offset = 0; + } + apr_file_t* filep = ll_apr_file_open(filename, flags, pool); + if (!filep) + { + return 0; + } + if (offset > 0) + { + offset = ll_apr_file_seek(filep, APR_SET, offset); + } + S32 bytes_written; + if (offset < 0) + { + bytes_written = 0; + } + else + { + bytes_written = ll_apr_file_write(filep, buf, nbytes ); + } + apr_file_close(filep); + + return bytes_written; +} + S32 ll_apr_file_seek(apr_file_t* apr_file, apr_seek_where_t where, S32 offset) { - apr_off_t apr_offset = offset; - apr_status_t s = apr_file_seek(apr_file, where, &apr_offset); + apr_status_t s; + apr_off_t apr_offset; + if (offset >= 0) + { + apr_offset = (apr_off_t)offset; + s = apr_file_seek(apr_file, where, &apr_offset); + } + else + { + apr_offset = 0; + s = apr_file_seek(apr_file, APR_END, &apr_offset); + } if (s != APR_SUCCESS) { return -1; } else { + llassert_always(apr_offset <= 0x7fffffff); return (S32)apr_offset; } } -bool ll_apr_file_remove(const LLString& filename) +bool ll_apr_file_remove(const LLString& filename, apr_pool_t* pool) { apr_status_t s; - s = apr_file_remove(filename.c_str(), gAPRPoolp); + if (pool == NULL) pool = gAPRPoolp; + s = apr_file_remove(filename.c_str(), pool); if (s != APR_SUCCESS) { llwarns << "ll_apr_file_remove failed on file: " << filename << llendl; @@ -188,10 +275,11 @@ bool ll_apr_file_remove(const LLString& filename) return true; } -bool ll_apr_file_rename(const LLString& filename, const LLString& newname) +bool ll_apr_file_rename(const LLString& filename, const LLString& newname, apr_pool_t* pool) { apr_status_t s; - s = apr_file_rename(filename.c_str(), newname.c_str(), gAPRPoolp); + if (pool == NULL) pool = gAPRPoolp; + s = apr_file_rename(filename.c_str(), newname.c_str(), pool); if (s != APR_SUCCESS) { llwarns << "ll_apr_file_rename failed on file: " << filename << llendl; @@ -199,3 +287,73 @@ bool ll_apr_file_rename(const LLString& filename, const LLString& newname) } return true; } + +bool ll_apr_file_exists(const LLString& filename, apr_pool_t* pool) +{ + apr_file_t* apr_file; + apr_status_t s; + if (pool == NULL) pool = gAPRPoolp; + s = apr_file_open(&apr_file, filename.c_str(), APR_READ, APR_OS_DEFAULT, pool); + if (s != APR_SUCCESS || !apr_file) + { + return false; + } + else + { + apr_file_close(apr_file); + return true; + } +} + +S32 ll_apr_file_size(const LLString& filename, apr_pool_t* pool) +{ + apr_file_t* apr_file; + apr_finfo_t info; + apr_status_t s; + if (pool == NULL) pool = gAPRPoolp; + s = apr_file_open(&apr_file, filename.c_str(), APR_READ, APR_OS_DEFAULT, pool); + if (s != APR_SUCCESS || !apr_file) + { + return 0; + } + else + { + apr_status_t s = apr_file_info_get(&info, APR_FINFO_SIZE, apr_file); + apr_file_close(apr_file); + if (s == APR_SUCCESS) + { + return (S32)info.size; + } + else + { + return 0; + } + } +} + +bool ll_apr_dir_make(const LLString& dirname, apr_pool_t* pool) +{ + apr_status_t s; + if (pool == NULL) pool = gAPRPoolp; + s = apr_dir_make(dirname.c_str(), APR_FPROT_OS_DEFAULT, pool); + if (s != APR_SUCCESS) + { + llwarns << "ll_apr_file_remove failed on file: " << dirname << llendl; + return false; + } + return true; +} + +bool ll_apr_dir_remove(const LLString& dirname, apr_pool_t* pool) +{ + apr_status_t s; + if (pool == NULL) pool = gAPRPoolp; + s = apr_file_remove(dirname.c_str(), pool); + if (s != APR_SUCCESS) + { + llwarns << "ll_apr_file_remove failed on file: " << dirname << llendl; + return false; + } + return true; +} + diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h index 1e9e944eef..e89912279e 100644 --- a/indra/llcommon/llapr.h +++ b/indra/llcommon/llapr.h @@ -106,14 +106,24 @@ typedef LLAtomic32<S32> LLAtomicS32; #define LL_APR_WB (APR_CREATE|APR_TRUNCATE|APR_WRITE|APR_BINARY) // "wb" #define LL_APR_RPB (APR_READ|APR_WRITE|APR_BINARY) // "r+b" #define LL_APR_WPB (APR_CREATE|APR_TRUNCATE|APR_READ|APR_WRITE|APR_BINARY) // "w+b" -apr_file_t* ll_apr_file_open(const LLString& filename, apr_int32_t flags, S32* sizep = NULL); +apr_file_t* ll_apr_file_open(const LLString& filename, apr_int32_t flags, S32* sizep, apr_pool_t* pool); +apr_file_t* ll_apr_file_open(const LLString& filename, apr_int32_t flags, S32* sizep); +apr_file_t* ll_apr_file_open(const LLString& filename, apr_int32_t flags, apr_pool_t* pool); +apr_file_t* ll_apr_file_open(const LLString& filename, apr_int32_t flags); // Returns actual offset, -1 if seek fails S32 ll_apr_file_seek(apr_file_t* apr_file, apr_seek_where_t where, S32 offset); -// Returns bytes read/written, 0 if read/write fails +// Returns bytes read/written, 0 if read/write fails: S32 ll_apr_file_read(apr_file_t* apr_file, void* buf, S32 nbytes); +S32 ll_apr_file_read_ex(const LLString& filename, apr_pool_t* pool, void *buf, S32 offset, S32 nbytes); S32 ll_apr_file_write(apr_file_t* apr_file, const void* buf, S32 nbytes); -bool ll_apr_file_remove(const LLString& filename); -bool ll_apr_file_rename(const LLString& filename, const LLString& newname); +S32 ll_apr_file_write_ex(const LLString& filename, apr_pool_t* pool, void *buf, S32 offset, S32 nbytes); +// returns false if failure: +bool ll_apr_file_remove(const LLString& filename, apr_pool_t* pool = NULL); +bool ll_apr_file_rename(const LLString& filename, const LLString& newname, apr_pool_t* pool = NULL); +bool ll_apr_file_exists(const LLString& filename, apr_pool_t* pool = NULL); +S32 ll_apr_file_size(const LLString& filename, apr_pool_t* pool = NULL); +bool ll_apr_dir_make(const LLString& dirname, apr_pool_t* pool = NULL); +bool ll_apr_dir_remove(const LLString& dirname, apr_pool_t* pool = NULL); /** * @brief Function which approprately logs error or remains quiet on diff --git a/indra/llcommon/llcommon.cpp b/indra/llcommon/llcommon.cpp index ff810abfa9..52fcaa3c19 100644 --- a/indra/llcommon/llcommon.cpp +++ b/indra/llcommon/llcommon.cpp @@ -8,6 +8,7 @@ #include "linden_common.h" #include "llcommon.h" +#include "llthread.h" //static BOOL LLCommon::sAprInitialized = FALSE; diff --git a/indra/llcommon/llcommon.h b/indra/llcommon/llcommon.h index c37d479ba9..e7fb5b84e4 100644 --- a/indra/llcommon/llcommon.h +++ b/indra/llcommon/llcommon.h @@ -12,7 +12,6 @@ #include "llapr.h" // #include "llframecallbackmanager.h" #include "lltimer.h" -#include "llworkerthread.h" #include "llfile.h" class LLCommon diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index 1ed25a0d17..bbff363f54 100644 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -12,6 +12,7 @@ #include "llerror.h" #include "llerrorcontrol.h" +#include "llapp.h" #include "llapr.h" extern apr_thread_mutex_t *gLogMutexp; #include "llfile.h" diff --git a/indra/llcommon/llevent.h b/indra/llcommon/llevent.h index 283f40f923..a3f6b0e942 100644 --- a/indra/llcommon/llevent.h +++ b/indra/llcommon/llevent.h @@ -12,6 +12,7 @@ #include "llsd.h" #include "llmemory.h" +#include "llthread.h" class LLEventListener; class LLEvent; diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h index 2fde728eaf..1a7e60656c 100644 --- a/indra/llcommon/llfasttimer.h +++ b/indra/llcommon/llfasttimer.h @@ -37,13 +37,22 @@ public: FTM_UPDATE_TERRAIN, FTM_UPDATE_PRIMITIVES, FTM_UPDATE_PARTICLES, + FTM_SIMULATE_PARTICLES, FTM_UPDATE_SKY, FTM_UPDATE_TEXTURES, + FTM_UPDATE_WATER, + FTM_UPDATE_CLOUDS, + FTM_UPDATE_GRASS, + FTM_UPDATE_TREE, + FTM_UPDATE_AVATAR, // common render components FTM_RENDER_GEOMETRY, FTM_RENDER_TERRAIN, FTM_RENDER_SIMPLE, + FTM_RENDER_FULLBRIGHT, + FTM_RENDER_GRASS, + FTM_RENDER_INVISIBLE, FTM_RENDER_SHINY, FTM_RENDER_BUMP, FTM_RENDER_TREES, @@ -62,6 +71,20 @@ public: FTM_MESSAGES, FTM_REBUILD, FTM_STATESORT, + FTM_STATESORT_DRAWABLE, + FTM_STATESORT_POSTSORT, + FTM_REBUILD_VBO, + FTM_REBUILD_VOLUME_VB, + FTM_REBUILD_BRIDGE_VB, + FTM_REBUILD_HUD_VB, + FTM_REBUILD_TERRAIN_VB, + FTM_REBUILD_WATER_VB, + FTM_REBUILD_TREE_VB, + FTM_REBUILD_PARTICLE_VB, + FTM_REBUILD_CLOUD_VB, + FTM_REBUILD_GRASS_VB, + FTM_REBUILD_NONE_VB, + FTM_REBUILD_OCCLUSION_VB, FTM_POOLS, FTM_POOLRENDER, FTM_IDLE_CB, @@ -71,6 +94,7 @@ public: FTM_UPDATE_LIGHTS, FTM_CULL, FTM_CULL_REBOUND, + FTM_FRUSTUM_CULL, FTM_GEO_UPDATE, FTM_GEO_RESERVE, FTM_GEO_LIGHT, @@ -97,6 +121,7 @@ public: FTM_IMAGE_UPDATE, FTM_IMAGE_CREATE, FTM_IMAGE_DECODE, + FTM_IMAGE_MARK_DIRTY, FTM_PIPELINE, FTM_VFILE_WAIT, FTM_FLEXIBLE_UPDATE, diff --git a/indra/llcommon/llfile.cpp b/indra/llcommon/llfile.cpp index 4acd94f943..f43e57f467 100644 --- a/indra/llcommon/llfile.cpp +++ b/indra/llcommon/llfile.cpp @@ -29,6 +29,19 @@ int LLFile::mkdir(const char* dirname, int perms) } // static +int LLFile::rmdir(const char* dirname) +{ +#if LL_WINDOWS + // permissions are ignored on Windows + std::string utf8dirname = dirname; + llutf16string utf16dirname = utf8str_to_utf16str(utf8dirname); + return _wrmdir(utf16dirname.c_str()); +#else + return ::rmdir(dirname); +#endif +} + +// static LLFILE* LLFile::fopen(const char* filename, const char* mode) /* Flawfinder: ignore */ { #if LL_WINDOWS diff --git a/indra/llcommon/llfile.h b/indra/llcommon/llfile.h index 2899f51a60..605918cd29 100644 --- a/indra/llcommon/llfile.h +++ b/indra/llcommon/llfile.h @@ -50,6 +50,7 @@ public: // be overridden by the user's umask. It is ignored on Windows. static int mkdir(const char* filename, int perms = 0700); + static int rmdir(const char* filename); static int remove(const char* filename); static int rename(const char* filename,const char* newname); static int stat(const char* filename,llstat* file_status); diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index 0a21c3a2a7..1063de5a8c 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -9,6 +9,7 @@ #include "linden_common.h" #include "llmemory.h" +#include "llmemtype.h" // not defining nullfunc will currently crash when trying to use a LLHandle template< typename _Ty > @@ -244,43 +245,6 @@ void operator delete[] (void *p) //---------------------------------------------------------------------------- -//static -LLMutex* LLThreadSafeRefCount::sMutex = 0; - -//static -void LLThreadSafeRefCount::initClass() -{ - if (!sMutex) - { - sMutex = new LLMutex(0); - } -} - -//static -void LLThreadSafeRefCount::cleanupClass() -{ - delete sMutex; - sMutex = NULL; -} - - -//---------------------------------------------------------------------------- - -LLThreadSafeRefCount::LLThreadSafeRefCount() : - mRef(0) -{ -} - -LLThreadSafeRefCount::~LLThreadSafeRefCount() -{ - if (mRef != 0) - { - llerrs << "deleting non-zero reference" << llendl; - } -} - -//---------------------------------------------------------------------------- - LLRefCount::LLRefCount() : mRef(0) { diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h index 962a4aa5d5..d543d023ff 100644 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -12,8 +12,6 @@ #include <cstdlib> #include "llerror.h" -#include "llthread.h" -#include "llmemtype.h" extern S32 gTotalDAlloc; extern S32 gTotalDAUse; @@ -42,53 +40,7 @@ private: // LLPointer<LLFoo> x = new LLFoo; // constructor does not do anything interesting // x->instantiate(); // does stuff like place x into an update queue -class LLThreadSafeRefCount -{ -public: - static void initClass(); // creates sMutex - static void cleanupClass(); // destroys sMutex - -private: - static LLMutex* sMutex; - -private: - LLThreadSafeRefCount(const LLThreadSafeRefCount&); // not implemented - LLThreadSafeRefCount&operator=(const LLThreadSafeRefCount&); // not implemented - -protected: - virtual ~LLThreadSafeRefCount(); // use unref() - -public: - LLThreadSafeRefCount(); - - void ref() - { - if (sMutex) sMutex->lock(); - mRef++; - if (sMutex) sMutex->unlock(); - } - - S32 unref() - { - llassert(mRef >= 1); - if (sMutex) sMutex->lock(); - S32 res = --mRef; - if (sMutex) sMutex->unlock(); - if (0 == res) - { - delete this; - res = 0; - } - return res; - } - S32 getNumRefs() const - { - return mRef; - } - -private: - S32 mRef; -}; +// see llthread.h for LLThreadSafeRefCount //---------------------------------------------------------------------------- @@ -132,6 +84,7 @@ private: //---------------------------------------------------------------------------- +// Note: relies on Type having ref() and unref() methods template <class Type> class LLPointer { public: diff --git a/indra/llcommon/llmemtype.h b/indra/llcommon/llmemtype.h index 17afaa6a8a..53f7f66285 100644 --- a/indra/llcommon/llmemtype.h +++ b/indra/llcommon/llmemtype.h @@ -52,6 +52,7 @@ public: MTYPE_DRAWABLE, MTYPE_OBJECT, + MTYPE_VERTEX_DATA, MTYPE_SPACE_PARTITION, MTYPE_PIPELINE, MTYPE_AVATAR, diff --git a/indra/llcommon/llqueuedthread.cpp b/indra/llcommon/llqueuedthread.cpp index bc41927d38..e6ac9ac11d 100644 --- a/indra/llcommon/llqueuedthread.cpp +++ b/indra/llcommon/llqueuedthread.cpp @@ -12,10 +12,9 @@ //============================================================================ // MAIN THREAD -LLQueuedThread::LLQueuedThread(const std::string& name, bool threaded, bool runalways) : +LLQueuedThread::LLQueuedThread(const std::string& name, bool threaded) : LLThread(name), mThreaded(threaded), - mRunAlways(runalways), mIdleThread(TRUE), mNextHandle(0) { @@ -28,6 +27,12 @@ LLQueuedThread::LLQueuedThread(const std::string& name, bool threaded, bool runa // MAIN THREAD LLQueuedThread::~LLQueuedThread() { + shutdown(); + // ~LLThread() will be called here +} + +void LLQueuedThread::shutdown() +{ setQuitting(); unpause(); // MAIN THREAD @@ -54,61 +59,69 @@ LLQueuedThread::~LLQueuedThread() } QueuedRequest* req; + S32 active_count = 0; while ( (req = (QueuedRequest*)mRequestHash.pop_element()) ) { + if (req->getStatus() == STATUS_QUEUED || req->getStatus() == STATUS_INPROGRESS) + { + ++active_count; + } req->deleteRequest(); } - - // ~LLThread() will be called here + if (active_count) + { + llwarns << "~LLQueuedThread() called with active requests: " << active_count << llendl; + } } //---------------------------------------------------------------------------- // MAIN THREAD -void LLQueuedThread::update(U32 ms_elapsed) +// virtual +S32 LLQueuedThread::update(U32 max_time_ms) { - updateQueue(0); + return updateQueue(max_time_ms); } -void LLQueuedThread::updateQueue(S32 inc) +S32 LLQueuedThread::updateQueue(U32 max_time_ms) { - // If mRunAlways == TRUE, unpause the thread whenever we put something into the queue. - // If mRunAlways == FALSE, we only unpause the thread when updateQueue() is called from the main loop (i.e. between rendered frames) - - if (inc == 0) // Frame Update + F64 max_time = (F64)max_time_ms * .001; + LLTimer timer; + S32 pending = 1; + + // Frame Update + if (mThreaded) { - if (mThreaded) - { - unpause(); - wake(); // Wake the thread up if necessary. - } - else + pending = getPending(); + unpause(); + } + else + { + while (pending > 0) { - while (processNextRequest() > 0) - ; + pending = processNextRequest(); + if (max_time && timer.getElapsedTimeF64() > max_time) + break; } } - else + return pending; +} + +void LLQueuedThread::incQueue() +{ + // Something has been added to the queue + if (!isPaused()) { - // Something has been added to the queue - if (mRunAlways) + if (mThreaded) { - if (mThreaded) - { - wake(); // Wake the thread up if necessary. - } - else - { - while(processNextRequest() > 0) - ; - } + wake(); // Wake the thread up if necessary. } } } //virtual // May be called from any thread -S32 LLQueuedThread::getPending(bool child_thread) +S32 LLQueuedThread::getPending() { S32 res; lockData(); @@ -122,7 +135,7 @@ void LLQueuedThread::waitOnPending() { while(1) { - updateQueue(0); + update(0); if (mIdleThread) { @@ -181,7 +194,7 @@ bool LLQueuedThread::addRequest(QueuedRequest* req) #endif unlockData(); - updateQueue(1); + incQueue(); return true; } @@ -195,7 +208,7 @@ bool LLQueuedThread::waitForResult(LLQueuedThread::handle_t handle, bool auto_co bool done = false; while(!done) { - updateQueue(0); // unpauses + update(0); // unpauses lockData(); QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle); if (!req) @@ -253,51 +266,47 @@ LLQueuedThread::status_t LLQueuedThread::getRequestStatus(handle_t handle) return res; } -LLQueuedThread::status_t LLQueuedThread::abortRequest(handle_t handle, U32 flags) +void LLQueuedThread::abortRequest(handle_t handle, bool autocomplete) { - status_t res = STATUS_EXPIRED; lockData(); QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle); if (req) { - res = req->abortRequest(flags); - if ((flags & AUTO_COMPLETE) && (res == STATUS_COMPLETE)) - { - mRequestHash.erase(handle); - req->deleteRequest(); -// check(); - } -#if _DEBUG -// llinfos << llformat("LLQueuedThread::Aborted req [%08d]",handle) << llendl; -#endif + req->setFlags(FLAG_ABORT | (autocomplete ? FLAG_AUTO_COMPLETE : 0)); } unlockData(); - return res; } // MAIN thread -LLQueuedThread::status_t LLQueuedThread::setFlags(handle_t handle, U32 flags) +void LLQueuedThread::setFlags(handle_t handle, U32 flags) { - status_t res = STATUS_EXPIRED; lockData(); QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle); if (req) { - res = req->setFlags(flags); + req->setFlags(flags); } unlockData(); - return res; } void LLQueuedThread::setPriority(handle_t handle, U32 priority) { lockData(); QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle); - if (req && (req->getStatus() == STATUS_QUEUED)) + if (req) { - llverify(mRequestQueue.erase(req) == 1); - req->setPriority(priority); - mRequestQueue.insert(req); + if(req->getStatus() == STATUS_INPROGRESS) + { + // not in list + req->setPriority(priority); + } + else if(req->getStatus() == STATUS_QUEUED) + { + // remove from list then re-insert + llverify(mRequestQueue.erase(req) == 1); + req->setPriority(priority); + mRequestQueue.insert(req); + } } unlockData(); } @@ -309,9 +318,10 @@ bool LLQueuedThread::completeRequest(handle_t handle) QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle); if (req) { - llassert(req->getStatus() != STATUS_QUEUED && req->getStatus() != STATUS_ABORT); + llassert_always(req->getStatus() != STATUS_QUEUED); + llassert_always(req->getStatus() != STATUS_INPROGRESS); #if _DEBUG -// llinfos << llformat("LLQueuedThread::Completed req [%08d]",handle) << llendl; +// llinfos << llformat("LLQueuedThread::Completed req [%08d]",handle) << llendl; #endif mRequestHash.erase(handle); req->deleteRequest(); @@ -345,28 +355,34 @@ bool LLQueuedThread::check() //============================================================================ // Runs on its OWN thread -int LLQueuedThread::processNextRequest() +S32 LLQueuedThread::processNextRequest() { - QueuedRequest *req = 0; + QueuedRequest *req; // Get next request from pool lockData(); while(1) { - if (!mRequestQueue.empty()) + req = NULL; + if (mRequestQueue.empty()) { - req = *mRequestQueue.begin(); - mRequestQueue.erase(mRequestQueue.begin()); + break; } - if (req && req->getStatus() == STATUS_ABORT) + req = *mRequestQueue.begin(); + mRequestQueue.erase(mRequestQueue.begin()); + if ((req->getFlags() & FLAG_ABORT) || (mStatus == QUITTING)) { req->setStatus(STATUS_ABORTED); - req = 0; - } - else - { - llassert (!req || req->getStatus() == STATUS_QUEUED) - break; + req->finishRequest(false); + if (req->getFlags() & FLAG_AUTO_COMPLETE) + { + mRequestHash.erase(req); + req->deleteRequest(); +// check(); + } + continue; } + llassert_always(req->getStatus() == STATUS_QUEUED); + break; } if (req) { @@ -374,22 +390,22 @@ int LLQueuedThread::processNextRequest() } unlockData(); - // This is the only place we will cal req->setStatus() after + // This is the only place we will call req->setStatus() after // it has initially been seet to STATUS_QUEUED, so it is // safe to access req. if (req) { // process request - bool complete = processRequest(req); + bool complete = req->processRequest(); if (complete) { lockData(); req->setStatus(STATUS_COMPLETE); - req->finishRequest(); - if (req->getFlags() & AUTO_COMPLETE) + req->finishRequest(true); + if (req->getFlags() & FLAG_AUTO_COMPLETE) { - llverify(mRequestHash.erase(req)) + mRequestHash.erase(req); req->deleteRequest(); // check(); } @@ -400,12 +416,18 @@ int LLQueuedThread::processNextRequest() lockData(); req->setStatus(STATUS_QUEUED); mRequestQueue.insert(req); + U32 priority = req->getPriority(); unlockData(); + if (priority < PRIORITY_NORMAL) + { + ms_sleep(1); // sleep the thread a little + } } } - int res; - if (getPending(true) == 0) + S32 res; + S32 pending = getPending(); + if (pending == 0) { if (isQuitting()) { @@ -418,7 +440,7 @@ int LLQueuedThread::processNextRequest() } else { - res = 1; + res = pending; } return res; } @@ -426,13 +448,14 @@ int LLQueuedThread::processNextRequest() bool LLQueuedThread::runCondition() { // mRunCondition must be locked here - return (mRequestQueue.empty() && mIdleThread) ? FALSE : TRUE; + if (mRequestQueue.empty() && mIdleThread) + return false; + else + return true; } void LLQueuedThread::run() { - llinfos << "QUEUED THREAD STARTING" << llendl; - while (1) { // this will block on the condition until runCondition() returns true, the thread is unpaused, or the thread leaves the RUNNING state. @@ -455,6 +478,8 @@ void LLQueuedThread::run() { break; } + + //LLThread::yield(); // thread should yield after each request } llinfos << "QUEUED THREAD " << mName << " EXITING." << llendl; @@ -472,20 +497,18 @@ LLQueuedThread::QueuedRequest::QueuedRequest(LLQueuedThread::handle_t handle, U3 LLQueuedThread::QueuedRequest::~QueuedRequest() { - if (mStatus != STATUS_DELETE) - { - llerrs << "Attemt to directly delete a LLQueuedThread::QueuedRequest; use deleteRequest()" << llendl; - } + llassert_always(mStatus == STATUS_DELETE); } //virtual -void LLQueuedThread::QueuedRequest::finishRequest() +void LLQueuedThread::QueuedRequest::finishRequest(bool completed) { } //virtual void LLQueuedThread::QueuedRequest::deleteRequest() { + llassert_always(mStatus != STATUS_INPROGRESS); setStatus(STATUS_DELETE); delete this; } diff --git a/indra/llcommon/llqueuedthread.h b/indra/llcommon/llqueuedthread.h index beff473f52..8b6a658333 100644 --- a/indra/llcommon/llqueuedthread.h +++ b/indra/llcommon/llqueuedthread.h @@ -33,7 +33,8 @@ public: PRIORITY_HIGH = 0x30000000, PRIORITY_NORMAL = 0x20000000, PRIORITY_LOW = 0x10000000, - PRIORITY_LOWBITS = 0x0FFFFFFF + PRIORITY_LOWBITS = 0x0FFFFFFF, + PRIORITY_HIGHBITS = 0x70000000 }; enum status_t { STATUS_EXPIRED = -1, @@ -41,13 +42,13 @@ public: STATUS_QUEUED = 1, STATUS_INPROGRESS = 2, STATUS_COMPLETE = 3, - STATUS_ABORT = 4, - STATUS_ABORTED = 5, - STATUS_DELETE = 6 + STATUS_ABORTED = 4, + STATUS_DELETE = 5 }; enum flags_t { - AUTO_COMPLETE = 1, - AUTO_DELETE = 2 // child-class dependent + FLAG_AUTO_COMPLETE = 1, + FLAG_AUTO_DELETE = 2, // child-class dependent + FLAG_ABORT = 4 }; typedef U32 handle_t; @@ -60,7 +61,7 @@ public: friend class LLQueuedThread; protected: - ~QueuedRequest(); // use deleteRequest() + virtual ~QueuedRequest(); // use deleteRequest() public: QueuedRequest(handle_t handle, U32 priority, U32 flags = 0); @@ -92,26 +93,14 @@ public: mStatus = newstatus; return oldstatus; } - status_t abortRequest(U32 flags) + void setFlags(U32 flags) { // NOTE: flags are |'d - if (mStatus == STATUS_QUEUED) - { - setStatus(STATUS_ABORT); - } mFlags |= flags; - status_t status = mStatus; - return status; - } - status_t setFlags(U32 flags) - { - // NOTE: flags are |'d - mFlags |= flags; - status_t status = mStatus; - return status; } - virtual void finishRequest(); // Always called when after has been processed + virtual bool processRequest() = 0; // Return true when request has completed + virtual void finishRequest(bool completed); // Always called from thread after request has completed or aborted virtual void deleteRequest(); // Only method to delete a request void setPriority(U32 pri) @@ -141,9 +130,10 @@ public: static handle_t nullHandle() { return handle_t(0); } public: - LLQueuedThread(const std::string& name, bool threaded = TRUE, bool runalways = TRUE); + LLQueuedThread(const std::string& name, bool threaded = true); virtual ~LLQueuedThread(); - + virtual void shutdown(); + private: // No copy constructor or copy assignment LLQueuedThread(const LLQueuedThread&); @@ -155,26 +145,25 @@ private: protected: handle_t generateHandle(); bool addRequest(QueuedRequest* req); - int processNextRequest(void); + S32 processNextRequest(void); + void incQueue(); - virtual bool processRequest(QueuedRequest* req) = 0; - public: bool waitForResult(handle_t handle, bool auto_complete = true); - void update(U32 ms_elapsed); - void updateQueue(S32 inc); + virtual S32 update(U32 max_time_ms); + S32 updateQueue(U32 max_time_ms); + void waitOnPending(); void printQueueStats(); - S32 getPending(bool child_thread = false); + S32 getPending(); bool getThreaded() { return mThreaded ? true : false; } - bool getRunAlways() { return mRunAlways ? true : false; } // Request accessors status_t getRequestStatus(handle_t handle); - status_t abortRequest(handle_t handle, U32 flags = 0); - status_t setFlags(handle_t handle, U32 flags); + void abortRequest(handle_t handle, bool autocomplete); + void setFlags(handle_t handle, U32 flags); void setPriority(handle_t handle, U32 priority); bool completeRequest(handle_t handle); // This is public for support classes like LLWorkerThread, @@ -186,7 +175,6 @@ public: protected: BOOL mThreaded; // if false, run on main thread and do updates during update() - BOOL mRunAlways; // if false, only wake the threads when updateClass() is called LLAtomic32<BOOL> mIdleThread; // request queue is empty (or we are quitting) and the thread is idle typedef std::set<QueuedRequest*, queued_request_less> request_queue_t; diff --git a/indra/llcommon/llsecondlifeurls.h b/indra/llcommon/llsecondlifeurls.h index b07c18eb72..cbea60034f 100644 --- a/indra/llcommon/llsecondlifeurls.h +++ b/indra/llcommon/llsecondlifeurls.h @@ -31,18 +31,9 @@ extern const char UPGRADE_TO_PREMIUM_URL[]; // How to get DirectX 9 extern const char DIRECTX_9_URL[]; -// On AMD with bad AGP controller -extern const char AMD_AGP_URL[]; - // Out of date VIA chipset extern const char VIA_URL[]; -// Out of date intel chipset driver -extern const char INTEL_CHIPSET_URL[]; - -// Out of date SiS chipset driver -extern const char SIS_CHIPSET_URL[]; - // Linden Blogs page extern const char BLOGS_URL[]; diff --git a/indra/llcommon/llstrider.h b/indra/llcommon/llstrider.h index 0688e43940..c5fbf1282a 100644 --- a/indra/llcommon/llstrider.h +++ b/indra/llcommon/llstrider.h @@ -32,6 +32,7 @@ public: Object* operator->() { return mObjectp; } Object& operator *() { return *mObjectp; } Object* operator ++(int) { Object* old = mObjectp; mBytep += mSkip; return old; } + Object* operator +=(int i) { mBytep += mSkip*i; return mObjectp; } Object& operator[](U32 index) { return *(Object*)(mBytep + (mSkip * index)); } }; diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp index bd2dd7c8f5..a92d553148 100644 --- a/indra/llcommon/llthread.cpp +++ b/indra/llcommon/llthread.cpp @@ -81,6 +81,11 @@ LLThread::LLThread(const std::string& name, apr_pool_t *poolp) : LLThread::~LLThread() { + shutdown(); +} + +void LLThread::shutdown() +{ // Warning! If you somehow call the thread destructor from itself, // the thread will die in an unclean fashion! if (mAPRThreadp) @@ -186,18 +191,6 @@ void LLThread::checkPause() //============================================================================ -bool LLThread::isQuitting() const -{ - return (QUITTING == mStatus); -} - - -bool LLThread::isStopped() const -{ - return (STOPPED == mStatus); -} - - void LLThread::setQuitting() { mRunCondition->lock(); @@ -328,3 +321,49 @@ void LLCondition::broadcast() apr_thread_cond_broadcast(mAPRCondp); } +//============================================================================ + +//---------------------------------------------------------------------------- + +//static +LLMutex* LLThreadSafeRefCount::sMutex = 0; + +//static +void LLThreadSafeRefCount::initClass() +{ + if (!sMutex) + { + sMutex = new LLMutex(0); + } +} + +//static +void LLThreadSafeRefCount::cleanupClass() +{ + delete sMutex; + sMutex = NULL; +} + + +//---------------------------------------------------------------------------- + +LLThreadSafeRefCount::LLThreadSafeRefCount() : + mRef(0) +{ +} + +LLThreadSafeRefCount::~LLThreadSafeRefCount() +{ + if (mRef != 0) + { + llerrs << "deleting non-zero reference" << llendl; + } +} + +//============================================================================ + +LLResponder::~LLResponder() +{ +} + +//============================================================================ diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h index f6f6bd210a..ce5daa938c 100644 --- a/indra/llcommon/llthread.h +++ b/indra/llcommon/llthread.h @@ -11,6 +11,7 @@ #include "llapr.h" #include "llapp.h" +#include "llmemory.h" #include "apr-1/apr_thread_cond.h" @@ -30,19 +31,20 @@ public: LLThread(const std::string& name, apr_pool_t *poolp = NULL); virtual ~LLThread(); // Warning! You almost NEVER want to destroy a thread unless it's in the STOPPED state. - + virtual void shutdown(); // stops the thread + static void yield(); // Static because it can be called by the main thread, which doesn't have an LLThread data structure. - bool isQuitting() const; - bool isStopped() const; + bool isQuitting() const { return (QUITTING == mStatus); } + bool isStopped() const { return (STOPPED == mStatus); } // PAUSE / RESUME functionality. See source code for important usage notes. public: // Called from MAIN THREAD. void pause(); void unpause(); - bool isPaused() { return mPaused ? true : false; } + bool isPaused() { return isStopped() || mPaused == TRUE; } // Cause the thread to wake up and check its condition void wake(); @@ -60,7 +62,7 @@ public: private: BOOL mPaused; - + // static function passed to APR thread creation routine static void *APR_THREAD_FUNC staticRun(apr_thread_t *apr_threadp, void *datap); @@ -161,4 +163,67 @@ void LLThread::unlockData() //============================================================================ +// see llmemory.h for LLPointer<> definition + +class LLThreadSafeRefCount +{ +public: + static void initClass(); // creates sMutex + static void cleanupClass(); // destroys sMutex + +private: + static LLMutex* sMutex; + +private: + LLThreadSafeRefCount(const LLThreadSafeRefCount&); // not implemented + LLThreadSafeRefCount&operator=(const LLThreadSafeRefCount&); // not implemented + +protected: + virtual ~LLThreadSafeRefCount(); // use unref() + +public: + LLThreadSafeRefCount(); + + void ref() + { + if (sMutex) sMutex->lock(); + mRef++; + if (sMutex) sMutex->unlock(); + } + + S32 unref() + { + llassert(mRef >= 1); + if (sMutex) sMutex->lock(); + S32 res = --mRef; + if (sMutex) sMutex->unlock(); + if (0 == res) + { + delete this; + res = 0; + } + return res; + } + S32 getNumRefs() const + { + return mRef; + } + +private: + S32 mRef; +}; + +//============================================================================ + +// Simple responder for self destructing callbacks +// Pure virtual class +class LLResponder : public LLThreadSafeRefCount +{ +public: + virtual ~LLResponder(); + virtual void completed(bool success) = 0; +}; + +//============================================================================ + #endif // LL_LLTHREAD_H diff --git a/indra/llcommon/llworkerthread.cpp b/indra/llcommon/llworkerthread.cpp index a9370c8f6d..31f5c1cfcd 100644 --- a/indra/llcommon/llworkerthread.cpp +++ b/indra/llcommon/llworkerthread.cpp @@ -14,98 +14,86 @@ #endif //============================================================================ - -/*static*/ LLWorkerThread* LLWorkerThread::sLocal = NULL; -/*static*/ std::set<LLWorkerThread*> LLWorkerThread::sThreadList; - -//============================================================================ // Run on MAIN thread -//static -void LLWorkerThread::initClass(bool local_is_threaded, bool local_run_always) +LLWorkerThread::LLWorkerThread(const std::string& name, bool threaded) : + LLQueuedThread(name, threaded), + mWorkerAPRPoolp(NULL) { - if (!sLocal) - { - sLocal = new LLWorkerThread(local_is_threaded, local_run_always); - } + apr_pool_create(&mWorkerAPRPoolp, NULL); + mDeleteMutex = new LLMutex(getAPRPool()); } -//static -void LLWorkerThread::cleanupClass() +LLWorkerThread::~LLWorkerThread() { - if (sLocal) + // Delete any workers in the delete queue (should be safe - had better be!) + if (!mDeleteList.empty()) { - while (sLocal->getPending()) - { - sLocal->update(0); - } - delete sLocal; - sLocal = NULL; - llassert(sThreadList.size() == 0); + llwarns << "Worker Thread: " << mName << " destroyed with " << mDeleteList.size() + << " entries in delete list." << llendl; } -} -//static -S32 LLWorkerThread::updateClass(U32 ms_elapsed) -{ - for (std::set<LLWorkerThread*>::iterator iter = sThreadList.begin(); iter != sThreadList.end(); iter++) - { - (*iter)->update(ms_elapsed); - } - return getAllPending(); + delete mDeleteMutex; + + // ~LLQueuedThread() will be called here } -//static -S32 LLWorkerThread::getAllPending() +// virtual +S32 LLWorkerThread::update(U32 max_time_ms) { - S32 res = 0; - for (std::set<LLWorkerThread*>::iterator iter = sThreadList.begin(); iter != sThreadList.end(); iter++) + S32 res = LLQueuedThread::update(max_time_ms); + // Delete scheduled workers + std::vector<LLWorkerClass*> delete_list; + std::vector<LLWorkerClass*> abort_list; + mDeleteMutex->lock(); + for (delete_list_t::iterator iter = mDeleteList.begin(); + iter != mDeleteList.end(); ) { - res += (*iter)->getPending(); + delete_list_t::iterator curiter = iter++; + LLWorkerClass* worker = *curiter; + if (worker->deleteOK()) + { + if (worker->getFlags(LLWorkerClass::WCF_WORK_FINISHED)) + { + delete_list.push_back(worker); + mDeleteList.erase(curiter); + } + else if (!worker->getFlags(LLWorkerClass::WCF_ABORT_REQUESTED)) + { + abort_list.push_back(worker); + } + } } - return res; -} - -//static -void LLWorkerThread::pauseAll() -{ - for (std::set<LLWorkerThread*>::iterator iter = sThreadList.begin(); iter != sThreadList.end(); iter++) + mDeleteMutex->unlock(); + // abort and delete after releasing mutex + for (std::vector<LLWorkerClass*>::iterator iter = abort_list.begin(); + iter != abort_list.end(); ++iter) { - (*iter)->pause(); + (*iter)->abortWork(false); } -} - -//static -void LLWorkerThread::waitOnAllPending() -{ - for (std::set<LLWorkerThread*>::iterator iter = sThreadList.begin(); iter != sThreadList.end(); iter++) + for (std::vector<LLWorkerClass*>::iterator iter = delete_list.begin(); + iter != delete_list.end(); ++iter) { - (*iter)->waitOnPending(); + LLWorkerClass* worker = *iter; + if (worker->mRequestHandle) + { + // Finished but not completed + completeRequest(worker->mRequestHandle); + worker->mRequestHandle = LLWorkerThread::nullHandle(); + worker->clearFlags(LLWorkerClass::WCF_HAVE_WORK); + } + delete *iter; } + return res; } //---------------------------------------------------------------------------- -LLWorkerThread::LLWorkerThread(bool threaded, bool runalways) : - LLQueuedThread("Worker", threaded, runalways) -{ - sThreadList.insert(this); -} - -LLWorkerThread::~LLWorkerThread() -{ - llverify(sThreadList.erase(this) == 1); - // ~LLQueuedThread() will be called here -} - -//---------------------------------------------------------------------------- - - -LLWorkerThread::handle_t LLWorkerThread::add(LLWorkerClass* workerclass, S32 param, U32 priority) +LLWorkerThread::handle_t LLWorkerThread::addWorkRequest(LLWorkerClass* workerclass, S32 param, U32 priority) { handle_t handle = generateHandle(); - Request* req = new Request(handle, priority, workerclass, param); + WorkRequest* req = new WorkRequest(handle, priority, workerclass, param); bool res = addRequest(req); if (!res) @@ -118,63 +106,80 @@ LLWorkerThread::handle_t LLWorkerThread::add(LLWorkerClass* workerclass, S32 par return handle; } -//============================================================================ -// Runs on its OWN thread - -bool LLWorkerThread::processRequest(QueuedRequest* qreq) +void LLWorkerThread::deleteWorker(LLWorkerClass* workerclass) { - Request *req = (Request*)qreq; - - req->getWorkerClass()->setWorking(true); - - bool complete = req->getWorkerClass()->doWork(req->getParam()); - - req->getWorkerClass()->setWorking(false); - - LLThread::yield(); // worker thread should yield after each request - - return complete; + mDeleteMutex->lock(); + mDeleteList.push_back(workerclass); + mDeleteMutex->unlock(); } //============================================================================ +// Runs on its OWN thread -LLWorkerThread::Request::Request(handle_t handle, U32 priority, LLWorkerClass* workerclass, S32 param) : +LLWorkerThread::WorkRequest::WorkRequest(handle_t handle, U32 priority, LLWorkerClass* workerclass, S32 param) : LLQueuedThread::QueuedRequest(handle, priority), mWorkerClass(workerclass), mParam(param) { } -void LLWorkerThread::Request::deleteRequest() +LLWorkerThread::WorkRequest::~WorkRequest() +{ +} + +// virtual (required for access by LLWorkerThread) +void LLWorkerThread::WorkRequest::deleteRequest() { LLQueuedThread::QueuedRequest::deleteRequest(); } +// virtual +bool LLWorkerThread::WorkRequest::processRequest() +{ + LLWorkerClass* workerclass = getWorkerClass(); + workerclass->setWorking(true); + bool complete = workerclass->doWork(getParam()); + workerclass->setWorking(false); + return complete; +} + +// virtual +void LLWorkerThread::WorkRequest::finishRequest(bool completed) +{ + LLWorkerClass* workerclass = getWorkerClass(); + workerclass->finishWork(getParam(), completed); + U32 flags = LLWorkerClass::WCF_WORK_FINISHED | (completed ? 0 : LLWorkerClass::WCF_WORK_ABORTED); + workerclass->setFlags(flags); +} + //============================================================================ // LLWorkerClass:: operates in main thread LLWorkerClass::LLWorkerClass(LLWorkerThread* workerthread, const std::string& name) : mWorkerThread(workerthread), mWorkerClassName(name), - mWorkHandle(LLWorkerThread::nullHandle()), + mRequestHandle(LLWorkerThread::nullHandle()), + mMutex(workerthread->getWorkerAPRPool()), mWorkFlags(0) { if (!mWorkerThread) { - mWorkerThread = LLWorkerThread::sLocal; + llerrs << "LLWorkerClass() called with NULL workerthread: " << name << llendl; } } + LLWorkerClass::~LLWorkerClass() { - if (mWorkHandle != LLWorkerThread::nullHandle()) + llassert_always(!(mWorkFlags & WCF_WORKING)); + llassert_always(mWorkFlags & WCF_DELETE_REQUESTED); + if (mRequestHandle != LLWorkerThread::nullHandle()) { - LLWorkerThread::Request* workreq = (LLWorkerThread::Request*)mWorkerThread->getRequest(mWorkHandle); + LLWorkerThread::WorkRequest* workreq = (LLWorkerThread::WorkRequest*)mWorkerThread->getRequest(mRequestHandle); if (!workreq) { llerrs << "LLWorkerClass destroyed with stale work handle" << llendl; } - if (workreq->getStatus() != LLWorkerThread::STATUS_ABORT && - workreq->getStatus() != LLWorkerThread::STATUS_ABORTED && + if (workreq->getStatus() != LLWorkerThread::STATUS_ABORTED && workreq->getStatus() != LLWorkerThread::STATUS_COMPLETE) { llerrs << "LLWorkerClass destroyed with active worker! Worker Status: " << workreq->getStatus() << llendl; @@ -184,21 +189,58 @@ LLWorkerClass::~LLWorkerClass() void LLWorkerClass::setWorkerThread(LLWorkerThread* workerthread) { - if (mWorkHandle != LLWorkerThread::nullHandle()) + mMutex.lock(); + if (mRequestHandle != LLWorkerThread::nullHandle()) { llerrs << "LLWorkerClass attempt to change WorkerThread with active worker!" << llendl; } mWorkerThread = workerthread; + mMutex.unlock(); +} + +//---------------------------------------------------------------------------- + +//virtual +void LLWorkerClass::finishWork(S32 param, bool success) +{ +} + +//virtual +bool LLWorkerClass::deleteOK() +{ + return true; // default always OK +} + +//---------------------------------------------------------------------------- + +// Called from worker thread +void LLWorkerClass::setWorking(bool working) +{ + mMutex.lock(); + if (working) + { + llassert_always(!(mWorkFlags & WCF_WORKING)); + setFlags(WCF_WORKING); + } + else + { + llassert_always((mWorkFlags & WCF_WORKING)); + clearFlags(WCF_WORKING); + } + mMutex.unlock(); } //---------------------------------------------------------------------------- bool LLWorkerClass::yield() { - llassert(mWorkFlags & WCF_WORKING); LLThread::yield(); mWorkerThread->checkPause(); - return (getFlags() & WCF_ABORT_REQUESTED) ? true : false; + bool res; + mMutex.lock(); + res = (getFlags() & WCF_ABORT_REQUESTED) ? true : false; + mMutex.unlock(); + return res; } //---------------------------------------------------------------------------- @@ -206,7 +248,9 @@ bool LLWorkerClass::yield() // calls startWork, adds doWork() to queue void LLWorkerClass::addWork(S32 param, U32 priority) { - if (mWorkHandle != LLWorkerThread::nullHandle()) + mMutex.lock(); + llassert_always(!(mWorkFlags & (WCF_WORKING|WCF_HAVE_WORK))); + if (mRequestHandle != LLWorkerThread::nullHandle()) { llerrs << "LLWorkerClass attempt to add work with active worker!" << llendl; } @@ -214,70 +258,93 @@ void LLWorkerClass::addWork(S32 param, U32 priority) // llinfos << "addWork: " << mWorkerClassName << " Param: " << param << llendl; #endif startWork(param); - mWorkHandle = mWorkerThread->add(this, param, priority); + clearFlags(WCF_WORK_FINISHED|WCF_WORK_ABORTED); + setFlags(WCF_HAVE_WORK); + mRequestHandle = mWorkerThread->addWorkRequest(this, param, priority); + mMutex.unlock(); } -void LLWorkerClass::abortWork() +void LLWorkerClass::abortWork(bool autocomplete) { + mMutex.lock(); #if _DEBUG -// LLWorkerThread::Request* workreq = mWorkerThread->getRequest(mWorkHandle); +// LLWorkerThread::WorkRequest* workreq = mWorkerThread->getRequest(mRequestHandle); // if (workreq) // llinfos << "abortWork: " << mWorkerClassName << " Param: " << workreq->getParam() << llendl; #endif - mWorkerThread->abortRequest(mWorkHandle); - setFlags(WCF_ABORT_REQUESTED); + if (mRequestHandle != LLWorkerThread::nullHandle()) + { + mWorkerThread->abortRequest(mRequestHandle, autocomplete); + mWorkerThread->setPriority(mRequestHandle, LLQueuedThread::PRIORITY_IMMEDIATE); + setFlags(WCF_ABORT_REQUESTED); + } + mMutex.unlock(); } // if doWork is complete or aborted, call endWork() and return true -bool LLWorkerClass::checkWork() +bool LLWorkerClass::checkWork(bool aborting) { + LLMutexLock lock(&mMutex); bool complete = false, abort = false; - LLWorkerThread::Request* workreq = (LLWorkerThread::Request*)mWorkerThread->getRequest(mWorkHandle); - llassert(workreq); - if (getFlags(WCF_ABORT_REQUESTED) || workreq->getStatus() == LLWorkerThread::STATUS_ABORTED) + if (mRequestHandle != LLWorkerThread::nullHandle()) { - complete = true; - abort = true; + LLWorkerThread::WorkRequest* workreq = (LLWorkerThread::WorkRequest*)mWorkerThread->getRequest(mRequestHandle); + llassert_always(workreq); + LLQueuedThread::status_t status = workreq->getStatus(); + if (status == LLWorkerThread::STATUS_ABORTED) + { + complete = true; + abort = true; + } + else if (status == LLWorkerThread::STATUS_COMPLETE) + { + complete = true; + } + else + { + llassert_always(!aborting || (workreq->getFlags() & LLQueuedThread::FLAG_ABORT)); + } + if (complete) + { + llassert_always(!(getFlags(WCF_WORKING))); + endWork(workreq->getParam(), abort); + mWorkerThread->completeRequest(mRequestHandle); + mRequestHandle = LLWorkerThread::nullHandle(); + clearFlags(WCF_HAVE_WORK); + } } - else if (workreq->getStatus() == LLWorkerThread::STATUS_COMPLETE) + else { complete = true; } - if (complete) - { -#if _DEBUG -// llinfos << "endWork: " << mWorkerClassName << " Param: " << workreq->getParam() << llendl; -#endif - endWork(workreq->getParam(), abort); - mWorkerThread->completeRequest(mWorkHandle); - mWorkHandle = LLWorkerThread::nullHandle(); - } return complete; } -void LLWorkerClass::killWork() +void LLWorkerClass::scheduleDelete() { - if (haveWork()) + bool do_delete = false; + mMutex.lock(); + if (!(getFlags(WCF_DELETE_REQUESTED))) { - abortWork(); - bool paused = mWorkerThread->isPaused(); - while (!checkWork()) - { - mWorkerThread->updateQueue(0); - } - if (paused) - { - mWorkerThread->pause(); - } + setFlags(WCF_DELETE_REQUESTED); + do_delete = true; + } + mMutex.unlock(); + if (do_delete) + { + mWorkerThread->deleteWorker(this); } } void LLWorkerClass::setPriority(U32 priority) { - if (haveWork()) + mMutex.lock(); + if (mRequestHandle != LLWorkerThread::nullHandle()) { - mWorkerThread->setPriority(mWorkHandle, priority); + mRequestPriority = priority; + mWorkerThread->setPriority(mRequestHandle, priority); } + mMutex.unlock(); } //============================================================================ diff --git a/indra/llcommon/llworkerthread.h b/indra/llcommon/llworkerthread.h index bf5887e797..d466c35786 100644 --- a/indra/llcommon/llworkerthread.h +++ b/indra/llcommon/llworkerthread.h @@ -28,13 +28,13 @@ class LLWorkerClass; class LLWorkerThread : public LLQueuedThread { public: - class Request : public LLQueuedThread::QueuedRequest + class WorkRequest : public LLQueuedThread::QueuedRequest { protected: - ~Request() {}; // use deleteRequest() + virtual ~WorkRequest(); // use deleteRequest() public: - Request(handle_t handle, U32 priority, LLWorkerClass* workerclass, S32 param); + WorkRequest(handle_t handle, U32 priority, LLWorkerClass* workerclass, S32 param); S32 getParam() { @@ -45,6 +45,8 @@ public: return mWorkerClass; } + /*virtual*/ bool processRequest(); + /*virtual*/ void finishRequest(bool completed); /*virtual*/ void deleteRequest(); private: @@ -52,26 +54,24 @@ public: S32 mParam; }; -public: - LLWorkerThread(bool threaded = true, bool runalways = true); - ~LLWorkerThread(); - -protected: - /*virtual*/ bool processRequest(QueuedRequest* req); +private: + typedef std::list<LLWorkerClass*> delete_list_t; + delete_list_t mDeleteList; + LLMutex* mDeleteMutex; + apr_pool_t* mWorkerAPRPoolp; public: - handle_t add(LLWorkerClass* workerclass, S32 param, U32 priority = PRIORITY_NORMAL); - - static void initClass(bool local_is_threaded = true, bool local_run_always = true); // Setup sLocal - static S32 updateClass(U32 ms_elapsed); - static S32 getAllPending(); - static void pauseAll(); - static void waitOnAllPending(); - static void cleanupClass(); // Delete sLocal + LLWorkerThread(const std::string& name, bool threaded = true); + ~LLWorkerThread(); -public: - static LLWorkerThread* sLocal; // Default worker thread - static std::set<LLWorkerThread*> sThreadList; // array of threads (includes sLocal) + apr_pool_t* getWorkerAPRPool() { return mWorkerAPRPoolp; } + + /*virtual*/ S32 update(U32 max_time_ms); + + handle_t addWorkRequest(LLWorkerClass* workerclass, S32 param, U32 priority = PRIORITY_NORMAL); + + void deleteWorker(LLWorkerClass* workerclass); // schedule for deletion + S32 getNumDeletes() { return mDeleteList.size(); } // debug }; //============================================================================ @@ -93,11 +93,17 @@ public: class LLWorkerClass { + friend class LLWorkerThread; + friend class LLWorkerThread::WorkRequest; public: typedef LLWorkerThread::handle_t handle_t; enum FLAGS { - WCF_WORKING = 0x01, + WCF_HAVE_WORK = 0x01, + WCF_WORKING = 0x02, + WCF_WORK_FINISHED = 0x10, + WCF_WORK_ABORTED = 0x20, + WCF_DELETE_REQUESTED = 0x40, WCF_ABORT_REQUESTED = 0x80 }; @@ -106,17 +112,29 @@ public: virtual ~LLWorkerClass(); // pure virtual, called from WORKER THREAD, returns TRUE if done - virtual bool doWork(S32 param)=0; // Called from LLWorkerThread::processRequest() - - // called from WORKER THREAD - void setWorking(bool working) { working ? setFlags(WCF_WORKING) : clearFlags(WCF_WORKING); } + virtual bool doWork(S32 param)=0; // Called from WorkRequest::processRequest() + // virtual, called from finishRequest() after completed or aborted + virtual void finishWork(S32 param, bool completed); // called from finishRequest() (WORK THREAD) + // virtual, returns true if safe to delete the worker + virtual bool deleteOK(); // called from update() (WORK THREAD) + // schedlueDelete(): schedules deletion once aborted or completed + void scheduleDelete(); + + bool haveWork() { return getFlags(WCF_HAVE_WORK); } // may still be true if aborted bool isWorking() { return getFlags(WCF_WORKING); } bool wasAborted() { return getFlags(WCF_ABORT_REQUESTED); } + + // setPriority(): changes the priority of a request + void setPriority(U32 priority); + U32 getPriority() { return mRequestPriority; } const std::string& getName() const { return mWorkerClassName; } protected: + // called from WORKER THREAD + void setWorking(bool working); + // Call from doWork only to avoid eating up cpu time. // Returns true if work has been aborted // yields the current thread and calls mWorkerThread->checkPause() @@ -128,20 +146,11 @@ protected: void addWork(S32 param, U32 priority = LLWorkerThread::PRIORITY_NORMAL); // abortWork(): requests that work be aborted - void abortWork(); + void abortWork(bool autocomplete); // checkWork(): if doWork is complete or aborted, call endWork() and return true - bool checkWork(); + bool checkWork(bool aborting = false); - // haveWork(): return true if mWorkHandle != null - bool haveWork() { return mWorkHandle != LLWorkerThread::nullHandle(); } - - // killWork(): aborts work and waits for the abort to process - void killWork(); - - // setPriority(): changes the priority of a request - void setPriority(U32 priority); - private: void setFlags(U32 flags) { mWorkFlags = mWorkFlags | flags; } void clearFlags(U32 flags) { mWorkFlags = mWorkFlags & ~flags; } @@ -156,9 +165,11 @@ private: protected: LLWorkerThread* mWorkerThread; std::string mWorkerClassName; - handle_t mWorkHandle; + handle_t mRequestHandle; + U32 mRequestPriority; // last priority set private: + LLMutex mMutex; LLAtomicU32 mWorkFlags; }; diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index dc864aaf53..9b37cdade5 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -17,7 +17,7 @@ #include "llmath.h" #include "stdtypes.h" #include "v4coloru.h" -#include "llmemory.h" +#include "llmemtype.h" #include "llimage.h" #include "llimagebmp.h" @@ -114,7 +114,7 @@ U8* LLImageBase::allocateData(S32 size) llerrs << llformat("LLImageBase::allocateData called with bad dimentions: %dx%dx%d",mWidth,mHeight,mComponents) << llendl; } } - else if ((size <= 0 || size > 4096*4096*16) && sSizeOverride == FALSE) + else if (size <= 0 || (size > 4096*4096*16 && sSizeOverride == FALSE)) { llerrs << "LLImageBase::allocateData: bad size: " << size << llendl; } @@ -197,7 +197,8 @@ LLImageRaw::LLImageRaw(U8 *data, U16 width, U16 height, S8 components) : LLImageBase() { mMemType = LLMemType::MTYPE_IMAGERAW; - copyData(data, width, height, components); + allocateDataSize(width, height, components); + memcpy(getData(), data, width*height*components); ++sRawImageCount; } @@ -239,20 +240,6 @@ void LLImageRaw::deleteData() LLImageBase::deleteData(); } -BOOL LLImageRaw::copyData(U8 *data, U16 width, U16 height, S8 components) -{ - if (!resize(width, height, components)) - { - return FALSE; - } - if (getData() == NULL || data == NULL) - { - return FALSE; - } - memcpy(getData(), data, width*height*components); /* Flawfinder: ignore */ - return TRUE; -} - BOOL LLImageRaw::resize(U16 width, U16 height, S8 components) { if ((getWidth() == width) && (getHeight() == height) && (getComponents() == components)) @@ -1243,25 +1230,8 @@ bool LLImageRaw::createFromFile(const LLString &filename, bool j2c_lowest_mip_on //static S32 LLImageFormatted::sGlobalFormattedMemory = 0; -//static -LLWorkerThread* LLImageFormatted::sWorkerThread = NULL; - -//static -void LLImageFormatted::initClass(bool threaded, bool run_always) -{ - sWorkerThread = new LLWorkerThread(threaded, run_always); -} - -//static -void LLImageFormatted::cleanupClass() -{ - delete sWorkerThread; - sWorkerThread = NULL; -} - - LLImageFormatted::LLImageFormatted(S8 codec) - : LLImageBase(), LLWorkerClass(sWorkerThread, "ImageFormatted"), + : LLImageBase(), mCodec(codec), mDecoding(0), mDecoded(0), @@ -1276,64 +1246,14 @@ LLImageFormatted::~LLImageFormatted() // NOTE: ~LLimageBase() call to deleteData() calls LLImageBase::deleteData() // NOT LLImageFormatted::deleteData() deleteData(); - releaseDecodedData(); -} - -//---------------------------------------------------------------------------- - -//virtual -void LLImageFormatted::startWork(S32 param) -{ - if (mDecoding) llerrs << "WTF?" << llendl; -} - -bool LLImageFormatted::doWork(S32 param) -{ - if (!(isWorking())) llerrs << "WTF?" << llendl; - llassert(mDecodedImage.notNull()); - if (param == 0) - { - // Decode primary channels - mDecoded = decode(mDecodedImage, .001f); // 1ms - } - else - { - // Decode aux channel - mDecoded = decode(mDecodedImage, .001f, param, param); // 1ms - } - if (mDecoded) - { - return true; - } - else - { - return false; - } -} - -void LLImageFormatted::endWork(S32 param, bool aborted) -{ - if (mDecoding) llerrs << "WTF?" << llendl; - if (!mDecoded) llerrs << "WTF?" << llendl; } //---------------------------------------------------------------------------- // static -LLImageFormatted* LLImageFormatted::createFromExtension(const LLString& instring) +LLImageFormatted* LLImageFormatted::createFromType(S8 codec) { - LLString exten; - size_t dotidx = instring.rfind('.'); - if (dotidx != LLString::npos) - { - exten = instring.substr(dotidx+1); - } - else - { - exten = instring; - } - S8 codec = get_codec(exten); - LLPointer<LLImageFormatted> image; + LLImageFormatted* image; switch(codec) { case IMG_CODEC_BMP: @@ -1354,10 +1274,28 @@ LLImageFormatted* LLImageFormatted::createFromExtension(const LLString& instring image = new LLImageDXT(); break; default: + image = NULL; break; } return image; } + +// static +LLImageFormatted* LLImageFormatted::createFromExtension(const LLString& instring) +{ + LLString exten; + size_t dotidx = instring.rfind('.'); + if (dotidx != LLString::npos) + { + exten = instring.substr(dotidx+1); + } + else + { + exten = instring; + } + S8 codec = get_codec(exten); + return createFromType(codec); +} //---------------------------------------------------------------------------- // virtual @@ -1374,15 +1312,6 @@ void LLImageFormatted::dump() //---------------------------------------------------------------------------- -void LLImageFormatted::readHeader(U8* data, S32 size) -{ - if (size <= 0) - { - size = calcHeaderSize(); - } - copyData(data, size); // calls updateData() -} - S32 LLImageFormatted::calcDataSize(S32 discard_level) { if (discard_level < 0) @@ -1426,82 +1355,6 @@ BOOL LLImageFormatted::decode(LLImageRaw* raw_image,F32 decode_time, S32 first_ return decode( raw_image, decode_time ); // Loads first 4 channels by default. } -// virtual -BOOL LLImageFormatted::requestDecodedData(LLPointer<LLImageRaw>& raw, S32 discard, F32 decode_time) -{ - llassert(getData() && getDataSize()); - // For most codecs, only mDiscardLevel data is available. (see LLImageDXT for exception) - if (discard >= 0 && discard != mDiscardLevel) - { - llerrs << "Request for invalid discard level" << llendl; - } - if (haveWork()) - { - checkWork(); - } - if (!mDecoded) - { - if (!haveWork()) - { - llassert(!mDecoding); - mDecodedImage = new LLImageRaw(getWidth(), getHeight(), getComponents()); - addWork(0); - } - return FALSE; - } - else - { - llassert(mDecodedImage.notNull()); - llassert(!mDecoding); - raw = mDecodedImage; - return TRUE; - } -} - -BOOL LLImageFormatted::requestDecodedAuxData(LLPointer<LLImageRaw>& raw, S32 channel, - S32 discard, F32 decode_time) -{ - llassert(getData() && getDataSize()); - // For most codecs, only mDiscardLevel data is available. (see LLImageDXT for exception) - if (discard >= 0 && discard != mDiscardLevel) - { - llerrs << "Request for invalid discard level" << llendl; - } - if (haveWork()) - { - checkWork(); - } - if (!mDecoded) - { - if (!haveWork()) - { - llassert(!mDecoding); - mDecodedImage = new LLImageRaw(getWidth(), getHeight(), 1); - addWork(channel); - } - return FALSE; - } - else - { - llassert(mDecodedImage.notNull()); - llassert(!mDecoding); - raw = mDecodedImage; - return TRUE; - } -} - - -// virtual -void LLImageFormatted::releaseDecodedData() -{ - if (mDecoded || mDecoding) - { - mDecodedImage = NULL; // deletes image - mDecoded = FALSE; - mDecoding = FALSE; - } -} - //---------------------------------------------------------------------------- // virtual @@ -1549,52 +1402,42 @@ void LLImageFormatted::sanityCheck() BOOL LLImageFormatted::copyData(U8 *data, S32 size) { - if (data && data != getData()) + if ( (data && data != getData()) || (size != getDataSize()) ) { deleteData(); allocateData(size); memcpy(getData(), data, size); /* Flawfinder: ignore */ } - updateData(); // virtual - return TRUE; } -BOOL LLImageFormatted::appendData(U8 *data, S32 size) +// LLImageFormatted becomes the owner of data +void LLImageFormatted::setData(U8 *data, S32 size) { - LLMemType mt1((LLMemType::EMemType)mMemType); - S32 old_size = getDataSize(); - U8* old_data = getData(); - S32 new_size = old_size + size; - U8* new_data = new U8[new_size]; - if (!new_data) - { - llerrs << "Out of memory in LLImageFormatted::appendData(U8 *data, S32 size)" << llendl; - return FALSE; - } - // resize the image - setDataAndSize(new_data, new_size); - // copy the old data and delete it - memcpy(new_data, old_data, old_size); /* Flawfinder: ignore */ - delete old_data; - // if we have new data, copy it and call updateData() - if (data) + if (data && data != getData()) { - memcpy(new_data + old_size, data, size); /* Flawfinder: ignore */ - updateData(); // virtual + deleteData(); + setDataAndSize(data, size); // Access private LLImageBase members + sGlobalFormattedMemory += getDataSize(); } - return TRUE; } -BOOL LLImageFormatted::setData(U8 *data, S32 size) +void LLImageFormatted::appendData(U8 *data, S32 size) { - if (data && data != getData()) + if (data) { - deleteData(); - setDataAndSize(data, size); // Access private LLImageBase members - sGlobalFormattedMemory += getDataSize(); + if (!getData()) + { + setData(data, size); + } + else + { + S32 cursize = getDataSize(); + S32 newsize = cursize + size; + reallocateData(newsize); + memcpy(getData() + cursize, data, size); + } } - return updateData(); // virtual } //---------------------------------------------------------------------------- @@ -1667,8 +1510,6 @@ S8 LLImageFormatted::getCodec() const //============================================================================ -//---------------------------------------------------------------------------- - static void avg4_colors4(const U8* a, const U8* b, const U8* c, const U8* d, U8* dst) { dst[0] = (U8)(((U32)(a[0]) + b[0] + c[0] + d[0])>>2); @@ -1794,3 +1635,5 @@ F32 LLImageBase::calc_download_priority(F32 virtual_size, F32 visible_pixels, S3 return w_priority; } + +//============================================================================ diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h index 13ea916654..0e007c2c86 100644 --- a/indra/llimage/llimage.h +++ b/indra/llimage/llimage.h @@ -13,7 +13,7 @@ #include "lluuid.h" #include "llstring.h" #include "llmemory.h" -#include "llworkerthread.h" +#include "llthread.h" const S32 MIN_IMAGE_MIP = 2; // 4x4, only used for expand/contract power of 2 const S32 MAX_IMAGE_MIP = 11; // 2048x2048 @@ -135,8 +135,6 @@ public: /*virtual*/ U8* allocateData(S32 size = -1); /*virtual*/ U8* reallocateData(S32 size); - BOOL copyData(U8 *data, U16 width, U16 height, S8 components); - BOOL resize(U16 width, U16 height, S8 components); U8 * getSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height) const; @@ -206,11 +204,10 @@ public: // Compressed representation of image. // Subclass from this class for the different representations (J2C, bmp) -class LLImageFormatted : public LLImageBase, public LLWorkerClass +class LLImageFormatted : public LLImageBase { public: - static void initClass(bool threaded = true, bool run_always = true); - static void cleanupClass(); + static LLImageFormatted* createFromType(S8 codec); static LLImageFormatted* createFromExtension(const LLString& instring); protected: @@ -228,22 +225,11 @@ public: /*virtual*/ void dump(); /*virtual*/ void sanityCheck(); - // LLWorkerThread -public: - // called from WORKER THREAD, returns TRUE if done - /*virtual*/ bool doWork(S32 param); -private: - // called from MAIN THREAD - /*virtual*/ void startWork(S32 param); // called from addWork() - /*virtual*/ void endWork(S32 param, bool aborted); // called from doWork() - // New methods public: // calcHeaderSize() returns the maximum size of header; // 0 indicates we don't know have a header and have to lead the entire file virtual S32 calcHeaderSize() { return 0; }; - // readHeader() reads size bytes into mData, and sets width/height/ncomponents - virtual void readHeader(U8* data, S32 size); // calcDataSize() returns how many bytes to read to load discard_level (including header) virtual S32 calcDataSize(S32 discard_level); // calcDiscardLevelBytes() returns the smallest valid discard level based on the number of input bytes @@ -253,27 +239,16 @@ public: BOOL load(const LLString& filename); BOOL save(const LLString& filename); -// BOOL save(LLVFS *vfs, const LLUUID &uuid, const LLAssetType::EType type); -// Depricated to remove VFS dependency (see .cpp for replacement): virtual BOOL updateData() = 0; // pure virtual - BOOL copyData(U8 *data, S32 size); // calls updateData() - BOOL setData(U8 *data, S32 size); // calls updateData() - BOOL appendData(U8 *data, S32 size); // use if some data (e.g header) is already loaded, calls updateData() + void setData(U8 *data, S32 size); + void appendData(U8 *data, S32 size); // Loads first 4 channels. virtual BOOL decode(LLImageRaw* raw_image, F32 decode_time=0.0) = 0; // Subclasses that can handle more than 4 channels should override this function. virtual BOOL decode(LLImageRaw* raw_image, F32 decode_time, S32 first_channel, S32 max_channel); - // Decode methods to return a pointer to raw data for purposes of passing to - // opengl or such. This class tracks the decoded data and keeps it alive until - // destroyed or releaseDecodedData() is called. - virtual BOOL requestDecodedData(LLPointer<LLImageRaw>& raw, S32 discard = -1, F32 decode_time=0.0); - virtual BOOL requestDecodedAuxData(LLPointer<LLImageRaw>& raw, S32 channel, - S32 discard = -1, F32 decode_time=0.0); - virtual void releaseDecodedData(); - virtual BOOL encode(const LLImageRaw* raw_image, F32 encode_time=0.0) = 0; S8 getCodec() const; @@ -283,16 +258,16 @@ public: S8 getDiscardLevel() const { return mDiscardLevel; } protected: + BOOL copyData(U8 *data, S32 size); // calls updateData() + +protected: S8 mCodec; S8 mDecoding; S8 mDecoded; S8 mDiscardLevel; - LLPointer<LLImageRaw> mDecodedImage; - public: static S32 sGlobalFormattedMemory; - static LLWorkerThread* sWorkerThread; }; #endif diff --git a/indra/llimage/llimagedxt.cpp b/indra/llimage/llimagedxt.cpp index dfb5b957d3..1b6ce65274 100644 --- a/indra/llimage/llimagedxt.cpp +++ b/indra/llimage/llimagedxt.cpp @@ -265,8 +265,7 @@ BOOL LLImageDXT::decode(LLImageRaw* raw_image, F32 time) return TRUE; } -// virtual -BOOL LLImageDXT::requestDecodedData(LLPointer<LLImageRaw>& raw, S32 discard, F32 decode_time) +BOOL LLImageDXT::getMipData(LLPointer<LLImageRaw>& raw, S32 discard) { if (discard < 0) { @@ -283,11 +282,6 @@ BOOL LLImageDXT::requestDecodedData(LLPointer<LLImageRaw>& raw, S32 discard, F32 return TRUE; } -void LLImageDXT::releaseDecodedData() -{ - // nothing to do -} - BOOL LLImageDXT::encode(const LLImageRaw* raw_image, F32 time, bool explicit_mips) { llassert_always(raw_image); @@ -426,6 +420,7 @@ bool LLImageDXT::convertToDXR() dxtfile_header_t* header = (dxtfile_header_t*)newdata; header->pixel_fmt.fourcc = getFourCC(newformat); setData(newdata, total_bytes); + updateData(); return true; } diff --git a/indra/llimage/llimagedxt.h b/indra/llimage/llimagedxt.h index 88d28a2958..e286d03e1e 100644 --- a/indra/llimage/llimagedxt.h +++ b/indra/llimage/llimagedxt.h @@ -82,12 +82,11 @@ public: BOOL encode(const LLImageRaw* raw_image, F32 time, bool explicit_mips); /*virtual*/ BOOL encode(const LLImageRaw* raw_image, F32 time=0.0); - /*virtual*/ BOOL requestDecodedData(LLPointer<LLImageRaw>& raw, S32 discard=-1, F32 decode_time=0.0); - /*virtual*/ void releaseDecodedData(); - /*virtual*/ S32 calcHeaderSize(); /*virtual*/ S32 calcDataSize(S32 discard_level = 0); + BOOL getMipData(LLPointer<LLImageRaw>& raw, S32 discard=-1); + void setFormat(); S32 getMipOffset(S32 discard); diff --git a/indra/llimage/llimagej2c.cpp b/indra/llimage/llimagej2c.cpp index 32a8c60fac..398e7c9e32 100644 --- a/indra/llimage/llimagej2c.cpp +++ b/indra/llimage/llimagej2c.cpp @@ -11,7 +11,7 @@ #include "lldir.h" #include "llimagej2c.h" -#include "llmemory.h" +#include "llmemtype.h" typedef LLImageJ2CImpl* (*CreateLLImageJ2CFunction)(); typedef void (*DestroyLLImageJ2CFunction)(LLImageJ2CImpl*); @@ -224,7 +224,22 @@ BOOL LLImageJ2C::decode(LLImageRaw *raw_imagep, F32 decode_time, S32 first_chann // Update the raw discard level updateRawDiscardLevel(); - return mImpl->decodeImpl(*this, *raw_imagep, decode_time, first_channel, max_channel_count); + mDecoding = TRUE; + BOOL res = mImpl->decodeImpl(*this, *raw_imagep, decode_time, first_channel, max_channel_count); + if (res) + { + if (!mDecoding) + { + // Failed + raw_imagep->deleteData(); + } + else + { + mDecoding = FALSE; + } + return TRUE; // done + } + return FALSE; } @@ -334,7 +349,7 @@ BOOL LLImageJ2C::loadAndValidate(const LLString &filename) U8 *data = new U8[file_size]; apr_size_t bytes_read = file_size; apr_status_t s = apr_file_read(apr_file, data, &bytes_read); // modifies bytes_read - if (s != APR_SUCCESS || bytes_read != file_size) + if (s != APR_SUCCESS || (S32)bytes_read != file_size) { delete[] data; setLastError("Unable to read entire file"); @@ -349,9 +364,9 @@ BOOL LLImageJ2C::loadAndValidate(const LLString &filename) BOOL LLImageJ2C::validate(U8 *data, U32 file_size) { LLMemType mt1((LLMemType::EMemType)mMemType); - // Taken from setData() - BOOL res = LLImageFormatted::setData(data, file_size); + setData(data, file_size); + BOOL res = updateData(); if ( !res ) { return FALSE; @@ -367,10 +382,9 @@ BOOL LLImageJ2C::validate(U8 *data, U32 file_size) return mImpl->getMetadata(*this); } -void LLImageJ2C::setDecodingDone(BOOL complete) +void LLImageJ2C::decodeFailed() { mDecoding = FALSE; - mDecoded = complete; } void LLImageJ2C::updateRawDiscardLevel() diff --git a/indra/llimage/llimagej2c.h b/indra/llimage/llimagej2c.h index 4a3b017a55..1181ae2bb8 100644 --- a/indra/llimage/llimagej2c.h +++ b/indra/llimage/llimagej2c.h @@ -53,7 +53,7 @@ protected: friend class LLImageJ2CImpl; friend class LLImageJ2COJ; friend class LLImageJ2CKDU; - void setDecodingDone(BOOL complete = TRUE); + void decodeFailed(); void updateRawDiscardLevel(); S32 mMaxBytes; // Maximum number of bytes of data to use... diff --git a/indra/llimage/llimageworker.cpp b/indra/llimage/llimageworker.cpp new file mode 100644 index 0000000000..b44bf19227 --- /dev/null +++ b/indra/llimage/llimageworker.cpp @@ -0,0 +1,165 @@ +/**
+ * @file llimage.cpp
+ * @brief Base class for images.
+ *
+ * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#include "linden_common.h"
+
+#include "llimageworker.h"
+#include "llimagedxt.h"
+
+//----------------------------------------------------------------------------
+
+//static
+LLWorkerThread* LLImageWorker::sWorkerThread = NULL;
+S32 LLImageWorker::sCount = 0;
+
+//static
+void LLImageWorker::initClass(LLWorkerThread* workerthread)
+{
+ sWorkerThread = workerthread;
+}
+
+//static
+void LLImageWorker::cleanupClass()
+{
+}
+
+//----------------------------------------------------------------------------
+
+LLImageWorker::LLImageWorker(LLImageFormatted* image, U32 priority, S32 discard, LLResponder* responder)
+ : LLWorkerClass(sWorkerThread, "Image"),
+ mFormattedImage(image),
+ mDecodedType(-1),
+ mDiscardLevel(discard),
+ mPriority(priority),
+ mResponder(responder)
+{
+ ++sCount;
+}
+
+LLImageWorker::~LLImageWorker()
+{
+ mDecodedImage = NULL;
+ mFormattedImage = NULL;
+ --sCount;
+}
+
+//----------------------------------------------------------------------------
+
+//virtual, main thread
+void LLImageWorker::startWork(S32 param)
+{
+ llassert_always(mDecodedImage.isNull());
+ mDecodedType = -1;
+}
+
+bool LLImageWorker::doWork(S32 param)
+{
+ bool decoded = false;
+ if(mDecodedImage.isNull())
+ {
+ if (!mFormattedImage->updateData())
+ {
+ mDecodedType = -2; // failed
+ return true;
+ }
+ if (mDiscardLevel >= 0)
+ {
+ mFormattedImage->setDiscardLevel(mDiscardLevel);
+ }
+ if (!(mFormattedImage->getWidth() * mFormattedImage->getHeight() * mFormattedImage->getComponents()))
+ {
+ decoded = true; // failed
+ }
+ else
+ {
+ S32 nc = param ? 1 : mFormattedImage->getComponents();
+ mDecodedImage = new LLImageRaw(mFormattedImage->getWidth(),
+ mFormattedImage->getHeight(),
+ nc);
+ }
+ }
+ if (!decoded)
+ {
+ if (param == 0)
+ {
+ // Decode primary channels
+ decoded = mFormattedImage->decode(mDecodedImage, .1f); // 1ms
+ }
+ else
+ {
+ // Decode aux channel
+ decoded = mFormattedImage->decode(mDecodedImage, .1f, param, param); // 1ms
+ }
+ }
+ if (decoded)
+ {
+ // Call the callback immediately; endWork doesn't get called until ckeckWork
+ if (mResponder.notNull())
+ {
+ bool success = (!wasAborted() && mDecodedImage.notNull() && mDecodedImage->getDataSize() != 0);
+ mResponder->completed(success);
+ }
+ }
+ return decoded;
+}
+
+void LLImageWorker::endWork(S32 param, bool aborted)
+{
+ if (mDecodedType != -2)
+ {
+ mDecodedType = aborted ? -2 : param;
+ }
+}
+
+//----------------------------------------------------------------------------
+
+
+BOOL LLImageWorker::requestDecodedAuxData(LLPointer<LLImageRaw>& raw, S32 channel, S32 discard)
+{
+ // For most codecs, only mDiscardLevel data is available.
+ // (see LLImageDXT for exception)
+ if (discard >= 0 && discard != mFormattedImage->getDiscardLevel())
+ {
+ llerrs << "Request for invalid discard level" << llendl;
+ }
+ checkWork();
+ if (mDecodedType == -2)
+ {
+ return TRUE; // aborted, done
+ }
+ if (mDecodedType != channel)
+ {
+ if (!haveWork())
+ {
+ addWork(channel, mPriority);
+ }
+ return FALSE;
+ }
+ else
+ {
+ llassert_always(!haveWork());
+ llassert_always(mDecodedType == channel);
+ raw = mDecodedImage; // smart pointer acquires ownership of data
+ mDecodedImage = NULL;
+ return TRUE;
+ }
+}
+
+BOOL LLImageWorker::requestDecodedData(LLPointer<LLImageRaw>& raw, S32 discard)
+{
+ if (mFormattedImage->getCodec() == IMG_CODEC_DXT)
+ {
+ // special case
+ LLImageDXT* imagedxt = (LLImageDXT*)((LLImageFormatted*)mFormattedImage);
+ return imagedxt->getMipData(raw, discard);
+ }
+ else
+ {
+ return requestDecodedAuxData(raw, 0, discard);
+ }
+}
diff --git a/indra/llimage/llimageworker.h b/indra/llimage/llimageworker.h new file mode 100644 index 0000000000..cdd30417ce --- /dev/null +++ b/indra/llimage/llimageworker.h @@ -0,0 +1,57 @@ +/**
+ * @file llimageworker.h
+ * @brief Object for managing images and their textures.
+ *
+ * Copyright (c) 2000-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#ifndef LL_LLIMAGEWORKER_H
+#define LL_LLIMAGEWORKER_H
+
+#include "llimage.h"
+#include "llworkerthread.h"
+
+class LLImageWorker : public LLWorkerClass
+{
+public:
+ static void initClass(LLWorkerThread* workerthread);
+ static void cleanupClass();
+ static LLWorkerThread* getWorkerThread() { return sWorkerThread; }
+
+ // LLWorkerThread
+public:
+ LLImageWorker(LLImageFormatted* image, U32 priority, S32 discard, LLResponder* responder = NULL);
+ ~LLImageWorker();
+
+ // called from WORKER THREAD, returns TRUE if done
+ /*virtual*/ bool doWork(S32 param);
+
+ BOOL requestDecodedData(LLPointer<LLImageRaw>& raw, S32 discard = -1);
+ BOOL requestDecodedAuxData(LLPointer<LLImageRaw>& raw, S32 channel, S32 discard = -1);
+ void releaseDecodedData();
+ void cancelDecode();
+
+private:
+ // called from MAIN THREAD
+ /*virtual*/ void startWork(S32 param); // called from addWork()
+ /*virtual*/ void endWork(S32 param, bool aborted); // called from doWork()
+
+protected:
+ LLPointer<LLImageFormatted> mFormattedImage;
+ LLPointer<LLImageRaw> mDecodedImage;
+ S32 mDecodedType;
+ S32 mDiscardLevel;
+
+private:
+ U32 mPriority;
+ LLPointer<LLResponder> mResponder;
+
+protected:
+ static LLWorkerThread* sWorkerThread;
+
+public:
+ static S32 sCount;
+};
+
+#endif
diff --git a/indra/llimagej2coj/llimagej2coj.cpp b/indra/llimagej2coj/llimagej2coj.cpp index 823d2a8dd4..a6c7c623f3 100644 --- a/indra/llimagej2coj/llimagej2coj.cpp +++ b/indra/llimagej2coj/llimagej2coj.cpp @@ -151,7 +151,6 @@ BOOL LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decod /* free image data structure */ opj_image_destroy(image); - base.setDecodingDone(); return TRUE; } @@ -262,6 +261,7 @@ BOOL LLImageJ2COJ::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, con codestream_length = cio_tell(cio); base.copyData(cio->buffer, codestream_length); + base.updateData(); // set width, height /* close and free the byte stream */ opj_cio_close(cio); diff --git a/indra/llinventory/llinventory.h b/indra/llinventory/llinventory.h index 9f750c46b2..8a6fdfd0ad 100644 --- a/indra/llinventory/llinventory.h +++ b/indra/llinventory/llinventory.h @@ -13,6 +13,7 @@ #include "llassetstorage.h" #include "lldarray.h" +#include "llmemtype.h" #include "llpermissions.h" #include "llsaleinfo.h" #include "llsd.h" diff --git a/indra/llmath/lloctree.h b/indra/llmath/lloctree.h index bea21e22c6..e5b2a5f312 100644 --- a/indra/llmath/lloctree.h +++ b/indra/llmath/lloctree.h @@ -21,6 +21,7 @@ #endif #define LL_OCTREE_PARANOIA_CHECK 0 +#define LL_OCTREE_MAX_CAPACITY 256 template <class T> class LLOctreeState; template <class T> class LLOctreeNode; @@ -88,7 +89,8 @@ public: virtual void removeByAddress(T* data) { getOctState()->removeByAddress(data); } virtual bool hasLeafState() const { return getOctState()->isLeaf(); } virtual void destroy() { getOctState()->destroy(); } - virtual oct_node* getNodeAt(T* data) { return getOctState()->getNodeAt(data); } + virtual oct_node* getNodeAt(T* data) { return getNodeAt(data->getPositionGroup(), data->getBinRadius()); } + virtual oct_node* getNodeAt(const LLVector3d& pos, const F64& rad) { return getOctState()->getNodeAt(pos, rad); } virtual U8 getOctant() const { return mOctant; } virtual void setOctant(U8 octant) { mOctant = octant; } virtual const oct_state* getOctState() const { return (const oct_state*) BaseType::mState; } @@ -117,9 +119,14 @@ public: return ret; } + virtual bool isInside(const LLVector3d& pos, const F64& rad) const + { + return rad <= mSize.mdV[0]*2.0 && isInside(pos); + } + virtual bool isInside(T* data) const { - return data->getBinRadius() <= mSize.mdV[0]*2.0 && isInside(data->getPositionGroup()); + return isInside(data->getPositionGroup(), data->getBinRadius()); } virtual bool isInside(const LLVector3d& pos) const @@ -155,6 +162,11 @@ public: bool contains(T* xform) { + return contains(xform->getBinRadius()); + } + + bool contains(F64 radius) + { if (mParent == NULL) { //root node contains nothing return false; @@ -162,7 +174,6 @@ public: F64 size = mSize.mdV[0]; F64 p_size = size * 2.0; - F64 radius = xform->getBinRadius(); return (radius <= 0.001 && size <= 0.001) || (radius <= p_size && radius > size); @@ -247,11 +258,15 @@ public: oct_node* getOctNode() { return (oct_node*) BaseType::getNode(); } virtual oct_node* getNodeAt(T* data) + { + return getNodeAt(data->getPositionGroup(), data->getBinRadius()); + } + + virtual oct_node* getNodeAt(const LLVector3d& pos, const F64& rad) { - const LLVector3d& pos = data->getPositionGroup(); LLOctreeNode<T>* node = getOctNode(); - if (node->isInside(data)) + if (node->isInside(pos, rad)) { //do a quick search by octant U8 octant = node->getOctant(pos.mdV); @@ -261,7 +276,7 @@ public: //at the appropriate octant or is smaller than the object. //by definition, that node is the smallest node that contains // the data - while (keep_going && node->getSize().mdV[0] >= data->getBinRadius()) + while (keep_going && node->getSize().mdV[0] >= rad) { keep_going = FALSE; for (U32 i = 0; i < node->getChildCount() && !keep_going; i++) @@ -275,9 +290,9 @@ public: } } } - else if (!node->contains(data) && node->getParent()) + else if (!node->contains(rad) && node->getParent()) { //if we got here, data does not exist in this node - return ((LLOctreeNode<T>*) node->getParent())->getNodeAt(data); + return ((LLOctreeNode<T>*) node->getParent())->getNodeAt(pos, rad); } return node; @@ -291,22 +306,15 @@ public: return false; } LLOctreeNode<T>* node = getOctNode(); + LLOctreeNode<T>* parent = node->getOctParent(); - if (data->getBinRadius() <= node->getSize().mdV[0]) - { - oct_node* dest = getNodeAt(data); - - if (dest != node) - { - dest->insert(data); - return false; - } - } - - //no kid found, is it even here? - if (node->isInside(data)) + //is it here? + if (node->isInside(data->getPositionGroup())) { - if (node->contains(data)) + if (getElementCount() < LL_OCTREE_MAX_CAPACITY && + (node->contains(data->getBinRadius()) || + (data->getBinRadius() > node->getSize().mdV[0] && + parent && parent->getElementCount() >= LL_OCTREE_MAX_CAPACITY))) { //it belongs here if (data == NULL) { @@ -327,7 +335,19 @@ public: return true; } else - { + { + //find a child to give it to + oct_node* child = NULL; + for (U32 i = 0; i < getChildCount(); i++) + { + child = getChild(i); + if (child->isInside(data->getPositionGroup())) + { + child->insert(data); + return false; + } + } + //it's here, but no kids are in the right place, make a new kid LLVector3d center(node->getCenter()); LLVector3d size(node->getSize()*0.5); @@ -359,7 +379,7 @@ public: //make the new kid LLOctreeState<T>* newstate = new LLOctreeState<T>(); - oct_node* child = new LLOctreeNode<T>(center, size, newstate, node); + child = new LLOctreeNode<T>(center, size, newstate, node); addChild(child); child->insert(data); @@ -367,8 +387,15 @@ public: } else { - //it's not in here, give it to the parent - node->getOctParent()->insert(data); + //it's not in here, give it to the root + LLOctreeNode<T>* parent = node->getOctParent(); + while (parent) + { + node = parent; + parent = node->getOctParent(); + } + + node->insert(data); } return false; diff --git a/indra/llmath/lltreenode.h b/indra/llmath/lltreenode.h index dd0c73c00c..cdc52cf90a 100644 --- a/indra/llmath/lltreenode.h +++ b/indra/llmath/lltreenode.h @@ -22,7 +22,6 @@ class LLTreeState public: LLTreeState(LLTreeNode<T>* node) { setNode(node); } virtual ~LLTreeState() { }; - virtual bool insert(T* data) = 0; virtual bool remove(T* data) = 0; virtual void setNode(LLTreeNode<T>* node); @@ -35,7 +34,7 @@ private: }; template <class T> -class LLTreeListener +class LLTreeListener: public LLRefCount { public: virtual ~LLTreeListener() { }; @@ -75,7 +74,7 @@ protected: LLTreeState<T>* mState; public: - std::vector<LLTreeListener<T>*> mListeners; + std::vector<LLPointer<LLTreeListener<T> > > mListeners; }; template <class T> diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index 75e4042f07..5354de783c 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -1765,9 +1765,6 @@ void LLVolume::createVolumeFaces() mVolumeFaces[i].create(); } } - - mBounds[1] = LLVector3(0,0,0); - mBounds[0] = LLVector3(512,512,512); } @@ -1812,21 +1809,28 @@ void LLVolumeParams::copyParams(const LLVolumeParams ¶ms) mPathParams.copyParams(params.mPathParams); } +// Less restricitve approx 0 for volumes +const F32 APPROXIMATELY_ZERO = 0.001f; +bool approx_zero( F32 f, F32 tolerance = APPROXIMATELY_ZERO) +{ + return (f >= -tolerance) && (f <= tolerance); +} + // return true if in range (or nearly so) -static bool limit_range(F32& v, F32 min, F32 max) +static bool limit_range(F32& v, F32 min, F32 max, F32 tolerance = APPROXIMATELY_ZERO) { F32 min_delta = v - min; if (min_delta < 0.f) { v = min; - if (!is_approx_zero(min_delta)) + if (!approx_zero(min_delta, tolerance)) return false; } F32 max_delta = max - v; if (max_delta < 0.f) { v = max; - if (!is_approx_zero(max_delta)) + if (!approx_zero(max_delta, tolerance)) return false; } return true; @@ -1841,9 +1845,10 @@ bool LLVolumeParams::setBeginAndEndS(const F32 b, const F32 e) valid &= limit_range(begin, 0.f, 1.f - MIN_CUT_DELTA); F32 end = e; + if (end >= .0149f && end < MIN_CUT_DELTA) end = MIN_CUT_DELTA; // eliminate warning for common rounding error valid &= limit_range(end, MIN_CUT_DELTA, 1.f); - valid &= limit_range(begin, 0.f, end - MIN_CUT_DELTA); + valid &= limit_range(begin, 0.f, end - MIN_CUT_DELTA, .01f); // Now set them. mProfileParams.setBegin(begin); @@ -1863,7 +1868,7 @@ bool LLVolumeParams::setBeginAndEndT(const F32 b, const F32 e) F32 end = e; valid &= limit_range(end, MIN_CUT_DELTA, 1.f); - valid &= limit_range(begin, 0.f, end - MIN_CUT_DELTA); + valid &= limit_range(begin, 0.f, end - MIN_CUT_DELTA, .01f); // Now set them. mPathParams.setBegin(begin); @@ -2020,7 +2025,7 @@ bool LLVolumeParams::setRadiusOffset(const F32 offset) { radius_offset = max_radius_mag; } - valid = is_approx_zero(delta); + valid = approx_zero(delta, .1f); } mPathParams.setRadiusOffset(radius_offset); @@ -2054,7 +2059,7 @@ bool LLVolumeParams::setSkew(const F32 skew_value) { skew = min_skew_mag; } - valid = is_approx_zero(delta); + valid = approx_zero(delta); } mPathParams.setSkew(skew); @@ -2980,10 +2985,15 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices, S32 v2 = face.mIndices[j*3+((k+1)%3)]; vertices.push_back(face.mVertices[v1].mPosition*mat); - normals.push_back(face.mVertices[v1].mNormal*norm_mat); + LLVector3 norm1 = face.mVertices[v1].mNormal * norm_mat; + norm1.normVec(); + normals.push_back(norm1); vertices.push_back(face.mVertices[v2].mPosition*mat); - normals.push_back(face.mVertices[v2].mNormal*norm_mat); + LLVector3 norm2 = face.mVertices[v2].mNormal * norm_mat; + norm2.normVec(); + normals.push_back(norm2); + segments.push_back(vertices.size()); } } @@ -3747,6 +3757,9 @@ BOOL LLVolumeFace::createUnCutCubeCap() num_vertices = (grid_size+1)*(grid_size+1); num_indices = quad_count * 4; + LLVector3& min = mExtents[0]; + LLVector3& max = mExtents[1]; + S32 offset = 0; if (mTypeMask & TOP_MASK) offset = (max_t-1) * max_s; @@ -3786,32 +3799,6 @@ BOOL LLVolumeFace::createUnCutCubeCap() } S32 vtop = mVertices.size(); -// S32 itop = mIndices.size(); -/// vector_append(mVertices,4); -// vector_append(mIndices,4); -// LLVector3 new_pt = lerp(pt1, pt2, t_fraction); -#if 0 - for(int t=0;t<4;t++){ - VertexData vd; - vd.mPosition = corners[t].mPosition; - vd.mNormal = - ((corners[(t+1)%4].mPosition-corners[t].mPosition)% - (corners[(t+2)%4].mPosition-corners[(t+1)%4].mPosition)); - vd.mNormal.normVec(); - - if (mTypeMask & TOP_MASK) - vd.mNormal *= -1.0f; - vd.mBinormal = vd.mNormal; - vd.mTexCoord = corners[t].mTexCoord; - mVertices.push_back(vd); - } - int idxs[] = {0,1,2,2,3,0}; - if (mTypeMask & TOP_MASK){ - for(int i=0;i<6;i++)mIndices.push_back(vtop+idxs[i]); - }else{ - for(int i=5;i>=0;i--)mIndices.push_back(vtop+idxs[i]); - } -#else for(int gx = 0;gx<grid_size+1;gx++){ for(int gy = 0;gy<grid_size+1;gy++){ VertexData newVert; @@ -3823,8 +3810,20 @@ BOOL LLVolumeFace::createUnCutCubeCap() (F32)gx/(F32)grid_size, (F32)gy/(F32)grid_size); mVertices.push_back(newVert); + + if (gx == 0 && gy == 0) + { + min = max = newVert.mPosition; + } + else + { + update_min_max(min,max,newVert.mPosition); + } } } + + mCenter = (min + max) * 0.5f; + int idxs[] = {0,1,(grid_size+1)+1,(grid_size+1)+1,(grid_size+1),0}; for(int gx = 0;gx<grid_size;gx++){ for(int gy = 0;gy<grid_size;gy++){ @@ -3835,7 +3834,7 @@ BOOL LLVolumeFace::createUnCutCubeCap() } } } -#endif + return TRUE; } @@ -3882,12 +3881,15 @@ BOOL LLVolumeFace::createCap() // Figure out the normal, assume all caps are flat faces. // Cross product to get normals. - LLVector2 cuv = LLVector2(0,0); - + LLVector2 cuv; + LLVector2 min_uv, max_uv; + + LLVector3& min = mExtents[0]; + LLVector3& max = mExtents[1]; + // Copy the vertices into the array for (i = 0; i < num_vertices; i++) { - if (mTypeMask & TOP_MASK) { mVertices[i].mTexCoord.mV[0] = profile[i].mV[0]+0.5f; @@ -3900,17 +3902,22 @@ BOOL LLVolumeFace::createCap() mVertices[i].mTexCoord.mV[1] = 0.5f - profile[i].mV[1]; } - if(i){ - //Dont include the first point of the profile in the average - cuv += mVertices[i].mTexCoord; - mCenter += mVertices[i].mPosition = mesh[i + offset].mPos; + mVertices[i].mPosition = mesh[i + offset].mPos; + + if (i == 0) + { + min = max = mVertices[i].mPosition; + min_uv = max_uv = mVertices[i].mTexCoord; + } + else + { + update_min_max(min,max, mVertices[i].mPosition); + update_min_max(min_uv, max_uv, mVertices[i].mTexCoord); } - else mVertices[i].mPosition = mesh[i + offset].mPos; - //mVertices[i].mNormal = normal; } - mCenter /= (F32)(num_vertices-1); - cuv /= (F32)(num_vertices-1); + mCenter = (min+max)*0.5f; + cuv = (min_uv + max_uv)*0.5f; LLVector3 binormal = calc_binormal_from_triangle( mCenter, cuv, @@ -4215,13 +4222,11 @@ BOOL LLVolumeFace::createCap() return TRUE; } - BOOL LLVolumeFace::createSide() { BOOL flat = mTypeMask & FLAT_MASK; S32 num_vertices, num_indices; - const std::vector<LLVolume::Point>& mesh = mVolumep->getMesh(); const std::vector<LLVector3>& profile = mVolumep->getProfile().mProfile; const std::vector<LLPath::PathPt>& path_data = mVolumep->getPath().mPath; @@ -4237,6 +4242,9 @@ BOOL LLVolumeFace::createSide() vector_append(mIndices,num_indices); vector_append(mEdge, num_indices); + LLVector3& face_min = mExtents[0]; + LLVector3& face_max = mExtents[1]; + mCenter.clearVec(); S32 begin_stex = llfloor( profile[mBeginS].mV[2] ); @@ -4284,17 +4292,26 @@ BOOL LLVolumeFace::createSide() i = mBeginS + s + max_s*t; } - mCenter += mVertices[cur_vertex].mPosition = mesh[i].mPos; + mVertices[cur_vertex].mPosition = mesh[i].mPos; mVertices[cur_vertex].mTexCoord = LLVector2(ss,tt); mVertices[cur_vertex].mNormal = LLVector3(0,0,0); mVertices[cur_vertex].mBinormal = LLVector3(0,0,0); + if (cur_vertex == 0) + { + face_min = face_max = mesh[i].mPos; + } + else + { + update_min_max(face_min, face_max, mesh[i].mPos); + } + cur_vertex++; if ((mTypeMask & INNER_MASK) && (mTypeMask & FLAT_MASK) && mNumS > 2 && s > 0) { - mCenter += mVertices[cur_vertex].mPosition = mesh[i].mPos; + mVertices[cur_vertex].mPosition = mesh[i].mPos; mVertices[cur_vertex].mTexCoord = LLVector2(ss,tt); mVertices[cur_vertex].mNormal = LLVector3(0,0,0); @@ -4316,15 +4333,19 @@ BOOL LLVolumeFace::createSide() i = mBeginS + s + max_s*t; ss = profile[mBeginS + s].mV[2] - begin_stex; - mCenter += mVertices[cur_vertex].mPosition = mesh[i].mPos; + mVertices[cur_vertex].mPosition = mesh[i].mPos; mVertices[cur_vertex].mTexCoord = LLVector2(ss,tt); mVertices[cur_vertex].mNormal = LLVector3(0,0,0); mVertices[cur_vertex].mBinormal = LLVector3(0,0,0); + + update_min_max(face_min,face_max,mesh[i].mPos); + cur_vertex++; } } - mCenter /= (F32)num_vertices; + + mCenter = (face_min + face_max) * 0.5f; S32 cur_index = 0; S32 cur_edge = 0; @@ -4448,32 +4469,14 @@ BOOL LLVolumeFace::createSide() } } - //this loop would LOVE OpenMP - LLVector3 min = mVolumep->mBounds[0] - mVolumep->mBounds[1]; - LLVector3 max = mVolumep->mBounds[0] + mVolumep->mBounds[1]; - - if (min == max && min == LLVector3(512,512,512)) + //normalize normals and binormals here so the meshes that reference + //this volume data don't have to + for (U32 i = 0; i < mVertices.size(); i++) { - min = max = mVertices[0].mPosition; - } - - for (U32 i = 0; i < mVertices.size(); i++) { mVertices[i].mNormal.normVec(); mVertices[i].mBinormal.normVec(); - - for (U32 j = 0; j < 3; j++) { - if (mVertices[i].mPosition.mV[j] > max.mV[j]) { - max.mV[j] = mVertices[i].mPosition.mV[j]; - } - if (mVertices[i].mPosition.mV[j] < min.mV[j]) { - min.mV[j] = mVertices[i].mPosition.mV[j]; - } - } } - mVolumep->mBounds[0] = (min + max) * 0.5f; //center - mVolumep->mBounds[1] = (max - min) * 0.5f; //half-height - return TRUE; } @@ -4572,7 +4575,7 @@ LLVector3 calc_binormal_from_triangle( -r0.mV[VZ] / r0.mV[VX], -r1.mV[VZ] / r1.mV[VX], -r2.mV[VZ] / r2.mV[VX]); - //binormal.normVec(); + // binormal.normVec(); return binormal; } else diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h index cf9ae00f21..97aeeb9589 100644 --- a/indra/llmath/llvolume.h +++ b/indra/llmath/llvolume.h @@ -756,6 +756,8 @@ public: S32 mNumS; S32 mNumT; + LLVector3 mExtents[2]; //minimum and maximum point of face + std::vector<VertexData> mVertices; std::vector<S32> mIndices; std::vector<S32> mEdge; @@ -849,7 +851,6 @@ public: const LLVolumeFace &getVolumeFace(const S32 f) const {return mVolumeFaces[f];} // DO NOT DELETE VOLUME WHILE USING THIS REFERENCE, OR HOLD A POINTER TO THIS VOLUMEFACE U32 mFaceMask; // bit array of which faces exist in this volume - LLVector3 mBounds[2]; // bounding box (center, half-height) LLVector3 mLODScaleBias; // vector for biasing LOD based on scale protected: diff --git a/indra/llmath/m3math.cpp b/indra/llmath/m3math.cpp index 523acb4dcf..6483f2adbe 100644 --- a/indra/llmath/m3math.cpp +++ b/indra/llmath/m3math.cpp @@ -33,14 +33,14 @@ LLMatrix3::LLMatrix3(const LLQuaternion &q) { - *this = q.getMatrix3(); + setRot(q); } LLMatrix3::LLMatrix3(const F32 angle, const LLVector3 &vec) { LLQuaternion quat(angle, vec); - *this = setRot(quat); + setRot(quat); } LLMatrix3::LLMatrix3(const F32 angle, const LLVector3d &vec) @@ -48,60 +48,25 @@ LLMatrix3::LLMatrix3(const F32 angle, const LLVector3d &vec) LLVector3 vec_f; vec_f.setVec(vec); LLQuaternion quat(angle, vec_f); - *this = setRot(quat); + setRot(quat); } LLMatrix3::LLMatrix3(const F32 angle, const LLVector4 &vec) { LLQuaternion quat(angle, vec); - *this = setRot(quat); + setRot(quat); } LLMatrix3::LLMatrix3(const F32 angle, const F32 x, const F32 y, const F32 z) { LLVector3 vec(x, y, z); LLQuaternion quat(angle, vec); - *this = setRot(quat); + setRot(quat); } LLMatrix3::LLMatrix3(const F32 roll, const F32 pitch, const F32 yaw) { - // Rotates RH about x-axis by 'roll' then - // rotates RH about the old y-axis by 'pitch' then - // rotates RH about the original z-axis by 'yaw'. - // . - // /|\ yaw axis - // | __. - // ._ ___| /| pitch axis - // _||\ \\ |-. / - // \|| \_______\_|__\_/_______ - // | _ _ o o o_o_o_o o /_\_ ________\ roll axis - // // /_______/ /__________> / - // /_,-' // / - // /__,-' - - F32 cx, sx, cy, sy, cz, sz; - F32 cxsy, sxsy; - - cx = (F32)cos(roll); //A - sx = (F32)sin(roll); //B - cy = (F32)cos(pitch); //C - sy = (F32)sin(pitch); //D - cz = (F32)cos(yaw); //E - sz = (F32)sin(yaw); //F - - cxsy = cx * sy; //AD - sxsy = sx * sy; //BD - - mMatrix[0][0] = cy * cz; - mMatrix[1][0] = -cy * sz; - mMatrix[2][0] = sy; - mMatrix[0][1] = sxsy * cz + cx * sz; - mMatrix[1][1] = -sxsy * sz + cx * cz; - mMatrix[2][1] = -sx * cy; - mMatrix[0][2] = -cxsy * cz + sx * sz; - mMatrix[1][2] = cxsy * sz + sx * cz; - mMatrix[2][2] = cx * cy; + setRot(roll,pitch,yaw); } // From Matrix and Quaternion FAQ @@ -288,34 +253,64 @@ LLQuaternion LLMatrix3::quaternion() const // These functions take Rotation arguments const LLMatrix3& LLMatrix3::setRot(const F32 angle, const F32 x, const F32 y, const F32 z) { - LLMatrix3 mat(angle, x, y, z); - *this = mat; + setRot(LLQuaternion(angle,x,y,z)); return *this; } const LLMatrix3& LLMatrix3::setRot(const F32 angle, const LLVector3 &vec) { - LLMatrix3 mat(angle, vec); - *this = mat; + setRot(LLQuaternion(angle, vec)); return *this; } const LLMatrix3& LLMatrix3::setRot(const F32 roll, const F32 pitch, const F32 yaw) { - LLMatrix3 mat(roll, pitch, yaw); - *this = mat; + // Rotates RH about x-axis by 'roll' then + // rotates RH about the old y-axis by 'pitch' then + // rotates RH about the original z-axis by 'yaw'. + // . + // /|\ yaw axis + // | __. + // ._ ___| /| pitch axis + // _||\ \\ |-. / + // \|| \_______\_|__\_/_______ + // | _ _ o o o_o_o_o o /_\_ ________\ roll axis + // // /_______/ /__________> / + // /_,-' // / + // /__,-' + + F32 cx, sx, cy, sy, cz, sz; + F32 cxsy, sxsy; + + cx = (F32)cos(roll); //A + sx = (F32)sin(roll); //B + cy = (F32)cos(pitch); //C + sy = (F32)sin(pitch); //D + cz = (F32)cos(yaw); //E + sz = (F32)sin(yaw); //F + + cxsy = cx * sy; //AD + sxsy = sx * sy; //BD + + mMatrix[0][0] = cy * cz; + mMatrix[1][0] = -cy * sz; + mMatrix[2][0] = sy; + mMatrix[0][1] = sxsy * cz + cx * sz; + mMatrix[1][1] = -sxsy * sz + cx * cz; + mMatrix[2][1] = -sx * cy; + mMatrix[0][2] = -cxsy * cz + sx * sz; + mMatrix[1][2] = cxsy * sz + sx * cz; + mMatrix[2][2] = cx * cy; return *this; } const LLMatrix3& LLMatrix3::setRot(const LLQuaternion &q) { - LLMatrix3 mat(q); - *this = mat; + *this = q.getMatrix3(); return *this; } - const LLMatrix3& LLMatrix3::setRows(const LLVector3 &fwd, const LLVector3 &left, const LLVector3 &up) { mMatrix[0][0] = fwd.mV[0]; diff --git a/indra/llmath/m3math.h b/indra/llmath/m3math.h index ac93ed86fb..c3798fca73 100644 --- a/indra/llmath/m3math.h +++ b/indra/llmath/m3math.h @@ -32,9 +32,6 @@ class LLQuaternion; static const U32 NUM_VALUES_IN_MAT3 = 3; -#if LL_WINDOWS -__declspec( align(16) ) -#endif class LLMatrix3 { public: @@ -119,11 +116,7 @@ class LLMatrix3 friend const LLMatrix3& operator*=(LLMatrix3 &a, const LLMatrix3 &b); // Return a * b friend std::ostream& operator<<(std::ostream& s, const LLMatrix3 &a); // Stream a -} -#if LL_DARWIN -__attribute__ ((aligned (16))) -#endif -; +}; inline LLMatrix3::LLMatrix3(void) { diff --git a/indra/llmath/m4math.h b/indra/llmath/m4math.h index 4f26d875ff..69463d7718 100644 --- a/indra/llmath/m4math.h +++ b/indra/llmath/m4math.h @@ -73,9 +73,6 @@ class LLQuaternion; static const U32 NUM_VALUES_IN_MAT4 = 4; -#if LL_WINDOWS -__declspec(align(16)) -#endif class LLMatrix4 { public: @@ -218,11 +215,7 @@ public: friend const LLMatrix4& operator*=(LLMatrix4 &a, const F32 &b); // Return a * b friend std::ostream& operator<<(std::ostream& s, const LLMatrix4 &a); // Stream a -} -#if LL_DARWIN -__attribute__ ((aligned (16))) -#endif -; +}; inline LLMatrix4::LLMatrix4() diff --git a/indra/llmath/v2math.h b/indra/llmath/v2math.h index c94333e2a9..863318551e 100644 --- a/indra/llmath/v2math.h +++ b/indra/llmath/v2math.h @@ -298,6 +298,21 @@ inline LLVector2 operator-(const LLVector2 &a) return LLVector2( -a.mV[0], -a.mV[1] ); } +inline void update_min_max(LLVector2& min, LLVector2& max, const LLVector2& pos) +{ + for (U32 i = 0; i < 2; i++) + { + if (min.mV[i] > pos.mV[i]) + { + min.mV[i] = pos.mV[i]; + } + if (max.mV[i] < pos.mV[i]) + { + max.mV[i] = pos.mV[i]; + } + } +} + inline std::ostream& operator<<(std::ostream& s, const LLVector2 &a) { s << "{ " << a.mV[VX] << ", " << a.mV[VY] << " }"; diff --git a/indra/llmath/v3math.cpp b/indra/llmath/v3math.cpp index 9e6084565e..c68e72bb97 100644 --- a/indra/llmath/v3math.cpp +++ b/indra/llmath/v3math.cpp @@ -118,7 +118,7 @@ const LLVector3& LLVector3::rotVec(F32 angle, const LLVector3 &vec) { if ( !vec.isExactlyZero() && angle ) { - *this = *this * LLMatrix3(angle, vec); + *this = *this * LLQuaternion(angle, vec); } return *this; } @@ -128,7 +128,7 @@ const LLVector3& LLVector3::rotVec(F32 angle, F32 x, F32 y, F32 z) LLVector3 vec(x, y, z); if ( !vec.isExactlyZero() && angle ) { - *this = *this * LLMatrix3(angle, vec); + *this = *this * LLQuaternion(angle, vec); } return *this; } diff --git a/indra/llmath/v3math.h b/indra/llmath/v3math.h index 72372c07e9..f787fa2ac1 100644 --- a/indra/llmath/v3math.h +++ b/indra/llmath/v3math.h @@ -396,6 +396,20 @@ inline BOOL LLVector3::isNull() const return FALSE; } +inline void update_min_max(LLVector3& min, LLVector3& max, const LLVector3& pos) +{ + for (U32 i = 0; i < 3; i++) + { + if (min.mV[i] > pos.mV[i]) + { + min.mV[i] = pos.mV[i]; + } + if (max.mV[i] < pos.mV[i]) + { + max.mV[i] = pos.mV[i]; + } + } +} inline F32 angle_between(const LLVector3& a, const LLVector3& b) { diff --git a/indra/llmath/v4math.h b/indra/llmath/v4math.h index abdc66e0b1..e9b8d5b71f 100644 --- a/indra/llmath/v4math.h +++ b/indra/llmath/v4math.h @@ -21,10 +21,6 @@ class LLQuaternion; static const U32 LENGTHOFVECTOR4 = 4; -#if LL_WINDOWS -__declspec( align(16) ) -#endif - class LLVector4 { public: @@ -95,12 +91,7 @@ class LLVector4 friend const LLVector4& operator/=(LLVector4 &a, F32 k); // Return a divided by scaler k friend LLVector4 operator-(const LLVector4 &a); // Return vector -a -} -#if LL_DARWIN -__attribute__ ((aligned (16))) -#endif -; - +}; // Non-member functions F32 angle_between(const LLVector4 &a, const LLVector4 &b); // Returns angle (radians) between a and b diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp new file mode 100644 index 0000000000..886697ed41 --- /dev/null +++ b/indra/llmessage/llcurl.cpp @@ -0,0 +1,343 @@ +/* + * llcurl.cpp + * MacTester + * + * Created by Zero Linden on 10/15/06. + * Copyright 2006 __MyCompanyName__. All rights reserved. + * + */ + +#include "llcurl.h" + +#include <iomanip> + +#include "llsdserialize.h" + +////////////////////////////////////////////////////////////////////////////// +/* + The trick to getting curl to do keep-alives is to reuse the + same easy handle for the requests. It appears that curl + keeps a pool of connections alive for each easy handle, but + doesn't share them between easy handles. Therefore it is + important to keep a pool of easy handles and reuse them, + rather than create and destroy them with each request. This + code does this. + + Furthermore, it would behoove us to keep track of which + hosts an easy handle was used for and pick an easy handle + that matches the next request. This code does not current + do this. + */ + +using namespace std; + +LLCurl::Responder::Responder() + : mReferenceCount(0) +{ +} +LLCurl::Responder::~Responder() +{ +} + +// virtual +void LLCurl::Responder::error(U32 status, const std::stringstream& content) +{ + llinfos << "LLCurl::Responder::error " << status << ": " << content.str() << llendl; +} + +// virtual +void LLCurl::Responder::result(const std::stringstream& content) +{ +} + +// virtual +void LLCurl::Responder::completed(U32 status, const std::stringstream& content) +{ + if (200 <= status && status < 300) + { + result(content); + } + else + { + error(status, content); + } +} + + +namespace boost +{ + void intrusive_ptr_add_ref(LLCurl::Responder* p) + { + ++p->mReferenceCount; + } + + void intrusive_ptr_release(LLCurl::Responder* p) + { + if(0 == --p->mReferenceCount) + { + delete p; + } + } +}; + +////////////////////////////////////////////////////////////////////////////// + +size_t +curlOutputCallback(void* data, size_t size, size_t nmemb, void* user_data) +{ + stringstream& output = *(stringstream*)user_data; + + size_t n = size * nmemb; + output.write((const char*)data, n); + if (!((istream&)output).good()) { + std::cerr << "WHAT!?!?!? istream side bad" << std::endl; + } + if (!((ostream&)output).good()) { + std::cerr << "WHAT!?!?!? ostream side bad" << std::endl; + } + + return n; +} + +// Only used if request contained a body (post or put), Not currently implemented. +// size_t +// curlRequestCallback(void* data, size_t size, size_t nmemb, void* user_data) +// { +// stringstream& request = *(stringstream*)user_data; + +// size_t n = size * nmemb; +// request.read((char*)data, n); +// return request.gcount(); +// } + + + + + +LLCurl::Easy::Easy() +{ + mHeaders = 0; + mHeaders = curl_slist_append(mHeaders, "Connection: keep-alive"); + mHeaders = curl_slist_append(mHeaders, "Keep-alive: 300"); + mHeaders = curl_slist_append(mHeaders, "Content-Type: application/xml"); + // FIXME: shouldn't be there for GET/DELETE + // FIXME: should have ACCEPT headers + + mHandle = curl_easy_init(); +} + +LLCurl::Easy::~Easy() +{ + curl_easy_cleanup(mHandle); + curl_slist_free_all(mHeaders); +} + +void +LLCurl::Easy::get(const string& url, ResponderPtr responder) +{ + prep(url, responder); + curl_easy_setopt(mHandle, CURLOPT_HTTPGET, 1); +} + +void +LLCurl::Easy::getByteRange(const string& url, S32 offset, S32 length, ResponderPtr responder) +{ + mRange = llformat("Range: bytes=%d-%d", offset,offset+length-1); + mHeaders = curl_slist_append(mHeaders, mRange.c_str()); + prep(url, responder); + curl_easy_setopt(mHandle, CURLOPT_HTTPGET, 1); +} + +void +LLCurl::Easy::perform() +{ + report(curl_easy_perform(mHandle)); +} + +void +LLCurl::Easy::prep(const std::string& url, ResponderPtr responder) +{ +#if !LL_DARWIN + curl_easy_reset(mHandle); // SJB: doesn't exisit on OSX 10.3.9 +#else + // SJB: equivalent? fast? + curl_easy_cleanup(mHandle); + mHandle = curl_easy_init(); +#endif + + curl_easy_setopt(mHandle, CURLOPT_PRIVATE, this); + +// curl_easy_setopt(mHandle, CURLOPT_VERBOSE, 1); // usefull for debugging + curl_easy_setopt(mHandle, CURLOPT_NOSIGNAL, 1); + curl_easy_setopt(mHandle, CURLOPT_WRITEFUNCTION, &curlOutputCallback); + curl_easy_setopt(mHandle, CURLOPT_WRITEDATA, &mOutput); +#if 1 // For debug + curl_easy_setopt(mHandle, CURLOPT_HEADERFUNCTION, &curlOutputCallback); + curl_easy_setopt(mHandle, CURLOPT_HEADERDATA, &mHeaderOutput); +#endif + curl_easy_setopt(mHandle, CURLOPT_ERRORBUFFER, &mErrorBuffer); + curl_easy_setopt(mHandle, CURLOPT_ENCODING, ""); + curl_easy_setopt(mHandle, CURLOPT_SSL_VERIFYPEER, false); + curl_easy_setopt(mHandle, CURLOPT_HTTPHEADER, mHeaders); + + mOutput.str(""); + if (!((istream&)mOutput).good()) { + std::cerr << "WHAT!?!?!? istream side bad" << std::endl; + } + if (!((ostream&)mOutput).good()) { + std::cerr << "WHAT!?!?!? ostream side bad" << std::endl; + } + + mURL = url; + curl_easy_setopt(mHandle, CURLOPT_URL, mURL.c_str()); + + mResponder = responder; +} + +void +LLCurl::Easy::report(CURLcode code) +{ + if (!mResponder) return; + + long responseCode; + + if (code == CURLE_OK) + { + curl_easy_getinfo(mHandle, CURLINFO_RESPONSE_CODE, &responseCode); + } + else + { + responseCode = 499; + } + + mResponder->completed(responseCode, mOutput); + mResponder = NULL; +} + + + + + + +LLCurl::Multi::Multi() +{ + mHandle = curl_multi_init(); +} + +LLCurl::Multi::~Multi() +{ + // FIXME: should clean up excess handles in mFreeEasy + curl_multi_cleanup(mHandle); +} + + +void +LLCurl::Multi::get(const std::string& url, ResponderPtr responder) +{ + LLCurl::Easy* easy = easyAlloc(); + easy->get(url, responder); + curl_multi_add_handle(mHandle, easy->mHandle); +} + +void +LLCurl::Multi::getByteRange(const std::string& url, S32 offset, S32 length, ResponderPtr responder) +{ + LLCurl::Easy* easy = easyAlloc(); + easy->getByteRange(url, offset, length, responder); + curl_multi_add_handle(mHandle, easy->mHandle); +} + +void +LLCurl::Multi::process() +{ + int count; + for (int call_count = 0; call_count < 5; call_count += 1) + { + if (CURLM_CALL_MULTI_PERFORM != curl_multi_perform(mHandle, &count)) + { + break; + } + } + + CURLMsg* msg; + int msgs_in_queue; + while ((msg = curl_multi_info_read(mHandle, &msgs_in_queue))) + { + if (msg->msg != CURLMSG_DONE) continue; + Easy* easy = 0; + curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, &easy); + if (!easy) continue; + easy->report(msg->data.result); + + curl_multi_remove_handle(mHandle, easy->mHandle); + easyFree(easy); + } +} + + + +LLCurl::Easy* +LLCurl::Multi::easyAlloc() +{ + Easy* easy = 0; + + if (mFreeEasy.empty()) + { + easy = new Easy(); + } + else + { + easy = mFreeEasy.back(); + mFreeEasy.pop_back(); + } + + return easy; +} + +void +LLCurl::Multi::easyFree(Easy* easy) +{ + if (mFreeEasy.size() < 5) + { + mFreeEasy.push_back(easy); + } + else + { + delete easy; + } +} + + + +namespace +{ + static LLCurl::Multi* sMainMulti = 0; + + LLCurl::Multi* + mainMulti() + { + if (!sMainMulti) { + sMainMulti = new LLCurl::Multi(); + } + return sMainMulti; + } +} + +void +LLCurl::get(const std::string& url, ResponderPtr responder) +{ + mainMulti()->get(url, responder); +} + +void +LLCurl::getByteRange(const std::string& url, S32 offset, S32 length, ResponderPtr responder) +{ + mainMulti()->getByteRange(url, offset, length, responder); +} + +void +LLCurl::process() +{ + mainMulti()->process(); +} + diff --git a/indra/llmessage/llcurl.h b/indra/llmessage/llcurl.h new file mode 100644 index 0000000000..4f1b5e6031 --- /dev/null +++ b/indra/llmessage/llcurl.h @@ -0,0 +1,118 @@ +/* + * llcurl.h + * MacTester + * + * Created by Zero Linden on 10/15/06. + * Copyright 2006 __MyCompanyName__. All rights reserved. + * + */ + +#ifndef LL_LLCURL_H +#define LL_LLCURL_H + +#include "linden_common.h" + +#include <sstream> +#include <string> +#include <vector> + +#include <boost/intrusive_ptr.hpp> +#include <curl/curl.h> + +// #include "llhttpclient.h" + +class LLCurl +{ +public: + class Multi; + + class Responder + { + public: + Responder(); + virtual ~Responder(); + + virtual void error(U32 status, const std::stringstream& content); // called with bad status codes + + virtual void result(const std::stringstream& content); + + virtual void completed(U32 status, const std::stringstream& content); + /**< The default implemetnation calls + either: + * result(), or + * error() + */ + + public: /* but not really -- don't touch this */ + U32 mReferenceCount; + }; + typedef boost::intrusive_ptr<Responder> ResponderPtr; + + class Easy + { + public: + Easy(); + ~Easy(); + + void get(const std::string& url, ResponderPtr); + void getByteRange(const std::string& url, S32 offset, S32 length, ResponderPtr); + + void perform(); + + private: + void prep(const std::string& url, ResponderPtr); + void report(CURLcode); + + CURL* mHandle; + struct curl_slist* mHeaders; + + std::string mURL; + std::string mRange; + std::stringstream mRequest; + + std::stringstream mOutput; + char mErrorBuffer[CURL_ERROR_SIZE]; + + std::stringstream mHeaderOutput; // Debug + + ResponderPtr mResponder; + + friend class Multi; + }; + + + class Multi + { + public: + Multi(); + ~Multi(); + + void get(const std::string& url, ResponderPtr); + void getByteRange(const std::string& url, S32 offset, S32 length, ResponderPtr); + + void process(); + + private: + Easy* easyAlloc(); + void easyFree(Easy*); + + CURLM* mHandle; + + typedef std::vector<Easy*> EasyList; + EasyList mFreeEasy; + }; + + + static void get(const std::string& url, ResponderPtr); + static void getByteRange(const std::string& url, S32 offset, S32 length, ResponderPtr responder); + + static void process(); +}; + +namespace boost +{ + void intrusive_ptr_add_ref(LLCurl::Responder* p); + void intrusive_ptr_release(LLCurl::Responder* p); +}; + +#endif // LL_LLCURL_H diff --git a/indra/llmessage/llpartdata.cpp b/indra/llmessage/llpartdata.cpp index 4ce7bc1fcd..6fc2af2cb2 100644 --- a/indra/llmessage/llpartdata.cpp +++ b/indra/llmessage/llpartdata.cpp @@ -212,6 +212,20 @@ BOOL LLPartSysData::unpack(LLDataPacker &dp) return TRUE; } +std::ostream& operator<<(std::ostream& s, const LLPartSysData &data) +{ + s << "Flags: " << std::hex << data.mFlags; + s << " Pattern: " << std::hex << (U32) data.mPattern << "\n"; + s << "Age: [" << data.mStartAge << ", " << data.mMaxAge << "]\n"; + s << "Angle: [" << data.mInnerAngle << ", " << data.mOuterAngle << "]\n"; + s << "Burst Rate: " << data.mBurstRate << "\n"; + s << "Burst Radius: " << data.mBurstRadius << "\n"; + s << "Burst Speed: [" << data.mBurstSpeedMin << ", " << data.mBurstSpeedMax << "]\n"; + s << "Burst Part Count: " << std::hex << (U32) data.mBurstPartCount << "\n"; + s << "Angular Velocity: " << data.mAngularVelocity << "\n"; + s << "Accel: " << data.mPartAccel; + return s; +} BOOL LLPartSysData::isNullPS(const S32 block_num) { diff --git a/indra/llmessage/llpartdata.h b/indra/llmessage/llpartdata.h index ba3bdaf9b6..662d635a08 100644 --- a/indra/llmessage/llpartdata.h +++ b/indra/llmessage/llpartdata.h @@ -167,6 +167,9 @@ public: // a combination of multiple parameters, we // need to clamp it using a separate method instead of an accessor. void clampSourceParticleRate(); + + friend std::ostream& operator<<(std::ostream& s, const LLPartSysData &data); // Stream a + public: // Public because I'm lazy.... diff --git a/indra/llmessage/llpumpio.cpp b/indra/llmessage/llpumpio.cpp index 5abc63fad0..320719072c 100644 --- a/indra/llmessage/llpumpio.cpp +++ b/indra/llmessage/llpumpio.cpp @@ -868,7 +868,7 @@ void LLPumpIO::processChain(LLChainInfo& chain) PUMP_DEBUG; if(LLIOPipe::isError(status)) { - llinfos << "Pump generated pipe error: '" + llinfos << "Pump generated pipe err: '" #if LL_DEBUG_PIPE_TYPE_IN_PUMP << typeid(*((*it).mPipe)).name() << "':'" #endif diff --git a/indra/llmessage/lltransfermanager.cpp b/indra/llmessage/lltransfermanager.cpp index 4eea7418af..bddd79367a 100644 --- a/indra/llmessage/lltransfermanager.cpp +++ b/indra/llmessage/lltransfermanager.cpp @@ -335,7 +335,7 @@ void LLTransferManager::processTransferInfo(LLMessageSystem *msgp, void **) { // Perhaps this stuff should be inside a method in LLTransferPacket? // I'm too lazy to do it now, though. - llinfos << "Playing back delayed packet " << packet_id << llendl; +// llinfos << "Playing back delayed packet " << packet_id << llendl; LLTransferPacket *packetp = ttp->mDelayedPacketMap[packet_id]; // This is somewhat inefficient, but avoids us having to duplicate @@ -455,6 +455,8 @@ void LLTransferManager::processTransferPacket(LLMessageSystem *msgp, void **) ttcp->deleteTransfer(ttp); return; } +#if 0 + // Spammy! const S32 LL_TRANSFER_WARN_GAP = 10; if(!ttp->gotInfo()) { @@ -468,6 +470,7 @@ void LLTransferManager::processTransferPacket(LLMessageSystem *msgp, void **) << " from " << msgp->getSender() << ", got " << packet_id << " expecting " << ttp->getNextPacketID() << llendl; } +#endif return; } @@ -508,7 +511,7 @@ void LLTransferManager::processTransferPacket(LLMessageSystem *msgp, void **) { // Perhaps this stuff should be inside a method in LLTransferPacket? // I'm too lazy to do it now, though. - llinfos << "Playing back delayed packet " << packet_id << llendl; +// llinfos << "Playing back delayed packet " << packet_id << llendl; LLTransferPacket *packetp = ttp->mDelayedPacketMap[packet_id]; // This is somewhat inefficient, but avoids us having to duplicate diff --git a/indra/llmessage/lltransfertargetvfile.cpp b/indra/llmessage/lltransfertargetvfile.cpp index b8c138886a..6714185d3f 100644 --- a/indra/llmessage/lltransfertargetvfile.cpp +++ b/indra/llmessage/lltransfertargetvfile.cpp @@ -15,33 +15,8 @@ #include "llvfile.h" //static -std::list<LLTransferTargetParamsVFile*> LLTransferTargetVFile::sCallbackQueue; - -//static void LLTransferTargetVFile::updateQueue(bool shutdown) { - for(std::list<LLTransferTargetParamsVFile*>::iterator iter = sCallbackQueue.begin(); - iter != sCallbackQueue.end(); ) - { - std::list<LLTransferTargetParamsVFile*>::iterator curiter = iter++; - LLTransferTargetParamsVFile* params = *curiter; - LLVFSThread::status_t s = LLVFile::getVFSThread()->getRequestStatus(params->mHandle); - if (s == LLVFSThread::STATUS_COMPLETE || s == LLVFSThread::STATUS_EXPIRED) - { - params->mCompleteCallback( - params->mErrCode, - params->getAssetID(), - params->getAssetType(), - params->mUserDatap); - delete params; - iter = sCallbackQueue.erase(curiter); - } - else if (shutdown) - { - delete params; - iter = sCallbackQueue.erase(curiter); - } - } } @@ -50,8 +25,7 @@ LLTransferTargetParamsVFile::LLTransferTargetParamsVFile() : mAssetType(LLAssetType::AT_NONE), mCompleteCallback(NULL), mUserDatap(NULL), - mErrCode(0), - mHandle(LLVFSThread::nullHandle()) + mErrCode(0) { } @@ -166,7 +140,6 @@ void LLTransferTargetVFile::completionCallback(const LLTSCode status) llwarns << "Aborting vfile transfer after asset storage shut down!" << llendl; return; } - LLVFSThread::handle_t handle = LLVFSThread::nullHandle(); // Still need to gracefully handle error conditions. S32 err_code = 0; @@ -175,11 +148,11 @@ void LLTransferTargetVFile::completionCallback(const LLTSCode status) case LLTS_DONE: if (!mNeedsCreate) { - handle = LLVFile::getVFSThread()->rename( - gAssetStorage->mVFS, - mTempID, mParams.getAssetType(), - mParams.getAssetID(), mParams.getAssetType(), - LLVFSThread::AUTO_DELETE); + LLVFile file(gAssetStorage->mVFS, mTempID, mParams.getAssetType(), LLVFile::WRITE); + if (!file.rename(mParams.getAssetID(), mParams.getAssetType())) + { + llerrs << "LLTransferTargetVFile: rename failed" << llendl; + } } err_code = LL_ERR_NOERR; lldebugs << "LLTransferTargetVFile::completionCallback for " @@ -219,20 +192,9 @@ void LLTransferTargetVFile::completionCallback(const LLTSCode status) } if (mParams.mCompleteCallback) { - if (handle != LLVFSThread::nullHandle()) - { - LLTransferTargetParamsVFile* params = new LLTransferTargetParamsVFile(mParams); - params->mErrCode = err_code; - params->mHandle = handle; - sCallbackQueue.push_back(params); - } - else - { - mParams.mCompleteCallback( - err_code, - mParams.getAssetID(), - mParams.getAssetType(), - mParams.mUserDatap); - } + mParams.mCompleteCallback(err_code, + mParams.getAssetID(), + mParams.getAssetType(), + mParams.mUserDatap); } } diff --git a/indra/llmessage/lltransfertargetvfile.h b/indra/llmessage/lltransfertargetvfile.h index 57eaeca378..e9d5fa0c00 100644 --- a/indra/llmessage/lltransfertargetvfile.h +++ b/indra/llmessage/lltransfertargetvfile.h @@ -71,8 +71,6 @@ protected: BOOL mNeedsCreate; LLUUID mTempID; - - static std::list<LLTransferTargetParamsVFile*> sCallbackQueue; }; #endif // LL_LLTRANSFERTARGETFILE_H diff --git a/indra/llmessage/message.h b/indra/llmessage/message.h index 48d950e377..3f9dfa08d6 100644 --- a/indra/llmessage/message.h +++ b/indra/llmessage/message.h @@ -421,6 +421,7 @@ public: void addStringFast( const char* varname, const std::string& s); // typed, checks storage space void addString( const char* varname, const std::string& s); // typed, checks storage space + TPACKETID getCurrentRecvPacketID() { return mCurrentRecvPacketID; } S32 getCurrentSendTotal() const { return mCurrentSendTotal; } // This method checks for current send total and returns true if diff --git a/indra/llprimitive/llvolumemessage.cpp b/indra/llprimitive/llvolumemessage.cpp index d2f1e12526..a43aa19cab 100644 --- a/indra/llprimitive/llvolumemessage.cpp +++ b/indra/llprimitive/llvolumemessage.cpp @@ -429,41 +429,36 @@ bool LLVolumeMessage::unpackPathParams(LLPathParams* params, LLDataPacker &dp) // static bool LLVolumeMessage::constrainVolumeParams(LLVolumeParams& params) { - bool ok = true; + U32 bad = 0; // This is called immediately after an unpack. feed the raw data // through the checked setters to constraint it to a valid set of // volume params. - ok &= params.setType( - params.getProfileParams().getCurveType(), - params.getPathParams().getCurveType()); - ok &= params.setBeginAndEndS( - params.getProfileParams().getBegin(), - params.getProfileParams().getEnd()); - ok &= params.setBeginAndEndT( - params.getPathParams().getBegin(), - params.getPathParams().getEnd()); - ok &= params.setHollow(params.getProfileParams().getHollow()); - ok &= params.setTwistBegin(params.getPathParams().getTwistBegin()); - ok &= params.setTwistEnd(params.getPathParams().getTwistEnd()); - ok &= params.setRatio( - params.getPathParams().getScaleX(), - params.getPathParams().getScaleY()); - ok &= params.setShear( - params.getPathParams().getShearX(), - params.getPathParams().getShearY()); - ok &= params.setTaper( - params.getPathParams().getTaperX(), - params.getPathParams().getTaperY()); - ok &= params.setRevolutions(params.getPathParams().getRevolutions()); - ok &= params.setRadiusOffset(params.getPathParams().getRadiusOffset()); - ok &= params.setSkew(params.getPathParams().getSkew()); - if(!ok) + bad |= params.setType(params.getProfileParams().getCurveType(), + params.getPathParams().getCurveType()) ? 0 : 1; + bad |= params.setBeginAndEndS(params.getProfileParams().getBegin(), + params.getProfileParams().getEnd()) ? 0 : 2; + bad |= params.setBeginAndEndT(params.getPathParams().getBegin(), + params.getPathParams().getEnd()) ? 0 : 4; + bad |= params.setHollow(params.getProfileParams().getHollow()) ? 0 : 8; + bad |= params.setTwistBegin(params.getPathParams().getTwistBegin()) ? 0 : 0x10; + bad |= params.setTwistEnd(params.getPathParams().getTwistEnd()) ? 0 : 0x20; + bad |= params.setRatio(params.getPathParams().getScaleX(), + params.getPathParams().getScaleY()) ? 0 : 0x40; + bad |= params.setShear(params.getPathParams().getShearX(), + params.getPathParams().getShearY()) ? 0 : 0x80; + bad |= params.setTaper(params.getPathParams().getTaperX(), + params.getPathParams().getTaperY()) ? 0 : 0x100; + bad |= params.setRevolutions(params.getPathParams().getRevolutions()) ? 0 : 0x200; + bad |= params.setRadiusOffset(params.getPathParams().getRadiusOffset()) ? 0 : 0x400; + bad |= params.setSkew(params.getPathParams().getSkew()) ? 0 : 0x800; + if(bad) { llwarns << "LLVolumeMessage::constrainVolumeParams() - " - << "forced to constrain incoming volume params." << llendl; + << "forced to constrain incoming volume params: " + << llformat("0x%04x",bad) << llendl; } - return ok; + return bad ? false : true; } bool LLVolumeMessage::packVolumeParams(const LLVolumeParams* params, LLMessageSystem *mesgsys) diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp index f42122b0ee..1fc040c7d6 100644 --- a/indra/llrender/llfontgl.cpp +++ b/indra/llrender/llfontgl.cpp @@ -14,6 +14,7 @@ #include "llfontgl.h" #include "llgl.h" #include "v4color.h" +#include "llstl.h" const S32 BOLD_OFFSET = 1; diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index b4edd3d365..9c1178b9f7 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -115,6 +115,15 @@ void LLImageGL::unbindTexture(S32 stage, LLGLenum bind_target) sCurrentBoundTextures[stage] = 0; } +// static (duplicated for speed and to avoid GL_TEXTURE_2D default argument which requires GL header dependency) +void LLImageGL::unbindTexture(S32 stage) +{ + glActiveTextureARB(GL_TEXTURE0_ARB + stage); + glClientActiveTextureARB(GL_TEXTURE0_ARB + stage); + glBindTexture(GL_TEXTURE_2D, 0); + sCurrentBoundTextures[stage] = 0; +} + // static void LLImageGL::updateStats(F32 current_time) { @@ -371,13 +380,8 @@ BOOL LLImageGL::bindTextureInternal(const S32 stage) const llwarns << "Trying to bind a texture while GL is disabled!" << llendl; } - stop_glerror(); - glActiveTextureARB(GL_TEXTURE0_ARB + stage); - //glClientActiveTextureARB(GL_TEXTURE0_ARB + stage); - - stop_glerror(); - + if (sCurrentBoundTextures[stage] && sCurrentBoundTextures[stage] == mTexName) { // already set! @@ -392,7 +396,6 @@ BOOL LLImageGL::bindTextureInternal(const S32 stage) const glBindTexture(mBindTarget, mTexName); sCurrentBoundTextures[stage] = mTexName; - stop_glerror(); if (mLastBindTime != sLastFrameTime) { @@ -631,6 +634,7 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) } mHasMipMaps = FALSE; } + glFlush(); stop_glerror(); } @@ -645,6 +649,11 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3 llwarns << "Setting subimage on image without GL texture" << llendl; return FALSE; } + if (datap == NULL) + { + llwarns << "Setting subimage on image with NULL datap" << llendl; + return FALSE; + } if (x_pos == 0 && y_pos == 0 && width == getWidth() && height == getHeight()) { @@ -657,7 +666,9 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3 dump(); llerrs << "setSubImage called with mipmapped image (not supported)" << llendl; } - llassert(mCurrentDiscardLevel == 0); + llassert_always(mCurrentDiscardLevel == 0); + llassert_always(x_pos >= 0 && y_pos >= 0); + if (((x_pos + width) > getWidth()) || (y_pos + height) > getHeight()) { @@ -698,7 +709,8 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3 datap += (y_pos * data_width + x_pos) * getComponents(); // Update the GL texture - llverify(bindTextureInternal(0)); + BOOL res = bindTextureInternal(0); + if (!res) llerrs << "LLImageGL::setSubImage(): bindTexture failed" << llendl; stop_glerror(); glTexSubImage2D(mTarget, 0, x_pos, y_pos, @@ -714,7 +726,7 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); stop_glerror(); } - + glFlush(); return TRUE; } diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h index 4f6a11c2d9..1586a837b4 100644 --- a/indra/llrender/llimagegl.h +++ b/indra/llrender/llimagegl.h @@ -17,7 +17,7 @@ //============================================================================ -class LLImageGL : public LLThreadSafeRefCount +class LLImageGL : public LLRefCount { public: // Size calculation @@ -29,6 +29,7 @@ public: // Usually you want stage = 0 and bind_target = GL_TEXTURE_2D static void bindExternalTexture( LLGLuint gl_name, S32 stage, LLGLenum bind_target); static void unbindTexture(S32 stage, LLGLenum target); + static void unbindTexture(S32 stage); // Uses GL_TEXTURE_2D (not a default arg to avoid gl.h dependency) // needs to be called every frame static void updateStats(F32 current_time); diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp new file mode 100644 index 0000000000..d6477d69ec --- /dev/null +++ b/indra/llrender/llvertexbuffer.cpp @@ -0,0 +1,918 @@ +#include "linden_common.h" + +#include "llvertexbuffer.h" +// #include "llrender.h" +#include "llglheaders.h" +#include "llmemory.h" +#include "llmemtype.h" + +//============================================================================ + +//static +S32 LLVertexBuffer::sCount = 0; +S32 LLVertexBuffer::sGLCount = 0; +BOOL LLVertexBuffer::sEnableVBOs = TRUE; +S32 LLVertexBuffer::sGLRenderBuffer = 0; +S32 LLVertexBuffer::sGLRenderIndices = 0; +U32 LLVertexBuffer::sLastMask = 0; +BOOL LLVertexBuffer::sVBOActive = FALSE; +BOOL LLVertexBuffer::sIBOActive = FALSE; +U32 LLVertexBuffer::sAllocatedBytes = 0; +BOOL LLVertexBuffer::sRenderActive = FALSE; + +std::vector<U32> LLVertexBuffer::sDeleteList; +LLVertexBuffer::buffer_list_t LLVertexBuffer::sLockedList; + +S32 LLVertexBuffer::sTypeOffsets[LLVertexBuffer::TYPE_MAX] = +{ + sizeof(LLVector3), // TYPE_VERTEX, + sizeof(LLVector3), // TYPE_NORMAL, + sizeof(LLVector2), // TYPE_TEXCOORD, + sizeof(LLVector2), // TYPE_TEXCOORD2, + sizeof(LLColor4U), // TYPE_COLOR, + sizeof(LLVector3), // TYPE_BINORMAL, + sizeof(F32), // TYPE_WEIGHT, + sizeof(LLVector4), // TYPE_CLOTHWEIGHT, +}; + +//static +void LLVertexBuffer::initClass(bool use_vbo) +{ + sEnableVBOs = use_vbo; +} + +//static +void LLVertexBuffer::unbind() +{ + if (sVBOActive) + { + glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); + sVBOActive = FALSE; + } + if (sIBOActive) + { + glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); + sIBOActive = FALSE; + } + + sGLRenderBuffer = 0; + sGLRenderIndices = 0; +} + +//static +void LLVertexBuffer::cleanupClass() +{ + LLMemType mt(LLMemType::MTYPE_VERTEX_DATA); + sLockedList.clear(); + startRender(); + stopRender(); + clientCopy(); // deletes GL buffers +} + +//static, call before rendering VBOs +void LLVertexBuffer::startRender() +{ + LLMemType mt(LLMemType::MTYPE_VERTEX_DATA); + if (sEnableVBOs) + { + glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); + glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); + sVBOActive = FALSE; + sIBOActive = FALSE; + } + + sRenderActive = TRUE; + sGLRenderBuffer = 0; + sGLRenderIndices = 0; + sLastMask = 0; +} + +void LLVertexBuffer::stopRender() +{ + sRenderActive = FALSE; +} + +void LLVertexBuffer::clientCopy() +{ + if (!sDeleteList.empty()) + { + size_t num = sDeleteList.size(); + glDeleteBuffersARB(sDeleteList.size(), (GLuint*) &(sDeleteList[0])); + sDeleteList.clear(); + sGLCount -= num; + } + + if (sEnableVBOs) + { + LLTimer timer; + BOOL reset = TRUE; + buffer_list_t::iterator iter = sLockedList.begin(); + while(iter != sLockedList.end()) + { + LLVertexBuffer* buffer = *iter; + if (buffer->isLocked() && buffer->useVBOs()) + { + buffer->setBuffer(0); + } + ++iter; + if (reset) + { + reset = FALSE; + timer.reset(); //skip first copy (don't count pipeline stall) + } + else + { + if (timer.getElapsedTimeF64() > 0.005) + { + break; + } + } + + } + + sLockedList.erase(sLockedList.begin(), iter); + } +} + +//---------------------------------------------------------------------------- + +// For debugging +struct VTNC /// Simple +{ + F32 v1,v2,v3; + F32 n1,n2,n3; + F32 t1,t2; + U32 c; +}; +static VTNC dbg_vtnc; + +struct VTUNCB // Simple + Bump +{ + F32 v1,v2,v3; + F32 n1,n2,n3; + F32 t1,t2; + F32 u1,u2; + F32 b1,b2,b3; + U32 c; +}; +static VTUNCB dbg_vtuncb; + +struct VTUNC // Surfacepatch +{ + F32 v1,v2,v3; + F32 n1,n2,n3; + F32 t1,t2; + F32 u1,u2; + U32 c; +}; +static VTUNC dbg_vtunc; + +struct VTNW /// Avatar +{ + F32 v1,v2,v3; + F32 n1,n2,n3; + F32 t1,t2; + F32 w; +}; +static VTNW dbg_vtnw; + +struct VTNPAD /// Avatar Output +{ + F32 v1,v2,v3,p1; + F32 n1,n2,n3,p2; + F32 t1,t2,p3,p4; +}; +static VTNPAD dbg_vtnpad; + +//---------------------------------------------------------------------------- + +LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) : + LLRefCount(), + mNumVerts(0), mNumIndices(0), mUsage(usage), mGLBuffer(0), mGLIndices(0), + mMappedData(NULL), + mMappedIndexData(NULL), mLocked(FALSE), + mResized(FALSE), mEmpty(TRUE), mFinal(FALSE), mFilthy(FALSE) +{ + LLMemType mt(LLMemType::MTYPE_VERTEX_DATA); + if (!sEnableVBOs) + { + mUsage = GL_STREAM_DRAW_ARB; + } + + S32 stride = 0; + for (S32 i=0; i<TYPE_MAX; i++) + { + U32 mask = 1<<i; + if (typemask & mask) + { + mOffsets[i] = stride; + stride += sTypeOffsets[i]; + } + } + mTypeMask = typemask; + mStride = stride; + sCount++; +} + +// protected, use unref() +//virtual +LLVertexBuffer::~LLVertexBuffer() +{ + LLMemType mt(LLMemType::MTYPE_VERTEX_DATA); + destroyGLBuffer(); + destroyGLIndices(); + sCount--; + + if (mLocked) + { + //pull off of locked list + for (buffer_list_t::iterator i = sLockedList.begin(); i != sLockedList.end(); ++i) + { + if (*i == this) + { + sLockedList.erase(i); + break; + } + } + } +}; + +//---------------------------------------------------------------------------- + +void LLVertexBuffer::createGLBuffer() +{ + LLMemType mt(LLMemType::MTYPE_VERTEX_DATA); + + U32 size = getSize(); + if (mGLBuffer) + { + destroyGLBuffer(); + } + + if (size == 0) + { + return; + } + + mMappedData = new U8[size]; + memset(mMappedData, 0, size); + mEmpty = TRUE; + + if (useVBOs()) + { + glGenBuffersARB(1, (GLuint*) &mGLBuffer); + mResized = TRUE; + sGLCount++; + } + else + { + static int gl_buffer_idx = 0; + mGLBuffer = ++gl_buffer_idx; + } +} + +void LLVertexBuffer::createGLIndices() +{ + LLMemType mt(LLMemType::MTYPE_VERTEX_DATA); + U32 size = getIndicesSize(); + + if (mGLIndices) + { + destroyGLIndices(); + } + + if (size == 0) + { + return; + } + + mMappedIndexData = new U8[size]; + memset(mMappedIndexData, 0, size); + mEmpty = TRUE; + + if (useVBOs()) + { + glGenBuffersARB(1, (GLuint*) &mGLIndices); + mResized = TRUE; + sGLCount++; + } + else + { + static int gl_buffer_idx = 0; + mGLIndices = ++gl_buffer_idx; + } +} + +void LLVertexBuffer::destroyGLBuffer() +{ + LLMemType mt(LLMemType::MTYPE_VERTEX_DATA); + if (mGLBuffer) + { + if (useVBOs()) + { + sDeleteList.push_back(mGLBuffer); + } + + delete [] mMappedData; + mMappedData = NULL; + mEmpty = TRUE; + sAllocatedBytes -= getSize(); + } + + mGLBuffer = 0; +} + +void LLVertexBuffer::destroyGLIndices() +{ + LLMemType mt(LLMemType::MTYPE_VERTEX_DATA); + if (mGLIndices) + { + if (useVBOs()) + { + sDeleteList.push_back(mGLIndices); + } + + delete [] mMappedIndexData; + mMappedIndexData = NULL; + mEmpty = TRUE; + sAllocatedBytes -= getIndicesSize(); + } + + mGLIndices = 0; +} + +void LLVertexBuffer::updateNumVerts(S32 nverts) +{ + LLMemType mt(LLMemType::MTYPE_VERTEX_DATA); + if (!mDynamicSize) + { + mNumVerts = nverts; + } + else if (mUsage == GL_STATIC_DRAW_ARB || + nverts > mNumVerts || + nverts < mNumVerts/2) + { + if (mUsage != GL_STATIC_DRAW_ARB) + { + nverts += nverts/4; + } + + mNumVerts = nverts; + } +} + +void LLVertexBuffer::updateNumIndices(S32 nindices) +{ + LLMemType mt(LLMemType::MTYPE_VERTEX_DATA); + if (!mDynamicSize) + { + mNumIndices = nindices; + } + else if (mUsage == GL_STATIC_DRAW_ARB || + nindices > mNumIndices || + nindices < mNumIndices/2) + { + if (mUsage != GL_STATIC_DRAW_ARB) + { + nindices += nindices/4; + } + + mNumIndices = nindices; + } +} + +void LLVertexBuffer::makeStatic() +{ + if (!sEnableVBOs) + { + return; + } + + if (sRenderActive) + { + llerrs << "Make static called during render." << llendl; + } + + if (mUsage != GL_STATIC_DRAW_ARB) + { + if (useVBOs()) + { + if (mGLBuffer) + { + sDeleteList.push_back(mGLBuffer); + } + if (mGLIndices) + { + sDeleteList.push_back(mGLIndices); + } + } + + if (mGLBuffer) + { + sGLCount++; + glGenBuffersARB(1, (GLuint*) &mGLBuffer); + } + if (mGLIndices) + { + sGLCount++; + glGenBuffersARB(1, (GLuint*) &mGLIndices); + } + + mUsage = GL_STATIC_DRAW_ARB; + mResized = TRUE; + + if (!mLocked) + { + mLocked = TRUE; + sLockedList.push_back(this); + } + } +} + +void LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create) +{ + LLMemType mt(LLMemType::MTYPE_VERTEX_DATA); + + updateNumVerts(nverts); + updateNumIndices(nindices); + + if (mMappedData) + { + llerrs << "LLVertexBuffer::allocateBuffer() called redundantly." << llendl; + } + if (create && (nverts || nindices)) + { + createGLBuffer(); + createGLIndices(); + } + + sAllocatedBytes += getSize() + getIndicesSize(); +} + +void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices) +{ + LLMemType mt(LLMemType::MTYPE_VERTEX_DATA); + mDynamicSize = TRUE; + if (mUsage == GL_STATIC_DRAW_ARB) + { //always delete/allocate static buffers on resize + destroyGLBuffer(); + destroyGLIndices(); + allocateBuffer(newnverts, newnindices, TRUE); + mFinal = FALSE; + } + else if (newnverts > mNumVerts || newnindices > mNumIndices || + newnverts < mNumVerts/2 || newnindices < mNumIndices/2) + { + sAllocatedBytes -= getSize() + getIndicesSize(); + + S32 oldsize = getSize(); + S32 old_index_size = getIndicesSize(); + + updateNumVerts(newnverts); + updateNumIndices(newnindices); + + S32 newsize = getSize(); + S32 new_index_size = getIndicesSize(); + + sAllocatedBytes += newsize + new_index_size; + + if (newsize) + { + if (!mGLBuffer) + { //no buffer exists, create a new one + createGLBuffer(); + } + else + { + //delete old buffer, keep GL buffer for now + U8* old = mMappedData; + mMappedData = new U8[newsize]; + if (old) + { + memcpy(mMappedData, old, llmin(newsize, oldsize)); + if (newsize > oldsize) + { + memset(mMappedData+oldsize, 0, newsize-oldsize); + } + + delete [] old; + } + else + { + memset(mMappedData, 0, newsize); + mEmpty = TRUE; + } + mResized = TRUE; + } + } + else if (mGLBuffer) + { + destroyGLBuffer(); + } + + if (new_index_size) + { + if (!mGLIndices) + { + createGLIndices(); + } + else + { + //delete old buffer, keep GL buffer for now + U8* old = mMappedIndexData; + mMappedIndexData = new U8[new_index_size]; + if (old) + { + memcpy(mMappedIndexData, old, llmin(new_index_size, old_index_size)); + if (new_index_size > old_index_size) + { + memset(mMappedIndexData+old_index_size, 0, new_index_size - old_index_size); + } + delete [] old; + } + else + { + memset(mMappedIndexData, 0, new_index_size); + mEmpty = TRUE; + } + mResized = TRUE; + } + } + else if (mGLIndices) + { + destroyGLIndices(); + } + } +} + +BOOL LLVertexBuffer::useVBOs() const +{ + //it's generally ineffective to use VBO for things that are streaming + //when we already have a client buffer around + if (mUsage == GL_STREAM_DRAW_ARB) + { + return FALSE; + } + + return sEnableVBOs && (!sRenderActive || !mLocked); +} + +//---------------------------------------------------------------------------- + +// Map for data access +U8* LLVertexBuffer::mapBuffer(S32 access) +{ + LLMemType mt(LLMemType::MTYPE_VERTEX_DATA); + if (sRenderActive) + { + llwarns << "Buffer mapped during render frame!" << llendl; + } + if (!mGLBuffer && !mGLIndices) + { + llerrs << "LLVertexBuffer::mapBuffer() called before createGLBuffer" << llendl; + } + if (mFinal) + { + llerrs << "LLVertexBuffer::mapBuffer() called on a finalized buffer." << llendl; + } + if (!mMappedData && !mMappedIndexData) + { + llerrs << "LLVertexBuffer::mapBuffer() called on unallocated buffer." << llendl; + } + + if (!mLocked && useVBOs()) + { + mLocked = TRUE; + sLockedList.push_back(this); + } + + return mMappedData; +} + +void LLVertexBuffer::unmapBuffer() +{ + LLMemType mt(LLMemType::MTYPE_VERTEX_DATA); + if (mMappedData || mMappedIndexData) + { + if (useVBOs() && mLocked) + { + if (mGLBuffer) + { + if (mResized) + { + glBufferDataARB(GL_ARRAY_BUFFER_ARB, getSize(), mMappedData, mUsage); + } + else + { + if (mEmpty || mDirtyRegions.empty()) + { + glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, getSize(), mMappedData); + } + else + { + for (std::vector<DirtyRegion>::iterator i = mDirtyRegions.begin(); i != mDirtyRegions.end(); ++i) + { + DirtyRegion& region = *i; + glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, region.mIndex*mStride, region.mCount*mStride, mMappedData + region.mIndex*mStride); + glFlush(); + } + } + } + } + + if (mGLIndices) + { + if (mResized) + { + glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, getIndicesSize(), mMappedIndexData, mUsage); + } + else + { + if (mEmpty || mDirtyRegions.empty()) + { + glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, getIndicesSize(), mMappedIndexData); + } + else + { + for (std::vector<DirtyRegion>::iterator i = mDirtyRegions.begin(); i != mDirtyRegions.end(); ++i) + { + DirtyRegion& region = *i; + glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, region.mIndicesIndex*sizeof(U32), + region.mIndicesCount*sizeof(U32), mMappedIndexData + region.mIndicesIndex*sizeof(U32)); + glFlush(); + } + } + } + } + + mDirtyRegions.clear(); + mFilthy = FALSE; + mResized = FALSE; + + if (mUsage == GL_STATIC_DRAW_ARB) + { //static draw buffers can only be mapped a single time + //throw out client data (we won't be using it again) + delete [] mMappedData; + delete [] mMappedIndexData; + mMappedIndexData = NULL; + mMappedData = NULL; + mEmpty = TRUE; + mFinal = TRUE; + } + else + { + mEmpty = FALSE; + } + + mLocked = FALSE; + + glFlush(); + } + } +} + +//---------------------------------------------------------------------------- + +template <class T,S32 type> struct VertexBufferStrider +{ + typedef LLStrider<T> strider_t; + static bool get(LLVertexBuffer& vbo, + strider_t& strider, + S32 index) + { + vbo.mapBuffer(); + if (type == LLVertexBuffer::TYPE_INDEX) + { + S32 stride = sizeof(T); + strider = (T*)(vbo.getMappedIndices() + index*stride); + strider.setStride(0); + return TRUE; + } + else if (vbo.hasDataType(type)) + { + S32 stride = vbo.getStride(); + strider = (T*)(vbo.getMappedData() + vbo.getOffset(type) + index*stride); + strider.setStride(stride); + return TRUE; + } + else + { + llerrs << "VertexBufferStrider could not find valid vertex data." << llendl; + } + return FALSE; + } +}; + + +bool LLVertexBuffer::getVertexStrider(LLStrider<LLVector3>& strider, S32 index) +{ + return VertexBufferStrider<LLVector3,TYPE_VERTEX>::get(*this, strider, index); +} +bool LLVertexBuffer::getIndexStrider(LLStrider<U32>& strider, S32 index) +{ + return VertexBufferStrider<U32,TYPE_INDEX>::get(*this, strider, index); +} +bool LLVertexBuffer::getTexCoordStrider(LLStrider<LLVector2>& strider, S32 index) +{ + return VertexBufferStrider<LLVector2,TYPE_TEXCOORD>::get(*this, strider, index); +} +bool LLVertexBuffer::getTexCoord2Strider(LLStrider<LLVector2>& strider, S32 index) +{ + return VertexBufferStrider<LLVector2,TYPE_TEXCOORD2>::get(*this, strider, index); +} +bool LLVertexBuffer::getNormalStrider(LLStrider<LLVector3>& strider, S32 index) +{ + return VertexBufferStrider<LLVector3,TYPE_NORMAL>::get(*this, strider, index); +} +bool LLVertexBuffer::getBinormalStrider(LLStrider<LLVector3>& strider, S32 index) +{ + return VertexBufferStrider<LLVector3,TYPE_BINORMAL>::get(*this, strider, index); +} +bool LLVertexBuffer::getColorStrider(LLStrider<LLColor4U>& strider, S32 index) +{ + return VertexBufferStrider<LLColor4U,TYPE_COLOR>::get(*this, strider, index); +} +bool LLVertexBuffer::getWeightStrider(LLStrider<F32>& strider, S32 index) +{ + return VertexBufferStrider<F32,TYPE_WEIGHT>::get(*this, strider, index); +} +bool LLVertexBuffer::getClothWeightStrider(LLStrider<LLVector4>& strider, S32 index) +{ + return VertexBufferStrider<LLVector4,TYPE_CLOTHWEIGHT>::get(*this, strider, index); +} + +void LLVertexBuffer::setStride(S32 type, S32 new_stride) +{ + LLMemType mt(LLMemType::MTYPE_VERTEX_DATA); + if (mNumVerts) + { + llerrs << "LLVertexBuffer::setOffset called with mNumVerts = " << mNumVerts << llendl; + } + // This code assumes that setStride() will only be called once per VBO per type. + S32 delta = new_stride - sTypeOffsets[type]; + for (S32 i=type+1; i<TYPE_MAX; i++) + { + if (mTypeMask & (1<<i)) + { + mOffsets[i] += delta; + } + } + mStride += delta; +} + +//---------------------------------------------------------------------------- + +// Set for rendering +void LLVertexBuffer::setBuffer(U32 data_mask) +{ + LLMemType mt(LLMemType::MTYPE_VERTEX_DATA); + //set up pointers if the data mask is different ... + BOOL setup = (sLastMask != data_mask); + + if (useVBOs()) + { + if (mGLBuffer && (mGLBuffer != sGLRenderBuffer || !sVBOActive)) + { + glBindBufferARB(GL_ARRAY_BUFFER_ARB, mGLBuffer); + sVBOActive = TRUE; + setup = TRUE; // ... or the bound buffer changed + } + if (mGLIndices && (mGLIndices != sGLRenderIndices || !sIBOActive)) + { + glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, mGLIndices); + sIBOActive = TRUE; + } + + unmapBuffer(); + } + else + { + if (!mDirtyRegions.empty()) + { + mFilthy = TRUE; + mDirtyRegions.clear(); + } + + if (mGLBuffer) + { + if (sEnableVBOs && sVBOActive) + { + glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); + sVBOActive = FALSE; + setup = TRUE; // ... or a VBO is deactivated + } + if (sGLRenderBuffer != mGLBuffer) + { + setup = TRUE; // ... or a client memory pointer changed + } + } + if (sEnableVBOs && mGLIndices && sIBOActive) + { + glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); + sIBOActive = FALSE; + } + } + + if (mGLIndices) + { + sGLRenderIndices = mGLIndices; + } + if (mGLBuffer) + { + sGLRenderBuffer = mGLBuffer; + if (data_mask && setup) + { + if (!sRenderActive) + { + llwarns << "Vertex buffer set for rendering outside of render frame." << llendl; + } + setupVertexBuffer(data_mask); // subclass specific setup (virtual function) + sLastMask = data_mask; + } + } +} + +// virtual (default) +void LLVertexBuffer::setupVertexBuffer(U32 data_mask) const +{ + LLMemType mt(LLMemType::MTYPE_VERTEX_DATA); + stop_glerror(); + U8* base = useVBOs() ? NULL : mMappedData; + S32 stride = mStride; + + if ((data_mask & mTypeMask) != data_mask) + { + llerrs << "LLVertexBuffer::setupVertexBuffer missing required components for supplied data mask." << llendl; + } + + if (data_mask & MAP_VERTEX) + { + glVertexPointer(3,GL_FLOAT, stride, (void*)(base + 0)); + } + if (data_mask & MAP_NORMAL) + { + glNormalPointer(GL_FLOAT, stride, (void*)(base + mOffsets[TYPE_NORMAL])); + } + if (data_mask & MAP_TEXCOORD2) + { + glClientActiveTextureARB(GL_TEXTURE1_ARB); + glTexCoordPointer(2,GL_FLOAT, stride, (void*)(base + mOffsets[TYPE_TEXCOORD2])); + } + if (data_mask & MAP_TEXCOORD) + { + glClientActiveTextureARB(GL_TEXTURE0_ARB); + glTexCoordPointer(2,GL_FLOAT, stride, (void*)(base + mOffsets[TYPE_TEXCOORD])); + } + if (data_mask & MAP_COLOR) + { + glColorPointer(4, GL_UNSIGNED_BYTE, stride, (void*)(base + mOffsets[TYPE_COLOR])); + } + if (data_mask & MAP_BINORMAL) + { + glVertexAttribPointerARB(6, 3, GL_FLOAT, FALSE, stride, (void*)(base + mOffsets[TYPE_BINORMAL])); + } + if (data_mask & MAP_WEIGHT) + { + glVertexAttribPointerARB(1, 1, GL_FLOAT, FALSE, stride, (void*)(base + mOffsets[TYPE_WEIGHT])); + } + if (data_mask & MAP_CLOTHWEIGHT) + { + glVertexAttribPointerARB(4, 4, GL_FLOAT, TRUE, stride, (void*)(base + mOffsets[TYPE_CLOTHWEIGHT])); + } + + llglassertok(); +} + +void LLVertexBuffer::markDirty(U32 vert_index, U32 vert_count, U32 indices_index, U32 indices_count) +{ + if (useVBOs() && !mFilthy) + { + if (!mDirtyRegions.empty()) + { + DirtyRegion& region = *(mDirtyRegions.rbegin()); + if (region.mIndex + region.mCount == vert_index && + region.mIndicesIndex + region.mIndicesCount == indices_index) + { + region.mCount += vert_count; + region.mIndicesCount += indices_count; + return; + } + } + + mDirtyRegions.push_back(DirtyRegion(vert_index,vert_count,indices_index,indices_count)); + } +} + +void LLVertexBuffer::markClean() +{ + if (!mResized && !mEmpty && !mFilthy) + { + buffer_list_t::reverse_iterator iter = sLockedList.rbegin(); + if (*iter == this) + { + mLocked = FALSE; + sLockedList.pop_back(); + } + } +} + diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h new file mode 100644 index 0000000000..e672321e76 --- /dev/null +++ b/indra/llrender/llvertexbuffer.h @@ -0,0 +1,179 @@ +#ifndef LL_LLVERTEXBUFFER_H +#define LL_LLVERTEXBUFFER_H + +#include "llgl.h" +#include "v2math.h" +#include "v3math.h" +#include "v4math.h" +#include "v4coloru.h" +#include "llstrider.h" +#include "llmemory.h" +#include <set> +#include <vector> + +//============================================================================ +// NOTES +// Threading: +// All constructors should take an 'create' paramater which should only be +// 'true' when called from the main thread. Otherwise createGLBuffer() will +// be called as soon as getVertexPointer(), etc is called (which MUST ONLY be +// called from the main (i.e OpenGL) thread) + +//============================================================================ +// base class + +class LLVertexBuffer : public LLRefCount +{ +public: + static void initClass(bool use_vbo); + static void cleanupClass(); + static void startRender(); //between start and stop render, no client copies will occur + static void stopRender(); //any buffer not copied to GL will be rendered from client memory + static void clientCopy(); //copy data from client to GL + static void unbind(); //unbind any bound vertex buffer + + enum { + TYPE_VERTEX, + TYPE_NORMAL, + TYPE_TEXCOORD, + TYPE_TEXCOORD2, + TYPE_COLOR, + // These use VertexAttribPointer and should possibly be made generic + TYPE_BINORMAL, + TYPE_WEIGHT, + TYPE_CLOTHWEIGHT, + TYPE_MAX, + TYPE_INDEX, + }; + enum { + MAP_VERTEX = (1<<TYPE_VERTEX), + MAP_NORMAL = (1<<TYPE_NORMAL), + MAP_TEXCOORD = (1<<TYPE_TEXCOORD), + MAP_TEXCOORD2 = (1<<TYPE_TEXCOORD2), + MAP_COLOR = (1<<TYPE_COLOR), + // These use VertexAttribPointer and should possibly be made generic + MAP_BINORMAL = (1<<TYPE_BINORMAL), + MAP_WEIGHT = (1<<TYPE_WEIGHT), + MAP_CLOTHWEIGHT = (1<<TYPE_CLOTHWEIGHT), + MAP_DRAW = 0x2000, // Buffer is in draw (read-only) mode + MAP_MAPPED = 0x4000, // Indicates that buffer has been mapped, but not to any type of data + MAP_UNMAPPED = 0x8000 // Indicates that buffer has been logically un-mapped + }; + +protected: + virtual ~LLVertexBuffer(); // use unref() + + virtual void setupVertexBuffer(U32 data_mask) const; // pure virtual, called from mapBuffer() + + void createGLBuffer(); + void createGLIndices(); + void destroyGLBuffer(); + void destroyGLIndices(); + void updateNumVerts(S32 nverts); + void updateNumIndices(S32 nindices); + virtual BOOL useVBOs() const; + void unmapBuffer(); + +public: + LLVertexBuffer(U32 typemask, S32 usage); + + // map for data access + U8* mapBuffer(S32 access = -1); + // set for rendering + virtual void setBuffer(U32 data_mask); // calls setupVertexBuffer() if data_mask is not 0 + // allocate buffer + void allocateBuffer(S32 nverts, S32 nindices, bool create); + virtual void resizeBuffer(S32 newnverts, S32 newnindices); + void makeStatic(); + + // Only call each getVertexPointer, etc, once before calling unmapBuffer() + // call unmapBuffer() after calls to getXXXStrider() before any cals to setBuffer() + // example: + // vb->getVertexBuffer(verts); + // vb->getNormalStrider(norms); + // setVertsNorms(verts, norms); + // vb->unmapBuffer(); + bool getVertexStrider(LLStrider<LLVector3>& strider, S32 index=0); + bool getIndexStrider(LLStrider<U32>& strider, S32 index=0); + bool getTexCoordStrider(LLStrider<LLVector2>& strider, S32 index=0); + bool getTexCoord2Strider(LLStrider<LLVector2>& strider, S32 index=0); + bool getNormalStrider(LLStrider<LLVector3>& strider, S32 index=0); + bool getBinormalStrider(LLStrider<LLVector3>& strider, S32 index=0); + bool getColorStrider(LLStrider<LLColor4U>& strider, S32 index=0); + bool getWeightStrider(LLStrider<F32>& strider, S32 index=0); + bool getClothWeightStrider(LLStrider<LLVector4>& strider, S32 index=0); + + BOOL isEmpty() const { return mEmpty; } + BOOL isLocked() const { return mLocked; } + S32 getNumVerts() const { return mNumVerts; } + S32 getNumIndices() const { return mNumIndices; } + U8* getIndicesPointer() const { return useVBOs() ? NULL : mMappedIndexData; } + U8* getVerticesPointer() const { return useVBOs() ? NULL : mMappedData; } + S32 getStride() const { return mStride; } + S32 getTypeMask() const { return mTypeMask; } + BOOL hasDataType(S32 type) const { return ((1 << type) & getTypeMask()) ? TRUE : FALSE; } + S32 getSize() const { return mNumVerts*mStride; } + S32 getIndicesSize() const { return mNumIndices * sizeof(U32); } + U8* getMappedData() const { return mMappedData; } + U8* getMappedIndices() const { return mMappedIndexData; } + S32 getOffset(S32 type) const { return mOffsets[type]; } + S32 getUsage() const { return mUsage; } + + void setStride(S32 type, S32 new_stride); + + void markDirty(U32 vert_index, U32 vert_count, U32 indices_index, U32 indices_count); + void markClean(); + +protected: + S32 mNumVerts; // Number of vertices + S32 mNumIndices; // Number of indices + S32 mStride; + U32 mTypeMask; + S32 mUsage; // GL usage + U32 mGLBuffer; // GL VBO handle + U32 mGLIndices; // GL IBO handle + U8* mMappedData; // pointer to currently mapped data (NULL if unmapped) + U8* mMappedIndexData; // pointer to currently mapped indices (NULL if unmapped) + BOOL mLocked; // if TRUE, buffer is being or has been written to in client memory + BOOL mFinal; // if TRUE, buffer can not be mapped again + BOOL mFilthy; // if TRUE, entire buffer must be copied (used to prevent redundant dirty flags) + BOOL mEmpty; // if TRUE, client buffer is empty (or NULL). Old values have been discarded. + S32 mOffsets[TYPE_MAX]; + BOOL mResized; // if TRUE, client buffer has been resized and GL buffer has not + BOOL mDynamicSize; // if TRUE, buffer has been resized at least once (and should be padded) + + class DirtyRegion + { + public: + U32 mIndex; + U32 mCount; + U32 mIndicesIndex; + U32 mIndicesCount; + + DirtyRegion(U32 vi, U32 vc, U32 ii, U32 ic) + : mIndex(vi), mCount(vc), mIndicesIndex(ii), mIndicesCount(ic) + { } + }; + + std::vector<DirtyRegion> mDirtyRegions; //vector of dirty regions to rebuild + +public: + static BOOL sRenderActive; + static S32 sCount; + static S32 sGLCount; + static std::vector<U32> sDeleteList; + typedef std::list<LLVertexBuffer*> buffer_list_t; + static buffer_list_t sLockedList; + + static BOOL sEnableVBOs; + static S32 sTypeOffsets[TYPE_MAX]; + static S32 sGLRenderBuffer; + static S32 sGLRenderIndices; + static BOOL sVBOActive; + static BOOL sIBOActive; + static U32 sLastMask; + static U32 sAllocatedBytes; +}; + + +#endif // LL_LLVERTEXBUFFER_H diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp index fc7a29887b..667985c699 100644 --- a/indra/llui/llcombobox.cpp +++ b/indra/llui/llcombobox.cpp @@ -43,6 +43,7 @@ LLComboBox::LLComboBox( const LLString& name, const LLRect &rect, const LLString mDrawButton(TRUE), mTextEntry(NULL), mArrowImage(NULL), + mArrowImageWidth(8), mAllowTextEntry(FALSE), mMaxChars(20), mTextEntryTentative(TRUE), @@ -99,6 +100,7 @@ LLComboBox::LLComboBox( const LLString& name, const LLRect &rect, const LLString LLUUID arrow_image_id( LLUI::sAssetsGroup->getString("combobox_arrow.tga") ); mArrowImage = LLUI::sImageProvider->getUIImageByID(arrow_image_id); + mArrowImageWidth = llmax(8,mArrowImage->getWidth()); // In case image hasn't loaded yet } @@ -502,7 +504,7 @@ void LLComboBox::setButtonVisible(BOOL visible) LLRect text_entry_rect(0, mRect.getHeight(), mRect.getWidth(), 0); if (visible) { - text_entry_rect.mRight -= mArrowImage->getWidth() + 2 * LLUI::sConfigGroup->getS32("DropShadowButton"); + text_entry_rect.mRight -= mArrowImageWidth + 2 * LLUI::sConfigGroup->getS32("DropShadowButton"); } //mTextEntry->setRect(text_entry_rect); mTextEntry->reshape(text_entry_rect.getWidth(), text_entry_rect.getHeight(), TRUE); @@ -525,7 +527,7 @@ void LLComboBox::draw() // Paste the graphic on the right edge if (!mArrowImage.isNull()) { - S32 left = mRect.getWidth() - mArrowImage->getWidth() - LLUI::sConfigGroup->getS32("DropShadowButton"); + S32 left = mRect.getWidth() - mArrowImageWidth - LLUI::sConfigGroup->getS32("DropShadowButton"); gl_draw_image( left, 0, mArrowImage, LLColor4::white); @@ -825,7 +827,7 @@ void LLComboBox::setAllowTextEntry(BOOL allow, S32 max_chars, BOOL set_tentative if (allow && !mAllowTextEntry) { S32 shadow_size = LLUI::sConfigGroup->getS32("DropShadowButton"); - mButton->setRect(LLRect( mRect.getWidth() - mArrowImage->getWidth() - 2 * shadow_size, + mButton->setRect(LLRect( mRect.getWidth() - mArrowImageWidth - 2 * shadow_size, rect.mTop, rect.mRight, rect.mBottom)); mButton->setTabStop(FALSE); @@ -835,7 +837,7 @@ void LLComboBox::setAllowTextEntry(BOOL allow, S32 max_chars, BOOL set_tentative if (!mTextEntry) { LLRect text_entry_rect(0, mRect.getHeight(), mRect.getWidth(), 0); - text_entry_rect.mRight -= mArrowImage->getWidth() + 2 * LLUI::sConfigGroup->getS32("DropShadowButton"); + text_entry_rect.mRight -= mArrowImageWidth + 2 * LLUI::sConfigGroup->getS32("DropShadowButton"); mTextEntry = new LLLineEditor("combo_text_entry", text_entry_rect, "", diff --git a/indra/llui/llcombobox.h b/indra/llui/llcombobox.h index 1ec31ec1c0..faf99937c9 100644 --- a/indra/llui/llcombobox.h +++ b/indra/llui/llcombobox.h @@ -167,8 +167,9 @@ protected: BOOL mDrawButton; LLLineEditor* mTextEntry; LLPointer<LLImageGL> mArrowImage; + S32 mArrowImageWidth; BOOL mAllowTextEntry; - S32 mMaxChars; + S32 mMaxChars; BOOL mTextEntryTentative; void (*mPrearrangeCallback)(LLUICtrl*,void*); void (*mTextEntryCallback)(LLLineEditor*, void*); diff --git a/indra/llui/llpanel.h b/indra/llui/llpanel.h index 59922994c1..fdf4a117d4 100644 --- a/indra/llui/llpanel.h +++ b/indra/llui/llpanel.h @@ -17,6 +17,7 @@ #include "llviewborder.h" #include "v4color.h" #include <list> +#include <queue> const S32 LLPANEL_BORDER_WIDTH = 1; const BOOL BORDER_YES = TRUE; diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index c168bbe5a8..f2ae318dca 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -2720,7 +2720,7 @@ void LLScrollListCtrl::setFocus(BOOL b) if (!getFirstSelected()) { selectFirstItem(); - onCommit(); + //onCommit(); // SJB: selectFirstItem() will call onCommit() if appropriate } LLUICtrl::setFocus(b); } diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index 710e333796..de34aabb1f 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -3934,6 +3934,8 @@ LLXMLNodePtr LLTextEditor::getXML(bool save_children) const node->createChild("word_wrap", TRUE)->setBoolValue(mWordWrap); + node->createChild("hide_scrollbar", TRUE)->setBoolValue(mHideScrollbarForShortDocs); + addColorXML(node, mCursorColor, "cursor_color", "TextCursorColor"); addColorXML(node, mFgColor, "text_color", "TextFgColor"); addColorXML(node, mReadOnlyFgColor, "text_readonly_color", "TextFgReadOnlyColor"); diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h index f58b7d6e16..1418151201 100644 --- a/indra/llui/lluictrl.h +++ b/indra/llui/lluictrl.h @@ -17,7 +17,6 @@ // // Classes // -class LLViewerImage; class LLFontGL; class LLButton; class LLTextBox; diff --git a/indra/llui/lluictrlfactory.cpp b/indra/llui/lluictrlfactory.cpp index 8ae9fd0284..21278455da 100644 --- a/indra/llui/lluictrlfactory.cpp +++ b/indra/llui/lluictrlfactory.cpp @@ -191,12 +191,18 @@ LLUICtrlFactory::LLUICtrlFactory() LLUICtrlCreator<LLMenuBarGL>::registerCreator(LL_MENU_BAR_GL_TAG, this); LLUICtrlCreator<LLScrollingPanelList>::registerCreator(LL_SCROLLING_PANEL_LIST_TAG, this); + setupPaths(); +} + +void LLUICtrlFactory::setupPaths() +{ LLString filename = gDirUtilp->getExpandedFilename(LL_PATH_SKINS, "paths.xml"); LLXMLNodePtr root; BOOL success = LLXMLNode::parseFile(filename, root, NULL); - + mXUIPaths.clear(); + if (!success) { LLString slash = gDirUtilp->getDirDelimiter(); @@ -220,7 +226,7 @@ LLUICtrlFactory::LLUICtrlFactory() path_val_ui.setArg("[Language]", language); LLString fullpath = app_dir + path_val_ui.getString(); - if (mXUIPaths.empty() || (find(mXUIPaths.begin(), mXUIPaths.end(), fullpath) == mXUIPaths.end()) ) + if (std::find(mXUIPaths.begin(), mXUIPaths.end(), fullpath) == mXUIPaths.end()) { mXUIPaths.push_back(app_dir + path_val_ui.getString()); } diff --git a/indra/llui/lluictrlfactory.h b/indra/llui/lluictrlfactory.h index b3bd5c9020..cb6864bafd 100644 --- a/indra/llui/lluictrlfactory.h +++ b/indra/llui/lluictrlfactory.h @@ -55,6 +55,8 @@ public: // do not call! needs to be public so run-time can clean up the singleton virtual ~LLUICtrlFactory(); + void setupPaths(); + void buildFloater(LLFloater* floaterp, const LLString &filename, const LLCallbackMap::map_t* factory_map = NULL, BOOL open = TRUE); diff --git a/indra/llvfs/lldir.cpp b/indra/llvfs/lldir.cpp index 9f8d6c08d5..d8d77e6a23 100644 --- a/indra/llvfs/lldir.cpp +++ b/indra/llvfs/lldir.cpp @@ -183,6 +183,27 @@ const std::string &LLDir::getTempDir() const return mTempDir; } +const std::string LLDir::getCacheDir(bool get_default) const +{ + if (mCacheDir.empty() || get_default) + { + std::string res; + if (getOSUserAppDir().empty()) + { + res = "data"; + } + else + { + res = getOSUserAppDir() + mDirDelimiter + "cache"; + } + return res; + } + else + { + return mCacheDir; + } +} + const std::string &LLDir::getCAFile() const { return mCAFile; @@ -198,7 +219,12 @@ const std::string &LLDir::getSkinDir() const return mSkinDir; } -std::string LLDir::getExpandedFilename(ELLPath location, const std::string &filename) const +std::string LLDir::getExpandedFilename(ELLPath location, const std::string& filename) const +{ + return getExpandedFilename(location, "", filename); +} + +std::string LLDir::getExpandedFilename(ELLPath location, const std::string& subdir, const std::string& in_filename) const { std::string prefix; switch (location) @@ -230,16 +256,7 @@ std::string LLDir::getExpandedFilename(ELLPath location, const std::string &file break; case LL_PATH_CACHE: - if (getOSUserAppDir().empty()) - { - prefix = "data"; - } - else - { - prefix = getOSUserAppDir(); - prefix += mDirDelimiter; - prefix += "cache"; - } + prefix = getCacheDir(); break; case LL_PATH_USER_SETTINGS: @@ -290,6 +307,16 @@ std::string LLDir::getExpandedFilename(ELLPath location, const std::string &file llassert(0); } + std::string filename = in_filename; + if (!subdir.empty()) + { + filename = subdir + mDirDelimiter + in_filename; + } + else + { + filename = in_filename; + } + std::string expanded_filename; if (!filename.empty()) { @@ -304,8 +331,7 @@ std::string LLDir::getExpandedFilename(ELLPath location, const std::string &file expanded_filename = filename; } } - else - if (!prefix.empty()) + else if (!prefix.empty()) { // Directory only, no file name. expanded_filename = prefix; @@ -405,6 +431,30 @@ void LLDir::setSkinFolder(const std::string &skin_folder) mSkinDir += skin_folder; } +bool LLDir::setCacheDir(const std::string &path) +{ + if (path.empty() ) + { + // reset to default + mCacheDir = ""; + return true; + } + else + { + LLFile::mkdir(path.c_str()); + std::string tempname = path + mDirDelimiter + "temp"; + LLFILE* file = LLFile::fopen(tempname.c_str(),"wt"); + if (file) + { + fclose(file); + LLFile::remove(tempname.c_str()); + mCacheDir = path; + return true; + } + return false; + } +} + void LLDir::dumpCurrentDirectories() { llinfos << "Current Directories:" << llendl; diff --git a/indra/llvfs/lldir.h b/indra/llvfs/lldir.h index 710dcd1ae3..5389378def 100644 --- a/indra/llvfs/lldir.h +++ b/indra/llvfs/lldir.h @@ -60,12 +60,14 @@ class LLDir const std::string &getChatLogsDir() const; // Location of the chat logs dir. const std::string &getPerAccountChatLogsDir() const; // Location of the per account chat logs dir. const std::string &getTempDir() const; // Common temporary directory + const std::string getCacheDir(bool get_default = false) const; // Location of the cache. const std::string &getCAFile() const; // File containing TLS certificate authorities const std::string &getDirDelimiter() const; // directory separator for platform (ie. '\' or '/' or ':') const std::string &getSkinDir() const; // User-specified skin folder. // Expanded filename std::string getExpandedFilename(ELLPath location, const std::string &filename) const; + std::string getExpandedFilename(ELLPath location, const std::string &subdir, const std::string &filename) const; // random filename in common temporary directory std::string getTempFilename() const; @@ -74,6 +76,7 @@ class LLDir virtual void setPerAccountChatLogsDir(const std::string &first, const std::string &last); // Set the per user chat log directory. virtual void setLindenUserDir(const std::string &first, const std::string &last); // Set the linden user dir to this user's dir virtual void setSkinFolder(const std::string &skin_folder); + virtual bool setCacheDir(const std::string &path); virtual void dumpCurrentDirectories(); @@ -91,6 +94,7 @@ protected: std::string mChatLogsDir; // Location for chat logs. std::string mCAFile; // Location of the TLS certificate authority PEM file. std::string mTempDir; + std::string mCacheDir; std::string mDirDelimiter; std::string mSkinDir; // Location for u ser-specified skin info. }; diff --git a/indra/llvfs/lllfsthread.cpp b/indra/llvfs/lllfsthread.cpp index 6af638fd12..598de1d370 100644 --- a/indra/llvfs/lllfsthread.cpp +++ b/indra/llvfs/lllfsthread.cpp @@ -19,10 +19,10 @@ //============================================================================ // Run on MAIN thread //static -void LLLFSThread::initClass(bool local_is_threaded, bool local_run_always) +void LLLFSThread::initClass(bool local_is_threaded) { llassert(sLocal == NULL); - sLocal = new LLLFSThread(local_is_threaded, local_run_always); + sLocal = new LLLFSThread(local_is_threaded); } //static @@ -46,8 +46,9 @@ void LLLFSThread::cleanupClass() //---------------------------------------------------------------------------- -LLLFSThread::LLLFSThread(bool threaded, bool runalways) : - LLQueuedThread("LFS", threaded, runalways) +LLLFSThread::LLLFSThread(bool threaded) : + LLQueuedThread("LFS", threaded), + mPriorityCounter(PRIORITY_LOWBITS) { } @@ -59,250 +60,164 @@ LLLFSThread::~LLLFSThread() //---------------------------------------------------------------------------- LLLFSThread::handle_t LLLFSThread::read(const LLString& filename, /* Flawfinder: ignore */ - U8* buffer, S32 offset, S32 numbytes, U32 priority, U32 flags) + U8* buffer, S32 offset, S32 numbytes, + Responder* responder, U32 priority) { handle_t handle = generateHandle(); - priority = llmax(priority, (U32)PRIORITY_LOW); // All reads are at least PRIORITY_LOW - Request* req = new Request(handle, priority, flags, + if (priority == 0) priority = PRIORITY_NORMAL | priorityCounter(); + else if (priority < PRIORITY_LOW) priority |= PRIORITY_LOW; // All reads are at least PRIORITY_LOW + + Request* req = new Request(this, handle, priority, FILE_READ, filename, - buffer, offset, numbytes); + buffer, offset, numbytes, + responder); bool res = addRequest(req); if (!res) { llerrs << "LLLFSThread::read called after LLLFSThread::cleanupClass()" << llendl; - req->deleteRequest(); - handle = nullHandle(); } return handle; } -S32 LLLFSThread::readImmediate(const LLString& filename, - U8* buffer, S32 offset, S32 numbytes) -{ - handle_t handle = generateHandle(); - - Request* req = new Request(handle, PRIORITY_IMMEDIATE, 0, - FILE_READ, filename, - buffer, offset, numbytes); - - S32 res = addRequest(req) ? 1 : 0; - if (res == 0) - { - llerrs << "LLLFSThread::read called after LLLFSThread::cleanupClass()" << llendl; - req->deleteRequest(); - } - else - { - llverify(waitForResult(handle, false) == true); - res = req->getBytesRead(); - completeRequest(handle); - } - return res; -} - LLLFSThread::handle_t LLLFSThread::write(const LLString& filename, - U8* buffer, S32 offset, S32 numbytes, U32 flags) + U8* buffer, S32 offset, S32 numbytes, + Responder* responder, U32 priority) { handle_t handle = generateHandle(); - Request* req = new Request(handle, 0, flags, - FILE_WRITE, filename, - buffer, offset, numbytes); - - bool res = addRequest(req); - if (!res) - { - llerrs << "LLLFSThread::read called after LLLFSThread::cleanupClass()" << llendl; - req->deleteRequest(); - handle = nullHandle(); - } + if (priority == 0) priority = PRIORITY_LOW | priorityCounter(); - return handle; -} - -S32 LLLFSThread::writeImmediate(const LLString& filename, - U8* buffer, S32 offset, S32 numbytes) -{ - handle_t handle = generateHandle(); - - Request* req = new Request(handle, PRIORITY_IMMEDIATE, 0, + Request* req = new Request(this, handle, priority, FILE_WRITE, filename, - buffer, offset, numbytes); - - S32 res = addRequest(req) ? 1 : 0; - if (res == 0) - { - llerrs << "LLLFSThread::write called after LLLFSThread::cleanupClass()" << llendl; - req->deleteRequest(); - } - else - { - llverify(waitForResult(handle, false) == true); - res = req->getBytesRead(); - completeRequest(handle); - } - return res; -} - - -LLLFSThread::handle_t LLLFSThread::rename(const LLString& filename, const LLString& newname, U32 flags) -{ - handle_t handle = generateHandle(); - - LLString* new_name_str = new LLString(newname); // deleted with Request - Request* req = new Request(handle, 0, flags, - FILE_RENAME, filename, - (U8*)new_name_str, 0, 0); - - bool res = addRequest(req); - if (!res) - { - llerrs << "LLLFSThread::rename called after LLLFSThread::cleanupClass()" << llendl; - req->deleteRequest(); - handle = nullHandle(); - } - - return handle; -} - -LLLFSThread::handle_t LLLFSThread::remove(const LLString& filename, U32 flags) -{ - handle_t handle = generateHandle(); - - Request* req = new Request(handle, 0, flags, - FILE_RENAME, filename, - NULL, 0, 0); + buffer, offset, numbytes, + responder); bool res = addRequest(req); if (!res) { - llerrs << "LLLFSThread::remove called after LLLFSThread::cleanupClass()" << llendl; - req->deleteRequest(); - handle = nullHandle(); + llerrs << "LLLFSThread::read called after LLLFSThread::cleanupClass()" << llendl; } return handle; } //============================================================================ -// Runs on its OWN thread - -bool LLLFSThread::processRequest(QueuedRequest* qreq) -{ - Request *req = (Request*)qreq; - - bool complete = req->processIO(); - - return complete; -} - -//============================================================================ -LLLFSThread::Request::Request(handle_t handle, U32 priority, U32 flags, +LLLFSThread::Request::Request(LLLFSThread* thread, + handle_t handle, U32 priority, operation_t op, const LLString& filename, - U8* buffer, S32 offset, S32 numbytes) : - QueuedRequest(handle, priority, flags), + U8* buffer, S32 offset, S32 numbytes, + Responder* responder) : + QueuedRequest(handle, priority, FLAG_AUTO_COMPLETE), + mThread(thread), mOperation(op), mFileName(filename), mBuffer(buffer), mOffset(offset), mBytes(numbytes), - mBytesRead(0) + mBytesRead(0), + mResponder(responder) { - llassert(mBuffer); - - if (numbytes <= 0 && mOperation != FILE_RENAME && mOperation != FILE_REMOVE) + if (numbytes <= 0) { llwarns << "LLLFSThread: Request with numbytes = " << numbytes << llendl; } } -void LLLFSThread::Request::finishRequest() +LLLFSThread::Request::~Request() { } +// virtual, called from own thread +void LLLFSThread::Request::finishRequest(bool completed) +{ + if (mResponder.notNull()) + { + mResponder->completed(completed ? mBytesRead : 0); + mResponder = NULL; + } +} + void LLLFSThread::Request::deleteRequest() { - if (getStatus() == STATUS_QUEUED || getStatus() == STATUS_ABORT) + if (getStatus() == STATUS_QUEUED) { llerrs << "Attempt to delete a queued LLLFSThread::Request!" << llendl; } - if (mOperation == FILE_WRITE) - { - if (mFlags & AUTO_DELETE) - { - delete mBuffer; - } - } - else if (mOperation == FILE_RENAME) + if (mResponder.notNull()) { - LLString* new_name = (LLString*)mBuffer; - delete new_name; + mResponder->completed(0); + mResponder = NULL; } LLQueuedThread::QueuedRequest::deleteRequest(); } -bool LLLFSThread::Request::processIO() +bool LLLFSThread::Request::processRequest() { bool complete = false; if (mOperation == FILE_READ) { llassert(mOffset >= 0); - apr_file_t* filep = ll_apr_file_open(mFileName, LL_APR_RB); + apr_file_t* filep = ll_apr_file_open(mFileName, LL_APR_RB, mThread->mAPRPoolp); if (!filep) { llwarns << "LLLFS: Unable to read file: " << mFileName << llendl; mBytesRead = 0; // fail return true; } + S32 off; if (mOffset < 0) - ll_apr_file_seek(filep, APR_END, 0); + off = ll_apr_file_seek(filep, APR_END, 0); else - ll_apr_file_seek(filep, APR_SET, mOffset); + off = ll_apr_file_seek(filep, APR_SET, mOffset); + llassert_always(off >= 0); mBytesRead = ll_apr_file_read(filep, mBuffer, mBytes ); apr_file_close(filep); complete = true; - //llinfos << llformat("LLLFSThread::READ '%s': %d bytes",mFileName.c_str(),mBytesRead) << llendl; +// llinfos << "LLLFSThread::READ:" << mFileName << " Bytes: " << mBytesRead << llendl; } else if (mOperation == FILE_WRITE) { - apr_file_t* filep = ll_apr_file_open(mFileName, LL_APR_WB); + apr_int32_t flags = APR_CREATE|APR_WRITE|APR_BINARY; + if (mOffset < 0) + flags |= APR_APPEND; + apr_file_t* filep = ll_apr_file_open(mFileName, flags, mThread->mAPRPoolp); if (!filep) { llwarns << "LLLFS: Unable to write file: " << mFileName << llendl; mBytesRead = 0; // fail return true; } - if (mOffset < 0) - ll_apr_file_seek(filep, APR_END, 0); - else - ll_apr_file_seek(filep, APR_SET, mOffset); + if (mOffset >= 0) + { + S32 seek = ll_apr_file_seek(filep, APR_SET, mOffset); + if (seek < 0) + { + apr_file_close(filep); + llwarns << "LLLFS: Unable to write file (seek failed): " << mFileName << llendl; + mBytesRead = 0; // fail + return true; + } + } mBytesRead = ll_apr_file_write(filep, mBuffer, mBytes ); complete = true; apr_file_close(filep); - //llinfos << llformat("LLLFSThread::WRITE '%s': %d bytes",mFileName.c_str(),mBytesRead) << llendl; - } - else if (mOperation == FILE_RENAME) - { - LLString* new_name = (LLString*)mBuffer; - ll_apr_file_rename(mFileName, *new_name); - complete = true; - //llinfos << llformat("LLLFSThread::RENAME '%s': '%s'",mFileName.c_str(),new_name->c_str()) << llendl; - } - else if (mOperation == FILE_REMOVE) - { - ll_apr_file_remove(mFileName); - complete = true; - //llinfos << llformat("LLLFSThread::REMOVE '%s'",mFileName.c_str()) << llendl; +// llinfos << "LLLFSThread::WRITE:" << mFileName << " Bytes: " << mBytesRead << "/" << mBytes << " Offset:" << mOffset << llendl; } else { - llerrs << llformat("LLLFSThread::unknown operation: %d", mOperation) << llendl; + llerrs << "LLLFSThread::unknown operation: " << (S32)mOperation << llendl; } return complete; } //============================================================================ + +LLLFSThread::Responder::~Responder() +{ +} + +//============================================================================ diff --git a/indra/llvfs/lllfsthread.h b/indra/llvfs/lllfsthread.h index 37a6e8bae5..74fd0ffd4d 100644 --- a/indra/llvfs/lllfsthread.h +++ b/indra/llvfs/lllfsthread.h @@ -36,15 +36,24 @@ public: //------------------------------------------------------------------------ public: + class Responder : public LLThreadSafeRefCount + { + public: + virtual ~Responder(); + virtual void completed(S32 bytes) = 0; + }; + class Request : public QueuedRequest { protected: - ~Request() {}; // use deleteRequest() + virtual ~Request(); // use deleteRequest() public: - Request(handle_t handle, U32 priority, U32 flags, + Request(LLLFSThread* thread, + handle_t handle, U32 priority, operation_t op, const LLString& filename, - U8* buffer, S32 offset, S32 numbytes); + U8* buffer, S32 offset, S32 numbytes, + Responder* responder); S32 getBytes() { @@ -67,12 +76,12 @@ public: return mFileName; } - /*virtual*/ void finishRequest(); + /*virtual*/ bool processRequest(); + /*virtual*/ void finishRequest(bool completed); /*virtual*/ void deleteRequest(); - - bool processIO(); private: + LLLFSThread* mThread; operation_t mOperation; LLString mFileName; @@ -80,35 +89,36 @@ public: U8* mBuffer; // dest for reads, source for writes, new UUID for rename S32 mOffset; // offset into file, -1 = append (WRITE only) S32 mBytes; // bytes to read from file, -1 = all - S32 mBytesRead; // bytes read from file + S32 mBytesRead; // bytes read from file + + LLPointer<Responder> mResponder; }; //------------------------------------------------------------------------ public: - LLLFSThread(bool threaded = TRUE, bool runalways = TRUE); + LLLFSThread(bool threaded = TRUE); ~LLLFSThread(); // Return a Request handle handle_t read(const LLString& filename, /* Flawfinder: ignore */ - U8* buffer, S32 offset, S32 numbytes, U32 pri=PRIORITY_NORMAL, U32 flags = 0); + U8* buffer, S32 offset, S32 numbytes, + Responder* responder, U32 pri=0); handle_t write(const LLString& filename, - U8* buffer, S32 offset, S32 numbytes, U32 flags = 0); - handle_t rename(const LLString& filename, const LLString& newname, U32 flags = 0); - handle_t remove(const LLString& filename, U32 flags = 0); + U8* buffer, S32 offset, S32 numbytes, + Responder* responder, U32 pri=0); - // Return number of bytes read - S32 readImmediate(const LLString& filename, - U8* buffer, S32 offset, S32 numbytes); - S32 writeImmediate(const LLString& filename, - U8* buffer, S32 offset, S32 numbytes); - - static void initClass(bool local_is_threaded = TRUE, bool run_always = TRUE); // Setup sLocal + // Misc + U32 priorityCounter() { return mPriorityCounter-- & PRIORITY_LOWBITS; } // Use to order IO operations + + // static initializers + static void initClass(bool local_is_threaded = TRUE); // Setup sLocal static S32 updateClass(U32 ms_elapsed); static void cleanupClass(); // Delete sLocal -protected: - /*virtual*/ bool processRequest(QueuedRequest* req); - + +private: + U32 mPriorityCounter; + public: static LLLFSThread* sLocal; // Default local file thread }; diff --git a/indra/llvfs/llvfile.cpp b/indra/llvfs/llvfile.cpp index a4612233d3..ae45c8fe42 100644 --- a/indra/llvfs/llvfile.cpp +++ b/indra/llvfs/llvfile.cpp @@ -51,12 +51,12 @@ LLVFile::~LLVFile() { if (!(mMode & LLVFile::WRITE)) { - // llwarns << "Destroying LLVFile with pending async read/write, aborting..." << llendl; - sVFSThread->abortRequest(mHandle, LLVFSThread::AUTO_COMPLETE); + //llwarns << "Destroying LLVFile with pending async read/write, aborting..." << llendl; + sVFSThread->setFlags(mHandle, LLVFSThread::FLAG_AUTO_COMPLETE | LLVFSThread::FLAG_ABORT); } else // WRITE { - sVFSThread->setFlags(mHandle, LLVFSThread::AUTO_COMPLETE); + sVFSThread->setFlags(mHandle, LLVFSThread::FLAG_AUTO_COMPLETE); } } } @@ -194,8 +194,8 @@ BOOL LLVFile::write(const U8 *buffer, S32 bytes) S32 offset = -1; mHandle = sVFSThread->write(mVFS, mFileID, mFileType, writebuf, offset, bytes, - LLVFSThread::AUTO_COMPLETE | LLVFSThread::AUTO_DELETE); - mHandle = LLVFSThread::nullHandle(); // AUTO_COMPLETE means we don't track this + LLVFSThread::FLAG_AUTO_COMPLETE | LLVFSThread::FLAG_AUTO_DELETE); + mHandle = LLVFSThread::nullHandle(); // FLAG_AUTO_COMPLETE means we don't track this } else { @@ -304,7 +304,7 @@ BOOL LLVFile::setMaxSize(S32 size) } if (sVFSThread->isPaused()) { - sVFSThread->updateQueue(0); + sVFSThread->update(0); } ms_sleep(10); } @@ -408,7 +408,7 @@ void LLVFile::waitForLock(EVFSLock lock) { if (sVFSThread->isPaused()) { - sVFSThread->updateQueue(0); + sVFSThread->update(0); } ms_sleep(1); } diff --git a/indra/llvfs/llvfs.cpp b/indra/llvfs/llvfs.cpp index 592f74dd02..e4749041ee 100644 --- a/indra/llvfs/llvfs.cpp +++ b/indra/llvfs/llvfs.cpp @@ -771,12 +771,17 @@ BOOL LLVFS::setMaxSize(const LLUUID &file_id, const LLAssetType::EType file_type } // round all sizes upward to KB increments - if (max_size & FILE_BLOCK_MASK) + // SJB: Need to not round for the new texture-pipeline code so we know the correct + // max file size. Need to investigate the potential problems with this... + if (file_type != LLAssetType::AT_TEXTURE) { - max_size += FILE_BLOCK_MASK; - max_size &= ~FILE_BLOCK_MASK; - } - + if (max_size & FILE_BLOCK_MASK) + { + max_size += FILE_BLOCK_MASK; + max_size &= ~FILE_BLOCK_MASK; + } + } + if (block && block->mLength > 0) { block->mAccessTime = (U32)time(NULL); @@ -1998,7 +2003,7 @@ LLString get_extension(LLAssetType::EType type) switch(type) { case LLAssetType::AT_TEXTURE: - extension = ".jp2"; // ".j2c"; // IrfanView recognizes .jp2 -sjb + extension = ".j2c"; break; case LLAssetType::AT_SOUND: extension = ".ogg"; diff --git a/indra/llvfs/llvfsthread.cpp b/indra/llvfs/llvfsthread.cpp index 619c1b9bb3..57cdb7626e 100644 --- a/indra/llvfs/llvfsthread.cpp +++ b/indra/llvfs/llvfsthread.cpp @@ -20,10 +20,10 @@ //============================================================================ // Run on MAIN thread //static -void LLVFSThread::initClass(bool local_is_threaded, bool local_run_always) +void LLVFSThread::initClass(bool local_is_threaded) { llassert(sLocal == NULL); - sLocal = new LLVFSThread(local_is_threaded, local_run_always); + sLocal = new LLVFSThread(local_is_threaded); } //static @@ -47,8 +47,8 @@ void LLVFSThread::cleanupClass() //---------------------------------------------------------------------------- -LLVFSThread::LLVFSThread(bool threaded, bool runalways) : - LLQueuedThread("VFS", threaded, runalways) +LLVFSThread::LLVFSThread(bool threaded) : + LLQueuedThread("VFS", threaded) { } @@ -145,38 +145,26 @@ S32 LLVFSThread::writeImmediate(LLVFS* vfs, const LLUUID &file_id, const LLAsset } -LLVFSThread::handle_t LLVFSThread::rename(LLVFS* vfs, const LLUUID &file_id, const LLAssetType::EType file_type, - const LLUUID &new_id, const LLAssetType::EType new_type, U32 flags) -{ - handle_t handle = generateHandle(); +// LLVFSThread::handle_t LLVFSThread::rename(LLVFS* vfs, const LLUUID &file_id, const LLAssetType::EType file_type, +// const LLUUID &new_id, const LLAssetType::EType new_type, U32 flags) +// { +// handle_t handle = generateHandle(); - LLUUID* new_idp = new LLUUID(new_id); // deleted with Request - // new_type is passed as "numbytes" - Request* req = new Request(handle, 0, flags, FILE_RENAME, vfs, file_id, file_type, - (U8*)new_idp, 0, (S32)new_type); +// LLUUID* new_idp = new LLUUID(new_id); // deleted with Request +// // new_type is passed as "numbytes" +// Request* req = new Request(handle, 0, flags, FILE_RENAME, vfs, file_id, file_type, +// (U8*)new_idp, 0, (S32)new_type); - bool res = addRequest(req); - if (!res) - { - llerrs << "LLVFSThread::read called after LLVFSThread::cleanupClass()" << llendl; - req->deleteRequest(); - handle = nullHandle(); - } +// bool res = addRequest(req); +// if (!res) +// { +// llerrs << "LLVFSThread::read called after LLVFSThread::cleanupClass()" << llendl; +// req->deleteRequest(); +// handle = nullHandle(); +// } - return handle; -} - -//============================================================================ -// Runs on its OWN thread - -bool LLVFSThread::processRequest(QueuedRequest* qreq) -{ - Request *req = (Request*)qreq; - - bool complete = req->processIO(); - - return complete; -} +// return handle; +// } //============================================================================ @@ -223,7 +211,7 @@ LLVFSThread::Request::Request(handle_t handle, U32 priority, U32 flags, } // dec locks as soon as a request finishes -void LLVFSThread::Request::finishRequest() +void LLVFSThread::Request::finishRequest(bool completed) { if (mOperation == FILE_WRITE) { @@ -241,13 +229,13 @@ void LLVFSThread::Request::finishRequest() void LLVFSThread::Request::deleteRequest() { - if (getStatus() == STATUS_QUEUED || getStatus() == STATUS_ABORT) + if (getStatus() == STATUS_QUEUED) { llerrs << "Attempt to delete a queued LLVFSThread::Request!" << llendl; } if (mOperation == FILE_WRITE) { - if (mFlags & AUTO_DELETE) + if (mFlags & FLAG_AUTO_DELETE) { delete [] mBuffer; } @@ -260,7 +248,7 @@ void LLVFSThread::Request::deleteRequest() LLQueuedThread::QueuedRequest::deleteRequest(); } -bool LLVFSThread::Request::processIO() +bool LLVFSThread::Request::processRequest() { bool complete = false; if (mOperation == FILE_READ) @@ -283,7 +271,7 @@ bool LLVFSThread::Request::processIO() mVFS->renameFile(mFileID, mFileType, *new_idp, new_type); mFileID = *new_idp; complete = true; - //llinfos << llformat("LLVFSThread::WRITE '%s': %d bytes arg:%d",getFilename(),mBytesRead) << llendl; + //llinfos << llformat("LLVFSThread::RENAME '%s': %d bytes arg:%d",getFilename(),mBytesRead) << llendl; } else { diff --git a/indra/llvfs/llvfsthread.h b/indra/llvfs/llvfsthread.h index 6839338813..ea7c5123b0 100644 --- a/indra/llvfs/llvfsthread.h +++ b/indra/llvfs/llvfsthread.h @@ -69,10 +69,9 @@ public: return std::string(tbuf); } - /*virtual*/ void finishRequest(); + /*virtual*/ bool processRequest(); + /*virtual*/ void finishRequest(bool completed); /*virtual*/ void deleteRequest(); - - bool processIO(); private: operation_t mOperation; @@ -90,10 +89,10 @@ public: //------------------------------------------------------------------------ public: static std::string sDataPath; - static void setDataPath(const std::string& path) { sDataPath = path; } + static LLVFSThread* sLocal; // Default worker thread public: - LLVFSThread(bool threaded = TRUE, bool runalways = TRUE); + LLVFSThread(bool threaded = TRUE); ~LLVFSThread(); // Return a Request handle @@ -101,8 +100,9 @@ public: U8* buffer, S32 offset, S32 numbytes, U32 pri=PRIORITY_NORMAL, U32 flags = 0); handle_t write(LLVFS* vfs, const LLUUID &file_id, const LLAssetType::EType file_type, U8* buffer, S32 offset, S32 numbytes, U32 flags); - handle_t rename(LLVFS* vfs, const LLUUID &file_id, const LLAssetType::EType file_type, - const LLUUID &new_id, const LLAssetType::EType new_type, U32 flags); + // SJB: rename seems to have issues, especially when threaded +// handle_t rename(LLVFS* vfs, const LLUUID &file_id, const LLAssetType::EType file_type, +// const LLUUID &new_id, const LLAssetType::EType new_type, U32 flags); // Return number of bytes read S32 readImmediate(LLVFS* vfs, const LLUUID &file_id, const LLAssetType::EType file_type, U8* buffer, S32 offset, S32 numbytes); @@ -111,12 +111,11 @@ public: /*virtual*/ bool processRequest(QueuedRequest* req); - static void initClass(bool local_is_threaded = TRUE, bool run_always = TRUE); // Setup sLocal +public: + static void initClass(bool local_is_threaded = TRUE); // Setup sLocal static S32 updateClass(U32 ms_elapsed); static void cleanupClass(); // Delete sLocal - -public: - static LLVFSThread* sLocal; // Default worker thread + static void setDataPath(const std::string& path) { sDataPath = path; } }; //============================================================================ diff --git a/indra/llwindow/llwindow.h b/indra/llwindow/llwindow.h index 442f4c9667..bbe530c906 100644 --- a/indra/llwindow/llwindow.h +++ b/indra/llwindow/llwindow.h @@ -298,6 +298,7 @@ public: // // helper funcs // +extern BOOL gDebugWindowProc; // Protocols, like "http" and "https" we support in URLs extern const S32 gURLProtocolWhitelistCount; diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index a32013a5ee..c18e72b706 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -11,6 +11,7 @@ #include "linden_common.h" #include <Carbon/Carbon.h> +#include <OpenGL/OpenGL.h> #include "llwindowmacosx.h" #include "llkeyboardmacosx.h" @@ -719,6 +720,22 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits } aglSetInteger(mContext, AGL_SWAP_INTERVAL, &frames_per_swap); +#if 0 // SJB: Got a compile error. Plus I don't want to test this along with everything else ; save it for later + //enable multi-threaded OpenGL + CGLError cgl_err; + CGLContextObj ctx = CGLGetCurrentContext(); + + cgl_err = CGLEnable( ctx, kCGLCEMPEngine); + + if (cgl_err != kCGLNoError ) + { + llinfos << "Multi-threaded OpenGL not available." << llendl; + } + else + { + llinfos << "Multi-threaded OpenGL enabled." << llendl; + } +#endif // Don't need to get the current gamma, since there's a call that restores it to the system defaults. return TRUE; } diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index c79a39c513..4efa173fc4 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -55,61 +55,6 @@ void show_window_creation_error(const char* title) { llwarns << title << llendl; shell_open( "help/window_creation_error.html"); - /* - OSMessageBox( - "Second Life is unable to run because it can't set up your display.\n" - "We need to be able to make a 32-bit color window at 1024x768, with\n" - "an 8 bit alpha channel.\n" - "\n" - "First, be sure your monitor is set to True Color (32-bit) in\n" - "Start -> Control Panels -> Display -> Settings.\n" - "\n" - "Otherwise, this may be due to video card driver issues.\n" - "Please make sure you have the latest video card drivers installed.\n" - "ATI drivers are available at http://www.ati.com/\n" - "nVidia drivers are available at http://www.nvidia.com/\n" - "\n" - "If you continue to receive this message, contact customer service.", - title, - OSMB_OK); - */ -} - -BOOL check_for_card(const char* RENDERER, const char* bad_card) -{ - if(bad_card == NULL) - { - return FALSE; - } - if (!strnicmp(RENDERER, bad_card, strlen(bad_card))) /* Flawfinder: ignore */ - { - char buffer[1024]; /* Flawfinder: ignore */ - snprintf(buffer, sizeof(buffer), /* Flawfinder: ignore */ - "Your video card appears to be a %s, which Second Life does not support.\n" - "\n" - "Second Life requires a video card with 32 Mb of memory or more, as well as\n" - "multitexture support. We explicitly support nVidia GeForce 2 or better, \n" - "and ATI Radeon 8500 or better.\n" - "\n" - "If you own a supported card and continue to receive this message, try \n" - "updating to the latest video card drivers. Otherwise look in the\n" - "secondlife.com support section or e-mail technical support\n" - "\n" - "You can try to run Second Life, but it will probably crash or run\n" - "very slowly. Try anyway?", - bad_card); - S32 button = OSMessageBox(buffer, "Unsupported video card", OSMB_YESNO); - if (OSBTN_YES == button) - { - return FALSE; - } - else - { - return TRUE; - } - } - - return FALSE; } //static @@ -132,6 +77,7 @@ LLWindowWin32::LLWindowWin32(char *title, char *name, S32 x, S32 y, S32 width, BOOL ignore_pixel_depth) : LLWindow(fullscreen, flags) { + S32 i = 0; mIconResource = gIconResource; mOverrideAspectRatio = 0.f; mNativeAspectRatio = 0.f; @@ -500,37 +446,6 @@ LLWindowWin32::LLWindowWin32(char *title, char *name, S32 x, S32 y, S32 width, return; } - // Check for some explicitly unsupported cards. - const char* RENDERER = (const char*) glGetString(GL_RENDERER); - - const char* CARD_LIST[] = - { "RAGE 128", - "RIVA TNT2", - "Intel 810", - "3Dfx/Voodoo3", - "Radeon 7000", - "Radeon 7200", - "Radeon 7500", - "Radeon DDR", - "Radeon VE", - "GDI Generic" }; - const S32 CARD_COUNT = sizeof(CARD_LIST)/sizeof(char*); - - // Future candidates: - // ProSavage/Twister - // SuperSavage - - S32 i; - for (i = 0; i < CARD_COUNT; i++) - { - if (check_for_card(RENDERER, CARD_LIST[i])) - { - close(); - shell_open( "help/unsupported_card.html" ); - return; - } - } - gGLManager.initWGL(); if (gGLManager.mHasWGLARBPixelFormat && (wglChoosePixelFormatARB != NULL)) diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h index 0b6fd5157a..ba944ca900 100644 --- a/indra/llwindow/llwindowwin32.h +++ b/indra/llwindow/llwindowwin32.h @@ -182,6 +182,7 @@ private: }; extern LLW32MsgCallback gAsyncMsgCallback; +extern LPWSTR gIconResource; static void handleMessage( const MSG& msg ); diff --git a/indra/llxml/llcontrol.cpp b/indra/llxml/llcontrol.cpp index da6302b27c..2af28f7d2c 100644 --- a/indra/llxml/llcontrol.cpp +++ b/indra/llxml/llcontrol.cpp @@ -113,7 +113,8 @@ void LLControlGroup::cleanup() LLControlBase* LLControlGroup::getControl(const LLString& name) { - return mNameTable[name]; + ctrl_name_table_t::iterator iter = mNameTable.find(name); + return iter == mNameTable.end() ? NULL : (LLControlBase*)iter->second; } BOOL LLControlGroup::declareControl(const LLString& name, eControlType type, const LLSD initial_val, const LLString& comment, BOOL persist) @@ -124,9 +125,11 @@ BOOL LLControlGroup::declareControl(const LLString& name, eControlType type, con LLControl* control = new LLControl(name, type, initial_val, comment, persist); mNameTable[name] = control; return TRUE; - } else + } + else { llwarns << "LLControlGroup::declareControl: Control named " << name << " already exists." << llendl; + mNameTable.erase(name); return FALSE; } } @@ -188,7 +191,7 @@ BOOL LLControlGroup::declareColor3(const LLString& name, const LLColor3 &initial LLSD LLControlGroup::registerListener(const LLString& name, LLSimpleListenerObservable *listener) { - LLControlBase *control = mNameTable[name]; + LLControlBase *control = getControl(name); if (control) { return control->registerListener(listener); @@ -198,7 +201,7 @@ LLSD LLControlGroup::registerListener(const LLString& name, LLSimpleListenerObse BOOL LLControlGroup::getBOOL(const LLString& name) { - LLControlBase* control = mNameTable[name]; + LLControlBase* control = getControl(name); if (control && control->isType(TYPE_BOOLEAN)) return control->get().asBoolean(); @@ -211,7 +214,7 @@ BOOL LLControlGroup::getBOOL(const LLString& name) S32 LLControlGroup::getS32(const LLString& name) { - LLControlBase* control = mNameTable[name]; + LLControlBase* control = getControl(name); if (control && control->isType(TYPE_S32)) return control->get().asInteger(); @@ -224,7 +227,7 @@ S32 LLControlGroup::getS32(const LLString& name) U32 LLControlGroup::getU32(const LLString& name) { - LLControlBase* control = mNameTable[name]; + LLControlBase* control = getControl(name); if (control && control->isType(TYPE_U32)) return control->get().asInteger(); @@ -237,7 +240,7 @@ U32 LLControlGroup::getU32(const LLString& name) F32 LLControlGroup::getF32(const LLString& name) { - LLControlBase* control = mNameTable[name]; + LLControlBase* control = getControl(name); if (control && control->isType(TYPE_F32)) return (F32) control->get().asReal(); @@ -250,7 +253,7 @@ F32 LLControlGroup::getF32(const LLString& name) LLString LLControlGroup::findString(const LLString& name) { - LLControlBase* control = mNameTable[name]; + LLControlBase* control = getControl(name); if (control && control->isType(TYPE_STRING)) return control->get().asString(); @@ -259,7 +262,7 @@ LLString LLControlGroup::findString(const LLString& name) LLString LLControlGroup::getString(const LLString& name) { - LLControlBase* control = mNameTable[name]; + LLControlBase* control = getControl(name); if (control && control->isType(TYPE_STRING)) return control->get().asString(); @@ -285,7 +288,7 @@ LLString LLControlGroup::getText(const LLString& name) LLVector3 LLControlGroup::getVector3(const LLString& name) { - LLControlBase* control = mNameTable[name]; + LLControlBase* control = getControl(name); if (control && control->isType(TYPE_VEC3)) return control->get(); @@ -298,7 +301,7 @@ LLVector3 LLControlGroup::getVector3(const LLString& name) LLVector3d LLControlGroup::getVector3d(const LLString& name) { - LLControlBase* control = mNameTable[name]; + LLControlBase* control = getControl(name); if (control && control->isType(TYPE_VEC3D)) return control->get(); @@ -311,7 +314,7 @@ LLVector3d LLControlGroup::getVector3d(const LLString& name) LLRect LLControlGroup::getRect(const LLString& name) { - LLControlBase* control = mNameTable[name]; + LLControlBase* control = getControl(name); if (control && control->isType(TYPE_RECT)) return control->get(); @@ -357,7 +360,7 @@ LLColor4 LLControlGroup::getColor(const LLString& name) LLColor4U LLControlGroup::getColor4U(const LLString& name) { - LLControlBase* control = mNameTable[name]; + LLControlBase* control = getControl(name); if (control && control->isType(TYPE_COL4U)) return control->get(); @@ -370,7 +373,7 @@ LLColor4U LLControlGroup::getColor4U(const LLString& name) LLColor4 LLControlGroup::getColor4(const LLString& name) { - LLControlBase* control = mNameTable[name]; + LLControlBase* control = getControl(name); if (control && control->isType(TYPE_COL4)) return control->get(); @@ -383,7 +386,7 @@ LLColor4 LLControlGroup::getColor4(const LLString& name) LLColor3 LLControlGroup::getColor3(const LLString& name) { - LLControlBase* control = mNameTable[name]; + LLControlBase* control = getControl(name); if (control && control->isType(TYPE_COL3)) return control->get(); @@ -396,9 +399,8 @@ LLColor3 LLControlGroup::getColor3(const LLString& name) BOOL LLControlGroup::controlExists(const LLString& name) { - void *control = mNameTable[name]; - - return (control != 0); + ctrl_name_table_t::iterator iter = mNameTable.find(name); + return iter != mNameTable.end(); } //------------------------------------------------------------------- @@ -407,7 +409,7 @@ BOOL LLControlGroup::controlExists(const LLString& name) void LLControlGroup::setBOOL(const LLString& name, BOOL val) { - LLControlBase* control = mNameTable[name]; + LLControlBase* control = getControl(name); if (control && control->isType(TYPE_BOOLEAN)) { @@ -422,7 +424,7 @@ void LLControlGroup::setBOOL(const LLString& name, BOOL val) void LLControlGroup::setS32(const LLString& name, S32 val) { - LLControlBase* control = mNameTable[name]; + LLControlBase* control = getControl(name); if (control && control->isType(TYPE_S32)) { @@ -437,7 +439,7 @@ void LLControlGroup::setS32(const LLString& name, S32 val) void LLControlGroup::setF32(const LLString& name, F32 val) { - LLControlBase* control = mNameTable[name]; + LLControlBase* control = getControl(name); if (control && control->isType(TYPE_F32)) { @@ -452,7 +454,7 @@ void LLControlGroup::setF32(const LLString& name, F32 val) void LLControlGroup::setU32(const LLString& name, U32 val) { - LLControlBase* control = mNameTable[name]; + LLControlBase* control = getControl(name); if (control && control->isType(TYPE_U32)) { @@ -467,7 +469,7 @@ void LLControlGroup::setU32(const LLString& name, U32 val) void LLControlGroup::setString(const LLString& name, const LLString &val) { - LLControlBase* control = mNameTable[name]; + LLControlBase* control = getControl(name); if (control && control->isType(TYPE_STRING)) { @@ -482,7 +484,7 @@ void LLControlGroup::setString(const LLString& name, const LLString &val) void LLControlGroup::setVector3(const LLString& name, const LLVector3 &val) { - LLControlBase* control = mNameTable[name]; + LLControlBase* control = getControl(name); if (control && control->isType(TYPE_VEC3)) { @@ -496,7 +498,7 @@ void LLControlGroup::setVector3(const LLString& name, const LLVector3 &val) void LLControlGroup::setVector3d(const LLString& name, const LLVector3d &val) { - LLControlBase* control = mNameTable[name]; + LLControlBase* control = getControl(name); if (control && control->isType(TYPE_VEC3D)) { @@ -510,7 +512,7 @@ void LLControlGroup::setVector3d(const LLString& name, const LLVector3d &val) void LLControlGroup::setRect(const LLString& name, const LLRect &val) { - LLControlBase* control = mNameTable[name]; + LLControlBase* control = getControl(name); if (control && control->isType(TYPE_RECT)) { @@ -524,7 +526,7 @@ void LLControlGroup::setRect(const LLString& name, const LLRect &val) void LLControlGroup::setColor4U(const LLString& name, const LLColor4U &val) { - LLControlBase* control = mNameTable[name]; + LLControlBase* control = getControl(name); if (control && control->isType(TYPE_COL4U)) { @@ -538,7 +540,7 @@ void LLControlGroup::setColor4U(const LLString& name, const LLColor4U &val) void LLControlGroup::setColor4(const LLString& name, const LLColor4 &val) { - LLControlBase* control = mNameTable[name]; + LLControlBase* control = getControl(name); if (control && control->isType(TYPE_COL4)) { @@ -557,7 +559,7 @@ void LLControlGroup::setValue(const LLString& name, const LLSD& val) return; } - LLControlBase* control = mNameTable[name]; + LLControlBase* control = getControl(name); if (control) { @@ -839,7 +841,7 @@ U32 LLControlGroup::loadFromFile(const LLString& filename, BOOL require_declarat { name = child_nodep->getName(); - BOOL declared = (mNameTable[name].notNull()); + BOOL declared = controlExists(name); if (require_declaration && !declared) { @@ -1026,8 +1028,7 @@ U32 LLControlGroup::saveToFile(const LLString& filename, BOOL nondefault_only) break; } - LLControlBase* control = (LLControlBase *)mNameTable[name]; - + LLControlBase* control = (LLControlBase *)iter->second; if (!control) { llwarns << "Tried to save invalid control: " << name << llendl; diff --git a/indra/llxml/llxmlnode.h b/indra/llxml/llxmlnode.h index ca8c1d176f..ae16a9d800 100644 --- a/indra/llxml/llxmlnode.h +++ b/indra/llxml/llxmlnode.h @@ -15,6 +15,7 @@ #include "indra_constants.h" #include "llmemory.h" +#include "llthread.h" #include "llstring.h" #include "llstringtable.h" diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightF.glsl index b2a6d67621..c169fceb88 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightF.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightF.glsl @@ -5,7 +5,7 @@ uniform sampler2D diffuseMap; void default_lighting() { vec4 color = gl_Color * texture2D(diffuseMap, gl_TexCoord[0].xy); - applyScatter(color.rgb); + //applyScatter(color.rgb); gl_FragColor = color; } diff --git a/indra/newview/app_settings/shaders/class1/objects/shinyF.glsl b/indra/newview/app_settings/shaders/class1/objects/shinyF.glsl new file mode 100644 index 0000000000..12c99a6567 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/objects/shinyF.glsl @@ -0,0 +1,13 @@ +void applyScatter(inout vec3 col);
+
+uniform samplerCube environmentMap;
+
+void main()
+{
+ vec3 ref = textureCube(environmentMap, gl_TexCoord[0].xyz).rgb;
+
+ applyScatter(ref);
+
+ gl_FragColor.rgb = ref;
+ gl_FragColor.a = gl_Color.a;
+}
diff --git a/indra/newview/app_settings/shaders/class1/objects/shinyV.glsl b/indra/newview/app_settings/shaders/class1/objects/shinyV.glsl new file mode 100644 index 0000000000..621ff6b5b7 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/objects/shinyV.glsl @@ -0,0 +1,27 @@ +void default_scatter(vec3 viewVec, vec3 lightDir);
+
+uniform vec4 origin;
+
+void main()
+{
+ //transform vertex
+ gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
+
+ vec3 pos = (gl_ModelViewMatrix * gl_Vertex).xyz;
+ vec3 norm = normalize(gl_NormalMatrix * gl_Normal);
+
+ gl_FrontColor = gl_Color;
+
+ vec3 ref = reflect(pos, norm);
+
+ vec3 d = pos - origin.xyz;
+ float dist = dot(normalize(d), ref);
+ vec3 e = d + (ref * max(origin.w-dist, 0.0));
+
+ ref = e - origin.xyz;
+
+ gl_TexCoord[0] = gl_TextureMatrix[0]*vec4(ref,1.0);
+
+ default_scatter(pos.xyz, gl_LightSource[0].position.xyz);
+}
+
diff --git a/indra/newview/app_settings/shaders/class2/lighting/lightF.glsl b/indra/newview/app_settings/shaders/class2/lighting/lightF.glsl index 0ef1129253..6f732ed731 100644 --- a/indra/newview/app_settings/shaders/class2/lighting/lightF.glsl +++ b/indra/newview/app_settings/shaders/class2/lighting/lightF.glsl @@ -5,7 +5,7 @@ uniform sampler2D diffuseMap; void default_lighting() { vec4 color = gl_Color * texture2D(diffuseMap, gl_TexCoord[0].xy); - applyScatter(color.rgb); + //applyScatter(color.rgb); gl_FragColor = color; } diff --git a/indra/newview/app_settings/viewerart.xml b/indra/newview/app_settings/viewerart.xml index dbd22278a7..1ae2010002 100644 --- a/indra/newview/app_settings/viewerart.xml +++ b/indra/newview/app_settings/viewerart.xml @@ -1,282 +1,4 @@ <settings version = "101"> - <closebox.tga value="47a8c844-cd2a-4b1a-be01-df8b1612fe5d"/> - <close_in_blue.tga value="e5821134-23c0-4bd0-af06-7fa95b9fb01a"/> - <tearoffbox.tga value="74e1a96f-4833-a24d-a1bb-1bce1468b0e7"/> - <tearoff_pressed.tga value="d2524c13-4ba6-af7c-e305-8ac6cc18d86a"/> - <resize_handle_bottom_right_blue.tga value="e3690e25-9690-4f6c-a745-e7dcd885285a"/> - <scrollbutton_up_out_blue.tga value="dad084d7-9a46-452a-b0ff-4b9f1cefdde9"/> - <scrollbutton_up_in_blue.tga value="a93abdf3-27b5-4e22-a8fa-c48216cd2e3a"/> - <scrollbutton_down_out_blue.tga value="b4ecdecf-5c8d-44e7-b882-17a77e88ed55"/> - <scrollbutton_down_in_blue.tga value="d2421bab-2eaf-4863-b8f6-5e4c52519247"/> - <scrollbutton_left_out_blue.tga value="43773e8d-49aa-48e0-80f3-a04715f4677a"/> - <scrollbutton_left_in_blue.tga value="ea137a32-6718-4d05-9c22-7d570d27b2cd"/> - <scrollbutton_right_out_blue.tga value="3d700d19-e708-465d-87f2-46c8c0ee7938"/> - <scrollbutton_right_in_blue.tga value="b749de64-e903-4c3c-ac0b-25fb6fa39cb5"/> - <spin_up_out_blue.tga value="56576e6e-6710-4e66-89f9-471b59122794"/> - <spin_up_in_blue.tga value="c8450082-96a0-4319-8090-d3ff900b4954"/> - <spin_down_out_blue.tga value="b6d240dd-5602-426f-b606-bbb49a30726d"/> - <spin_down_in_blue.tga value="a985ac71-052f-48e6-9c33-d931c813ac92"/> - <radio_active_false.tga value="7a1ba9b8-1047-4d1e-9cfc-bc478c80b63f"/> - <radio_active_true.tga value="52f09e07-5816-4052-953c-94c6c10479b7"/> - <radio_inactive_false.tga value="90688481-67ff-4af0-be69-4aa084bcad1e"/> - <radio_inactive_true.tga value="1975db39-aa29-4251-aea0-409ac09d414d"/> - <checkbox_enabled_false.tga value="05bb64ee-96fd-4243-b74e-f40a41bc53ba"/> - <checkbox_enabled_true.tga value="cf4a2ed7-1533-4686-9dde-df9a37ddca55"/> - <checkbox_disabled_false.tga value="7d94cb59-32a2-49bf-a516-9e5a2045f9d9"/> - <checkbox_disabled_true.tga value="c817c642-9abd-4236-9287-ae0513fe7d2b"/> - <tab_top_blue.tga value="1ed83f57-41cf-4052-a3b4-2e8bb78d8191"/> - <tab_top_selected_blue.tga value="16d032e8-817b-4368-8a4e-b7b947ae3889"/> - <tab_bottom_blue.tga value="bf0a8779-689b-48c3-bb9a-6af546366ef4"/> - <tab_bottom_selected_blue.tga value="c001d8fd-a869-4b6f-86a1-fdcb106df9c7"/> - <tab_left.tga value="1097dcb3-aef9-8152-f471-431d840ea89e"/> - <tab_left_selected.tga value="bea77041-5835-1661-f298-47e2d32b7a70"/> - <crosshairs.tga value="6e1a3980-bf2d-4274-8970-91e60d85fb52"/> - <move_backward_in.tga value="db11d956-5e7d-4aa5-b39d-7774d339fc5c"/> - <move_backward_out.tga value="3ae8bb18-ed97-4cd3-ae5c-d54bc8479fe7"/> - <move_down_in.tga value="b92a70b9-c841-4c94-b4b3-cee9eb460d48"/> - <move_down_out.tga value="b5abc9fa-9e62-4e03-bc33-82c4c1b6b689"/> - <move_forward_in.tga value="54197a61-f5d1-4c29-95d2-c071d08849cb"/> - <move_forward_out.tga value="a0eb4021-1b20-4a53-892d-8faa9265a6f5"/> - <move_left_in.tga value="724996f5-b956-46f6-9844-4fcfce1d5e83"/> - <move_left_out.tga value="82476321-0374-4c26-9567-521535ab4cd7"/> - <move_right_in.tga value="7eeb57d2-3f37-454d-a729-8b217b8be443"/> - <move_right_out.tga value="1fbe4e60-0607-44d1-a50a-032eff56ae75"/> - <move_turn_left_in.tga value="95463c78-aaa6-464d-892d-3a805b6bb7bf"/> - <move_turn_left_out.tga value="13a93910-6b44-45eb-ad3a-4d1324c59bac"/> - <move_turn_right_in.tga value="5e616d0d-4335-476f-9977-560bccd009da"/> - <move_turn_right_out.tga value="5a44fd04-f52b-4c30-8b00-4a31e27614bd"/> - <move_up_out.tga value="f887146d-829f-4e39-9211-cf872b78f97c"/> - <move_up_in.tga value="49b4b357-e430-4b56-b9e0-05b8759c3c82"/> - <cam_rotate_out.tga value="88745b46-da05-11d5-8ac0-0003477c4611"/> - <cam_rotate_in.tga value="70bf2262-3eed-4996-88ac-076907e8921d"/> - <cam_zoom_out.tga value="bb02e941-cb3b-4dd3-892a-6841b5de6e45"/> - <cam_zoom_plus_in.tga value="c7aefd32-ce13-4242-82cc-2631d44ff9d3"/> - <cam_zoom_minus_in.tga value="deed3f4b-93e9-4183-a3b0-a5a98a6de1bb"/> - <cam_tracking_out.tga value="95c4ea0e-e3c2-4904-b847-7d7676139ebb"/> - <cam_tracking_in.tga value="fe2fc73b-5a64-4a8e-aacc-46fa81faf96a"/> - <direction_arrow.tga value="586383e8-4d9b-4fba-9196-2b5938e79c2c"/> - <minimize.tga value="34c9398d-bb78-4643-9633-46a2fa3e9637"/> - <minimize_inactive.tga value="6e72abba-1378-437f-bf7a-f0c15f3e99a3"/> - <minimize_pressed.tga value="39801651-26cb-4926-af57-7af9352c273c"/> - <restore.tga value="111b39de-8928-4690-b7b2-e17d5c960277"/> - <restore_inactive.tga value="0eafa471-70af-4882-b8c1-40a310929744"/> - <restore_pressed.tga value="90a0ed5c-2e7b-4845-9958-a64a1b30f312"/> - <combobox_arrow.tga value="b31c1335-0e9c-4927-bc90-53277777d9c1"/> - <white.tga value="5748decc-f629-461c-9a36-a35a221fe21f"/> - <darkgray.tga value="267e26d3-e0e1-41b8-91b1-3b337102928d"/> - <lightgray.tga value="c520bf46-cc5d-412b-a60b-9f1bd245189f"/> - <eyes.tga value="6522e74d-1660-4e7f-b601-6f48c1659a77"/> - <hair.tga value="7ca39b4c-bd19-4699-aff7-f93fd03d3e7b"/> - <black.tga value="e2244626-f22f-4839-8123-1e7baddeb659"/> - <close_inactive_blue.tga value="779e4fa3-9b13-f74a-fba9-3886fe9c86ba"/> - <button_disabled_32x128.tga value="f8124d60-2875-c358-7847-2acb63e5400c"/> - <button_enabled_32x128.tga value="d8faf8cb-ee6e-b0b5-abd9-bde873ad3461"/> - <button_enabled_selected_32x128.tga value="1eddba75-b682-110a-104e-6cdcce616a25"/> - <button_anim_play_selected.tga value="119c37bb-24af-45fe-ae11-3a6bc3c85138"/> - <button_anim_pause_selected.tga value="ad65d67a-777b-fbfa-693d-4bdcfca2acca"/> - <button_anim_pause.tga value="db2d9c2d-0bbd-21e2-e83a-103ea2def7a8"/> - <button_anim_play.tga value="2a7f6738-5d82-2ff3-d419-30ed09cbb72b"/> - <button_anim_stop.tga value="e10c9e36-d9f6-c8b4-de96-557dccce9205"/> - <button_anim_stop_selected.tga value="b8c0e0aa-2771-439e-c919-d2f5dad69a1c"/> - <rounded_square.tga value="38ce8b3c-fb30-5c59-9926-bd643613f606"/> - <rounded_square_soft.tga value="4c95e6bc-fe77-9cb4-b58a-909848042c1e"/> - <badge_ok.tga value="211035a7-c313-378d-478c-e80bbd0fde63"/> - <badge_note.tga value="13f6e639-b3f9-28da-a1e6-e990a43052b6"/> - <badge_warn.tga value="0992d4bc-7af8-4a1f-f2e6-e6c4083b066e"/> - <badge_error.tga value="00c50485-8491-ab70-2ea8-43f26fd028e2"/> - <status_money.tga value="5863eb7a-1546-6501-533a-6061f73a36b7"/> - <status_health.tga value="4330e8ce-b39b-1eb8-c2ec-a97c0b3947b5"/> - <status_fly.tga value="0e058115-5b8f-c3d7-dcaa-9623d92885d1"/> - <status_build.tga value="175a6b75-45c9-c2c2-4765-bf37a3909b53"/> - <status_busy.tga value="beb0d821-6725-abdf-032d-1f70cdabde82"/> - <status_scripts.tga value="4cc1afcd-04dd-178f-e074-0f9dc730ab45"/> - <status_buy_currency.tga value="f43a535a-59ac-26e3-84bc-c786735fabe4"/> - <status_buy_currency_pressed.tga value="bfa5be70-37c7-8126-fecd-df55390954d5"/> - <status_buy_land.tga value="1a0edac5-3e50-fc9b-2752-70c1f69cb959"/> - <status_buy_land_pressed.tga value="257647b7-199f-99ff-8be9-f6753289a3aa"/> - <terrain_dirt.tga value="b8d3965a-ad78-bf43-699b-bff8eca6c975"/> - <terrain_grass.tga value="abb783e6-3e93-26c0-248a-247666855da3"/> - <terrain_mountain.tga value="179cdabd-398a-9b6b-1391-4dc333ba321f"/> - <terrain_rock.tga value="beb169c7-11ea-fff2-efe5-0f24dc881df2"/> - <terrain_dirt_detail.tga value="0bc58228-74a0-7e83-89bc-5c23464bcec5"/> - <terrain_grass_detail.tga value="63338ede-0037-c4fd-855b-015d77112fc8"/> - <terrain_mountain_detail.tga value="303cd381-8560-7579-23f1-f0a880799740"/> - <terrain_rock_detail.tga value="53a2f406-4895-1d13-d541-d2e3b86bc19c"/> - <square_btn_32x128.tga value="b28df901-6b8d-d31c-7903-4eb9676d4bfc"/> - <square_btn_selected_32x128.tga value="c48c9e95-191b-96d3-08b2-6e8ada58b651"/> - <tree_pine_1.tga value="0187babf-6c0d-5891-ebed-4ecab1426683"/> - <tree_oak.tga value="8a515889-eac9-fb55-8eba-d2dc09eb32c8"/> - <tree_tropical_1.tga value="5bc11cd6-2f40-071e-a8da-0903394204f9"/> - <tree_palm_1.tga value="ca4e8c27-473c-eb1c-2f5d-50ee3f07d85c"/> - <tree_dogwood.tga value="64367bd1-697e-b3e6-0b65-3f862a577366"/> - <tree_tropical_2.tga value="cdd9a9fc-6d0b-f90d-8416-c72b6019bca8"/> - <tree_palm_2.tga value="2d784476-d0db-9979-0cff-9408745a7cf3"/> - <tree_cypress_1.tga value="fb2ae204-3fd1-df33-594f-c9f882830e66"/> - <tree_cypress_2.tga value="30047cec-269d-408e-0c30-b2603b887268"/> - <tree_pine_2.tga value="d691a01c-13b7-578d-57c0-5caef0b4e7e1"/> - <tree_plumeria.tga value="6de37e4e-7029-61f5-54b8-f5e63f983f58"/> - <winter_tree_aspen.tga value="7c0cf89b-44b1-1ce2-dd74-07102a98ac2a"/> - <winter_tree_pine_1.tga value="10d2a01a-0818-84b9-4b96-c2eb63256519"/> - <winter_tree_pine_2.tga value="67931331-0c02-4876-1255-28770896c6a2"/> - <tree_eucalyptus.tga value="a6162133-724b-54df-a12f-51cd070ad6f3"/> - <tree_fern.tga value="8872f2b8-31db-42d8-580a-b3e4a91262de"/> - <tree_eelgrass.tga value="96b4de31-f4fa-337d-ec78-451e3609769e"/> - <tree_sea_sword.tga value="5894e2e7-ab8d-edfa-e61c-18cf16854ba3"/> - <tree_kelp_1.tga value="2caf1179-7861-6ff3-4b7d-46e17780bdfa"/> - <tree_kelp_2.tga value="2a4880b6-b7a3-690a-2049-bfbe38eafb9f"/> - <tree_beach_grass_1.tga value="18fb888b-e8f1-dce7-7da7-321d651ea6b0"/> - <tool_dozer.tga value="d2a0d4d4-54eb-4d16-be4b-4eae43845c74"/> - <tool_dozer_active.tga value="d4afdbbe-1550-4b7d-91de-95731f47e8e3"/> - <tool_land.tga value="86fe4df4-0ecb-4382-b9ae-475925a92388"/> - <tool_land_active.tga value="34e60587-0791-4a07-8918-f5995fcc22a3"/> - <tool_zoom.tga value="27eb8829-fe65-45ed-a49a-73aac42f4b38"/> - <tool_zoom_active.tga value="69445f58-5c8e-44e0-9d2e-47408bb43b39"/> - <tool_orbit.tga value="06964fe4-033f-448a-95c9-30dc41d1be8b"/> - <tool_orbit_active.tga value="ee4e07db-3f72-4098-bd4c-aef34515a7bc"/> - <tool_pan.tga value="a32aa302-0a15-48d2-b2b1-4d69f1161173"/> - <tool_pan_active.tga value="24d9ad33-0b42-4eb5-99a3-659d838bc5c0"/> - <inv_folder_texture.tga value="743f035b-a049-43f4-16c7-7ec8daa2c481"/> - <inv_folder_sound.tga value="e10cb910-1e71-da47-bd12-8c53f7793714"/> - <inv_folder_callingcard.tga value="a3735971-e2b2-d78a-580d-d265cd8f2484"/> - <inv_folder_landmark.tga value="9f921155-7c8c-e276-d5ec-03ac9340584d"/> - <inv_folder_script.tga value="baa5c310-6a6d-cc48-51eb-65196ba31d77"/> - <inv_folder_object.tga value="113e5133-fd0d-ee51-4a59-9d67ca10e8a7"/> - <inv_folder_notecard.tga value="a9e75d84-5073-9cb7-10a9-1ca68ef5c7ba"/> - <inv_folder_clothing.tga value="f1427d3d-b2e8-97c4-69ab-1f36d4c0e8f0"/> - <inv_folder_bodypart.tga value="1fe05580-1d2f-0345-b28b-52b6e3a20e5d"/> - <inv_folder_trash.tga value="88ad072e-ea0b-aabd-5ac0-b37862a6eb66"/> - <inv_folder_plain_closed.tga value="86f00960-c3e9-9680-145d-3beffd743e9c"/> - <inv_folder_plain_open.tga value="d15dc243-2d0b-47af-0ce1-ec376464bdc8"/> - <inv_folder_snapshot.tga value="6efe85e7-800f-1843-296c-a5b7adffe091"/> - <inv_folder_lostandfound.tga value="9a371a04-297d-bacf-0d16-5f49753efe1d"/> - <inv_folder_animation.tga value="4d59b3ee-f29d-b912-2bcc-9bb1f8a07ec6"/> - <inv_folder_gesture.tga value="4de9129a-9fc1-d759-d739-364293906ba2"/> - <inv_item_texture.tga value="19f452d7-4eee-9f46-76cc-5497d17f1dd9"/> - <inv_item_sound.tga value="eb414d69-c77d-d4e7-66e6-6c2e6f6c1976"/> - <inv_item_callingcard_online.tga value="672cc53e-8dc0-ba91-2a4e-574104cf071c"/> - <inv_item_callingcard_offline.tga value="d0afe86b-2489-7600-55b7-6abb0a63d9f9"/> - <inv_item_landmark.tga value="bf25a2a0-85da-7fa0-0993-e461768d0221"/> - <inv_item_landmark_visited.tga value="229fac85-5428-4ab7-adeb-eb8389e91092"/> - <inv_item_script.tga value="59a3df81-ed76-06c9-7264-6dada535e7a3"/> - <inv_item_clothing.tga value="34dfe476-8e26-0e3a-11cf-76cc4a7126ce"/> - <inv_item_object.tga value="0f0780a0-89c4-742a-ef28-26405a41cf85"/> - <inv_item_notecard.tga value="23ce8a2c-9ea2-d863-6572-806f0645b0c7"/> - <inv_item_bodypart.tga value="d2a5362d-5c55-57dd-a9e9-5c814d1ddc16"/> - <inv_item_attach.tga value="5bcae41e-aa5d-02f8-edf1-605ebdd875ab"/> - <inv_item_snapshot.tga value="3810d584-b092-7caa-57e0-010f192b9659"/> - <inv_item_eyes.tga value="eaa5fd96-5c25-06ef-2280-7ef20203e167"/> - <inv_item_gloves.tga value="117b11cb-c04e-5081-13da-1a8846070fd0"/> - <inv_item_hair.tga value="6bca3bf4-ed6d-d438-63a0-2a7066d03a0b"/> - <inv_item_jacket.tga value="8df59386-56e0-c811-0443-840da3acb3a5"/> - <inv_item_pants.tga value="a87a58ca-f857-63b1-0acf-072711ed1bdb"/> - <inv_item_shape.tga value="4463e433-4db5-79ef-c1b0-4821b03ddb07"/> - <inv_item_shirt.tga value="e2ffb62b-6abc-22d6-952d-764759b4d636"/> - <inv_item_shoes.tga value="cf384fa5-1edd-c37c-2134-283dd4fe3396"/> - <inv_item_skirt.tga value="0b43f826-2abc-2944-7d72-10777a51d19b"/> - <inv_item_socks.tga value="22137c6d-6ec5-6eee-9a2e-2d7a9e6cbcd4"/> - <inv_item_underpants.tga value="2f15dc09-4385-526c-aa5d-d9d516ec7d99"/> - <inv_item_undershirt.tga value="f72ab629-a3ab-de0c-35c0-5285e27478ce"/> - <inv_item_animation.tga value="b5cda0d6-d196-ce48-63db-d04323ef8931"/> - <inv_item_gesture.tga value="5579245d-d5bf-5f13-46b0-8624490de24c"/> - <pixiesmall.tga value="168e6813-096e-07ea-97ae-fd416826f627"/> - <legend.tga value="ca7609c6-6ec6-32d9-332e-0d8f437ef644"/> - <propertyline.tga value="e3548c46-8d5e-03da-fcab-4fc36ad818bb"/> - <startup_logo.tga value="66864f3c-e095-d9c8-058d-d6575e6ed1b8"/> - <grass_texture_1.tga value="79504bf5-c3ec-0763-6563-d843de66d0a1"/> - <grass_texture_2.tga value="6c4727b8-ac79-ba44-3b81-f9aa887b47eb"/> - <grass_texture_3.tga value="99bd60a2-3250-efc9-2e39-2fbcadefbecc"/> - <grass_texture_4.tga value="7a2b3a4a-53c2-53ac-5716-aac7d743c020"/> - <undergrowth_1.tga value="8f458549-173b-23ff-d4ff-bfaa5ea2371b"/> - <silhouette.tga value="da5d4079-7819-6b53-d2a4-dc9929381d7d"/> - <avatar_thumb_bkgrnd.tga value="3a7f4f0d-be14-ee78-29e3-fc8b0b2a68d3"/> - <missing_asset.tga value="32dfd1c8-7ff6-5909-d983-6d4adfb4255d"/> - <alpha_gradient.tga value="e97cf410-8e61-7005-ec06-629eba4cd1fb"/> - <alpha_gradient_2d.tga value="38b86f85-2575-52a9-a531-23108d8da837"/> - <alpha_noise.tga value="b9e1cf8a-9660-c020-0c69-18f1ea27268a"/> - <alpha_sizzle.tga value="e121e2fc-7573-740f-edfd-0d45a9ba486e"/> - <bump_woodgrain.tga value="058c75c0-a0d5-f2f8-43f3-e9699a89c2fc"/> - <bump_bark.tga value="6c9fa78a-1c69-2168-325b-3e03ffa348ce"/> - <bump_bricks.tga value="b8eed5f0-64b7-6e12-b67f-43fa8e773440"/> - <bump_checker.tga value="9deab416-9c63-78d6-d558-9a156f12044c"/> - <bump_concrete.tga value="db9d39ec-a896-c287-1ced-64566217021e"/> - <bump_crustytile.tga value="f2d7b6f6-4200-1e9a-fd5b-96459e950f94"/> - <bump_cutstone.tga value="d9258671-868f-7511-c321-7baef9e948a4"/> - <bump_discs.tga value="d21e44ca-ff1c-a96e-b2ef-c0753426b7d9"/> - <bump_gravel.tga value="4726f13e-bd07-f2fb-feb0-bfa2ac58ab61"/> - <bump_petridish.tga value="e569711a-27c2-aad4-9246-0c910239a179"/> - <bump_siding.tga value="073c9723-540c-5449-cdd4-0e87fdc159e3"/> - <bump_stonetile.tga value="ae874d1a-93ef-54fb-5fd3-eb0cb156afc0"/> - <bump_stucco.tga value="92e66e00-f56f-598a-7997-048aa64cde18"/> - <bump_suction.tga value="83b77fc6-10b4-63ec-4de7-f40629f238c5"/> - <bump_weave.tga value="735198cf-6ea0-2550-e222-21d3c6a341ae"/> - <icon_avatar_online.tga value="529ed15b-3d41-dcc1-79de-90bf21770b5b"/> - <icon_avatar_offline.tga value="34648c67-5bfb-5790-e05e-8bd6600fd087"/> - <icon_event.tga value="be235ae0-53cf-1d68-b3ae-cf375ed1fb58"/> - <icon_event_mature.tga value="cc090999-1b3e-2e97-7a38-c9f4afd10297"/> - <icon_group.tga value="04237108-a879-5a95-9b0c-b18fd09bc447"/> - <icon_place.tga value="ba0bac4e-815e-14e1-2895-5065b8c703b3"/> - <icon_top_pick.tga value="77ca91a2-4431-aeaf-6249-3dd99c7dd86d"/> - <icon_popular.tga value="bdd47da5-5b5b-c906-37ad-16aaa64f096f"/> - <icon_for_sale.tga value="f20728fd-1670-3771-2293-e0dd3f0bcaab"/> - <icon_auction.tga value="96abf5b1-335c-6b76-61e3-74ada07f3cb8"/> - <icon_land_for_landless.tga value="c421ddf2-b9d7-b373-503c-f4c423f37f1c"/> - <icon_day_cycle.tga value="5b30a285-f1e3-92b1-dcd3-0d07366ced3e"/> - <icon_lock.tga value="9beb8cdd-3dce-53c2-b28e-e1f3bc2ec0a4"/> - <noentrylines.tga value="5d3e196b-fd4d-ada7-e4c1-99f8e9f1cfbf"/> - <noentrypasslines.tga value="ac8f8627-6a30-8da8-d4bd-958668eea7a0"/> - <notify_tip_icon.tga value="74ba3584-58ea-9984-5b76-62d37942ab77"/> - <notify_box_icon.tga value="b2ef2d31-9714-a07b-6ca7-31638166364b"/> - <notify_next.tga value="07d0ea4c-af0c-aad1-dbbf-c24020ff2b80"/> - <map_avatar_you_8.tga value="02fbdc40-5e07-a6e1-228b-58e10f8335b7"/> - <map_avatar_8.tga value="0be58a91-8065-c02b-7a12-2cc14dddbc37"/> - <map_avatar_16.tga value="db0dadd5-026a-88cf-f5c1-523a0a2daa3e"/> - <map_telehub.tga value="bf1b2bb0-13b1-40ae-3354-b1b93761bdb4"/> - <map_infohub.tga value="85b1a79a-7f6c-9df3-4d6c-17b1a4efb55a"/> - <map_home.tga value="ae9b8f5f-03a1-2e71-db77-6eb27a1ba181"/> - <map_event.tga value="6008be5e-9267-2a3a-9798-e81b076c22ca"/> - <map_event_mature.tga value="f9cdba28-a227-d613-2f16-ce06209314ae"/> - <map_track_8.tga value="bfdc7bf6-e2ee-1754-f4df-cc25887714ad"/> - <map_track_16.tga value="a3878395-ef00-a0e6-ee9a-f45ed6b9ce59"/> - <object_cone.tga value="c2b8c90a-7dca-26e3-1a63-7aa4a0389cf9"/> - <object_cone_active.tga value="cf69c64b-f19e-e1f3-a586-42fef31a23be"/> - <object_cube.tga value="70c747ac-1de3-a8b9-514d-101753ca6ccb"/> - <object_cube_active.tga value="f9c5e213-1076-7a7d-7889-52388aad2c1a"/> - <object_cylinder.tga value="13e35d95-5f6c-9a91-1766-49dedf9b1267"/> - <object_cylinder_active.tga value="3f3e4932-8412-e2a7-cfe9-92caf5978b1b"/> - <object_grass.tga value="7ca8e672-920b-4653-3970-1abc91abef58"/> - <object_grass_active.tga value="d0fc7cc9-646a-6860-cf7c-1d9e58cd6dab"/> - <object_hemi_cone.tga value="69d5e60c-739a-40b1-b526-84072121e394"/> - <object_hemi_cone_active.tga value="2e0c5435-95bb-1c0d-5da1-42336fb1cfc0"/> - <object_hemi_cylinder.tga value="f4be3e06-24a8-f86e-acc7-7daefc0572b7"/> - <object_hemi_cylinder_active.tga value="67279486-cfc1-3633-de42-85db65db373c"/> - <object_hemi_sphere.tga value="b67251ab-1716-b9fb-f911-967ba3fe027b"/> - <object_hemi_sphere_active.tga value="6c489466-3058-6475-6b1b-e5fc1d49f1f3"/> - <object_pyramid.tga value="9dde8b56-2cc4-a932-b63a-38c3a83221ad"/> - <object_pyramid_active.tga value="e7217b1a-e3d8-e339-d28a-d7714d0b5bee"/> - <object_sphere.tga value="7fa122c0-b994-460e-8636-cdc451d67268"/> - <object_sphere_active.tga value="f2c3bcbc-2904-41a5-1c22-688f176fd1ee"/> - <object_tetrahedron.tga value="e17db404-9fc5-9534-1038-777c82b2771f"/> - <object_tetrahedron_active.tga value="2792ea3b-c052-85fe-d168-a62b2f4e9d7c"/> - <object_tree.tga value="710d1bec-fb33-28f1-e77e-ddbb5b51f5ed"/> - <object_tree_active.tga value="da4835c7-b12a-41dd-11db-dae452f040c2"/> - <object_prism.tga value="02935f3a-dcda-3b42-1874-da89d4c12870"/> - <object_prism_active.tga value="223aac97-bd2f-ec2e-ad45-5641b77c78f9"/> - <object_torus.tga value="19e1f4c9-6aa6-4414-981d-59a1343a6472"/> - <object_torus_active.tga value="ef2bca77-5004-4547-b00a-3b96e463f89f"/> - <object_tube.tga value="7ce81316-a478-480f-961c-435fcbdecaf0"/> - <object_tube_active.tga value="55c3e4d1-cfdc-48a8-af32-a34844b91832"/> - <object_ring_active.tga value="2c955a73-fa31-237b-a4a1-5c8ede3bae50"/> - <object_ring.tga value="a7610e41-4647-16d8-0e0e-85a1211c1596"/> - <container_animation.tga value="c4e657a1-4c86-0159-2da0-32ff948484e6"/> - <container_bodypart.tga value="770cb2df-758d-34d5-36c7-e3de06db5b5d"/> - <container_clothing.tga value="dd90406f-4c8f-a3f9-41df-d562f94f09e0"/> - <container_gesture.tga value="59cd31c0-2791-3c48-f740-f0a36c68653e"/> - <container_landmark.tga value="24c63386-04f7-ce6f-4ff2-dfb215d2e21f"/> - <container_many_things.tga value="849d3292-d9fa-7186-5465-dd7b5fc1ec48"/> - <container_object.tga value="ad887ae1-2bee-f2c9-6786-5599de3c95c4"/> - <container_script.tga value="b93bd494-c4bd-bcdf-4a59-35a9497d03f3"/> - <container_sound.tga value="5ddea031-cfa3-2776-43e3-c7146c1b4cd6"/> - <container_texture.tga value="b3f95caf-bd62-bef3-0ded-dea752920629"/> <avatar_aim_l_bow.bvh value="46bb4359-de38-4ed8-6a22-f1f52fe8f506"/> <avatar_aim_r_bazooka.bvh value="b5b4a67d-0aee-30d2-72cd-77b333e932ef"/> <avatar_aim_r_handgun.bvh value="3147d815-6338-b932-f011-16b56d9ac18b"/> @@ -391,114 +113,4 @@ <avatar_yes_happy.bvh value="b8c8b2a3-9008-1771-3bfc-90924955ab2d"/> <avatar_yes_head.bvh value="15dd911d-be82-2856-26db-27659b142875"/> <avatar_yoga_float.bvh value="42ecd00b-9947-a97c-400a-bbc9174c7aeb"/> - <fringe.tga value="8ac54e9d-ec09-d804-60ab-47404a9b4a36"/> - <foot_shadow.tga value="14e8a47d-1055-0a68-5d55-eafd9ad3da5b"/> - <img_smoke_poof.tga value="c734da52-f2ba-f0ba-d59e-15ea49f3d5e9"/> - <img_shot.tga value="173b05c7-53a9-4cf8-ce6b-5eec21c5c63f"/> - <folder_arrow.tga value="09a324a8-acc1-d9cd-2cbd-7465d90d3a98"/> - <color_swatch_alpha.tga value="f13db22f-c55c-8bdf-7b1c-221e56fde253"/> - <script_error.tga value="e5a0ec29-f59e-d29e-2c59-ed66c187c26c"/> - <status_script_debug.tga value="7775b5cc-93a5-6efd-0d9b-4e079afac217"/> - <water_normal.tga value="822ded49-9a6c-f61c-cb89-6df54f42cdf4"/> - <icon_groupnotice.tga value="21579c81-a85e-f11c-2d80-33a4c007d88c"/> - <icon_groupnoticeinventory.tga value="8fcca699-08e7-3d58-2f05-86c9d52bbe82"/> - <tab_background_lightgrey.tga value="c769e547-c307-43ca-2b6a-51cad6d1c527"/> - <tab_background_purple.tga value="0ae8a2e9-aff4-249c-fc4a-0f41f89847dd"/> - <tab_background_darkpurple.tga value="38ff4f7e-3078-a749-8302-d6cc94b404c4"/> - <smicon_warn.tga value="f47c17a3-8bfb-3c9f-22b8-77923de7eed9"/> - <uv_test1.tga value="f43b75f5-9aa5-18ec-d5d9-e6d1b8442613"/> - <uv_test2.tga value="300ce95f-3d3f-7c1a-3a22-3fc48f873fb9"/> - <eye_button_active.tga value="2b42b375-f9b4-788e-46c7-7ef38762d0ba"/> - <eye_button_inactive.tga value="be1b7225-98b5-eb2a-2c86-ddaae3328a6e"/> - <account_id_blue.tga value="6ab9179a-7308-58db-6c9d-893d3b52bece"/> - <account_id_orange.tga value="fbe89371-1251-4e77-d2d8-8eeccffe3ca8"/> - <account_id_green.tga value="3bf64d5a-38d3-b752-cf52-3d9f8fca353a"/> - <status_push.tga value="07d1f523-e327-4d10-20d6-8bc22a6e8f56"/> - <ff_visible_online.tga value="d609a41f-34c0-7aae-b2c6-2fc3ab26d916"/> - <ff_visible_map.tga value="20b52706-c1ab-414a-9dea-1cb788ad5689"/> - <ff_edit_mine.tga value="1baee0b9-4b89-39eb-8815-866d82300ab5"/> - <ff_edit_theirs.tga value="32e981cd-4700-da5a-7fc7-d573ec3742f4"/> - <inv_item_script_dangerous.tga value="0b502db8-6fcd-c442-ecfe-483a0dce875e"/> - <ff_visible_map_button.tga value="c1079bef-5cf9-90f3-6dcd-48989851c252"/> - <ff_visible_online_button.tga value="36749b47-93d6-2c5e-7ebd-d38d30311163"/> - <ff_edit_theirs_button.tga value="ca229f65-d7e0-133e-1bc2-674abc33f3d5"/> - <ff_edit_mine_button.tga value="57f05b46-63d8-c3d5-66d6-8b915746b956"/> - <ff_online_status_button.tga value="3b1b6a53-9c8c-568a-22c5-2a8f3e5286f5"/> - <oi_hud_cen_0_0.tga value="3c650257-9caf-7cad-b26c-84c9eca560f1"/> - <oi_hud_intro.tga value="7611fb3d-9ff2-abd3-d98f-805c1c87e757"/> - <oi_hud_underwater.tga value="cde61aea-83c2-3001-d598-6b348f7a8e0b"/> - <oi_hud_got_passport.tga value="1271838d-d777-b811-7c4c-2a00308bd80a"/> - <oi_hud_texture_off_edge.tga value="852be205-b1ea-6356-58c8-8c5ee5a841a6"/> - <oi_hud_texture_on_edge.tga value="ab11e6ff-a732-be70-67df-c43131274562"/> - <oi_hud_flyingabovewater.tga value="c9d150d6-2739-5f8b-cce6-3cf98242920a"/> - <oi_hud_walkingabovewater.tga value="78284eeb-05f3-ff25-11a0-3cc9dbb30f0c"/> - <oi_hud_landmark.tga value="6cd9c221-9d42-a283-256b-09a113a87271"/> - <oi_hud_cus_5_3.tga value="7c12f4fb-f502-26d1-a2f3-cdb6aff61663"/> - <oi_hud_cus_5_2.tga value="c52c9c94-adc0-0f4e-6658-ed33d6ea8829"/> - <oi_hud_cus_5_1.tga value="9f6d5d11-6ca9-608c-e8a6-b77989350292"/> - <oi_hud_cus_5_0.tga value="2000cff1-119f-2023-66c0-ac5630d2f96e"/> - <oi_hud_cus_4_5.tga value="f302a935-ccd1-e2f5-3a38-e185cc262f3a"/> - <oi_hud_cus_4_3.tga value="af8d5b3c-b40f-cea5-b0b2-440fbd84a11a"/> - <oi_hud_cus_4_2.tga value="11b26901-8207-12bc-5224-10a12ac4c651"/> - <oi_hud_cus_4_1.tga value="41baadb7-1b94-907e-9443-54e92bba77cd"/> - <oi_hud_cus_4_0.tga value="9d627f8e-092c-5d32-6c12-ef76ab81cedc"/> - <oi_hud_cus_3_4.tga value="b196486e-d0d2-4fd7-529a-c84b4495fc74"/> - <oi_hud_cus_3_2.tga value="0b81c4bb-de33-e493-7bcb-e7221d97e5e7"/> - <oi_hud_cus_3_1.tga value="436dab74-25ae-8b60-c648-50663b7faa1d"/> - <oi_hud_cus_3_0.tga value="6c1594de-1e66-273c-a2ab-8f0ffa8b4633"/> - <oi_hud_cus_2_4.tga value="bb31fe48-8566-eec0-e96b-64025f832b63"/> - <oi_hud_cus_2_2.tga value="c946959a-26ae-eb66-efa0-20154057789d"/> - <oi_hud_cus_2_1.tga value="c946959a-26ae-eb66-efa0-20154057789d"/> - <oi_hud_cus_2_0.tga value="d7833106-b4a8-7666-bde1-64886de289f9"/> - <oi_hud_cus_1_0.tga value="811ded22-5940-940c-4821-6fbbfb6611d6"/> - <oi_hud_cus_1_1.tga value="eda8513b-a343-5109-1fd6-f1c7ad89b703"/> - <oi_hud_cus_1_2.tga value="7a4ce18c-e715-34d4-dfee-704c270a8ac8"/> - <oi_hud_cus_1_4.tga value="d3771c15-ac03-b762-b992-d9fd2fedf38a"/> - <oi_hud_com_4_4.tga value="d9e1e90d-3cc3-6269-128e-67f7a2b32d26"/> - <oi_hud_com_4_2.tga value="0f649a26-6fdb-c73b-ffac-e50fc311d5ce"/> - <oi_hud_com_4_1.tga value="ae5b1ce6-a2d2-22d2-f532-6280b3bc6adb"/> - <oi_hud_com_4_0.tga value="12cda3a0-58c7-dfa8-7f9b-380e5bb8baf9"/> - <oi_hud_com_3_4.tga value="ff326257-0530-356a-e0f8-be535044e540"/> - <oi_hud_com_3_2.tga value="66740ddb-1d56-89f9-f0c9-ae5eb7bb9537"/> - <oi_hud_com_3_1.tga value="55d662f4-6a28-6388-7c75-af1c9fd33055"/> - <oi_hud_com_3_0.tga value="de9d318f-b69e-82f9-0c61-43b868c5ca6b"/> - <oi_hud_com_2_4.tga value="01d47e68-400a-d0e1-afb7-d6806d1d477e"/> - <oi_hud_com_2_0.tga value="09c98850-27d4-6a12-abae-4af4bba23b6b"/> - <oi_hud_com_1_3.tga value="5c2049b9-f797-6608-ca71-758f3716aa90"/> - <oi_hud_com_1_1.tga value="1116ff68-cdc4-1cfc-e137-30f8426afeda"/> - <oi_hud_com_1_0.tga value="bd847d31-f5af-95f7-2b9c-af47d8ba53bd"/> - <oi_hud_nav_4_5.tga value="66194280-b087-db94-35d9-41e8f7518515"/> - <oi_hud_nav_4_4.tga value="180c4241-e309-4c05-13ee-9080ab69498d"/> - <oi_hud_nav_4_3.tga value="e98a6ba6-99c6-fa15-84b6-9afadea6c467"/> - <oi_hud_nav_4_2.tga value="2e19f352-1893-59a9-949b-4d2cfd3a8222"/> - <oi_hud_nav_4_1.tga value="13a1675b-fb5a-19b3-b5a3-74b0a6765f7d"/> - <oi_hud_nav_4_0.tga value="e7526e8d-b085-b26c-b0ae-2708ec231401"/> - <oi_hud_nav_3_5.tga value="5e67b0d0-29a2-6a08-c85e-b12d59e53d6e"/> - <oi_hud_nav_3_4.tga value="2ed8fbc2-5c4d-53c2-b289-88baffceab1a"/> - <oi_hud_nav_3_3.tga value="e0a72f1a-282e-1c1a-2cb7-6423feb41759"/> - <oi_hud_nav_3_2.tga value="4bcebb23-da5e-47d9-eac1-e4453f762c8c"/> - <oi_hud_nav_3_1.tga value="6ac87575-330e-3a2d-3b80-a34e7b277e50"/> - <oi_hud_nav_3_0.tga value="f1451e8e-7310-9152-47d5-5d037c28fef3"/> - <oi_hud_nav_2_6.tga value="c60b42ff-ee60-98e4-e603-ca2470141d4b"/> - <oi_hud_nav_2_5.tga value="a02b5a1a-bbdb-5556-ae5b-a2e68494755a"/> - <oi_hud_nav_2_4.tga value="625535ab-8abf-b3e7-48fb-43f728b77c79"/> - <oi_hud_nav_2_3.tga value="00a609c3-5750-3b5a-3ce3-458bdf632203"/> - <oi_hud_nav_2_2.tga value="94903387-d37f-092c-e4d2-c190f68577b8"/> - <oi_hud_nav_2_1.tga value="ee0cd82c-6ce8-8e73-307b-6d0dc77b19e8"/> - <oi_hud_nav_2_0.tga value="3e10b379-ed2c-7424-1fe7-bef3558c7536"/> - <oi_hud_nav_1_4.tga value="bf8d0be8-2012-1664-3ea5-e69a71c206e9"/> - <oi_hud_nav_1_2.tga value="72100f87-18a7-fc4a-4793-de281e8b02cc"/> - <oi_hud_nav_1_1.tga value="b048faf3-60ce-c3a2-d034-36613449d377"/> - <oi_hud_nav_1_0.tga value="0ad45106-3b26-6448-0b90-feae8bd46c38"/> - <oi_hud_mov_4_5.tga value="7c4a45c2-37dd-312c-c6ab-20896dd0a5a6"/> - <oi_hud_mov_4_3.tga value="8a88da1c-3735-c71e-d48a-016df0798de4"/> - <oi_hud_mov_4_2.tga value="f55ae4d3-7d6a-e6ac-4cf7-03014ce14390"/> - <oi_hud_mov_4_1.tga value="1cc3fcf1-35c0-e222-27d2-6905cf5c4cee"/> - <oi_hud_mov_4_0.tga value="1ae592dc-46f4-616e-b7c6-0dff3e6f40e5"/> - <oi_hud_mov_3_4.tga value="831b39be-99fc-45bd-ba85-708f9dc93bfd"/> - <oi_hud_mov_3_2.tga value="9f7e7373-92a9-d66a-ad5a-afb55ca6ac1f"/> - <oi_hud_mov_3_1.tga value="ab37ed0d-7e66-1f77-3acf-b0fe4b74dbe8"/> - <oi_hud_mov_3_0.tga value="f5ff1f08-4c92-8606-1854-cc5b9d3e445c"/> - <oi_hud_mov_1_2.tga value="1e3abeed-e893-c44e-1f9d-5ecc76d21e5d"/> - <oi_hud_mov_1_0.tga value="e300fc95-aa94-8e31-c501-ce903cac8b7c"/> -</settings>
\ No newline at end of file +</settings> diff --git a/indra/newview/featuretable.txt b/indra/newview/featuretable.txt index 3675fc3618..59e816d61b 100644 --- a/indra/newview/featuretable.txt +++ b/indra/newview/featuretable.txt @@ -1,4 +1,4 @@ -version 9 +version 10 // NOTE: This is mostly identical to featuretable_mac.txt with a few differences // Should be combined into one table @@ -23,7 +23,7 @@ version 9 // NOTE: All settings are set to the MIN of applied values, including 'all'! // list all -RenderAGP 1 1 +RenderVBO 1 1 RenderAniso 1 0 RenderAvatarMode 1 2 RenderAvatarVP 1 1 @@ -40,6 +40,7 @@ VertexShaderEnable 1 1 // list Class0 VertexShaderEnable 1 0 +RenderVBO 1 1 RenderDistance 1 64 RenderAvatarVP 1 0 RenderAvatarMode 1 0 @@ -52,6 +53,7 @@ RenderRippleWater 1 0 // list Class1 VertexShaderEnable 1 0 +RenderVBO 1 1 RenderDistance 1 96 RenderAvatarVP 1 1 RenderAvatarMode 1 0 @@ -99,7 +101,7 @@ RenderAvatarVP 0 0 // "Default" setups for safe, low, medium, high // list safe -RenderAGP 1 0 +RenderVBO 1 0 RenderAniso 1 0 RenderAvatarVP 0 0 RenderLighting 1 0 @@ -108,7 +110,7 @@ RenderTerrainDetail 1 0 list low -RenderAGP 1 1 +RenderVBO 1 0 RenderAniso 1 0 RenderLighting 1 0 @@ -135,12 +137,17 @@ RenderObjectBump 0 0 // // Graphics card based feature masks // -list Brookdale +list OpenGLPre15 +RenderVBO 1 0 + +list Intel +RenderVBO 1 0 RenderAniso 1 0 RenderLighting 1 0 RenderTerrainDetail 1 0 list GeForce2 +RenderVBO 1 1 RenderAniso 1 0 RenderLighting 1 0 RenderParticleCount 1 2048 @@ -150,10 +157,7 @@ list GeForce3 list ATI -// Hacked to be paranoid "safe" -// Disable AGP entirely, in Catalyst 4.3 it's at least 50% slower list Radeon8500 -RenderAGP 0 0 RenderLighting 1 0 RenderParticleCount 1 4096 @@ -162,9 +166,8 @@ list Radeon9700 RenderParticleCount 1 4096 // Hacked to be paranoid "safe" -// Disable AGP entirely, in Catalyst 4.3 it's at least 50% slower list MobilityRadeon9000 -RenderLighting 1 0 +RenderLighting 1 0 RenderParticleCount 1 4096 list GeForceFX diff --git a/indra/newview/featuretable_mac.txt b/indra/newview/featuretable_mac.txt index 25228fc999..568a260034 100644 --- a/indra/newview/featuretable_mac.txt +++ b/indra/newview/featuretable_mac.txt @@ -24,7 +24,7 @@ version 9 // // Mac specific: RenderAvatarVP not enabled at all list all -RenderAGP 1 1 +RenderVBO 1 1 RenderAniso 1 0 RenderAvatarMode 1 2 RenderAvatarVP 1 0 @@ -99,7 +99,7 @@ RenderAvatarVP 0 0 // "Default" setups for safe, low, medium, high // list safe -RenderAGP 1 0 +RenderVBO 1 0 RenderAniso 1 0 RenderAvatarVP 0 0 RenderDistance 1 64 @@ -109,7 +109,7 @@ RenderTerrainDetail 1 0 list low -RenderAGP 1 1 +RenderVBO 1 0 RenderAniso 1 0 RenderDistance 1 96 RenderLighting 1 0 @@ -135,6 +135,12 @@ list RAM256MB RenderDistance 1 96 RenderObjectBump 0 0 +// +// Graphics card based feature masks +// +list OpenGLPre15 +RenderVBO 1 0 + // nVidia settings list NVIDIA @@ -146,6 +152,6 @@ RenderParticleCount 1 2048 RenderTerrainDetail 1 0 // -// ATI and AGP now work okay. +// ATI settings // list ATI diff --git a/indra/newview/gpu_table.txt b/indra/newview/gpu_table.txt index fae089486e..92f9b446f8 100644 --- a/indra/newview/gpu_table.txt +++ b/indra/newview/gpu_table.txt @@ -17,11 +17,14 @@ 3Dfx .*3Dfx.* 0 3Dlabs .*3Dlabs.* 0 ATI All-in-Wonder PCI-E .*ATI.*All-in-Wonder.*PCI-E.* 1 +ATI All-in-Wonder X800 .*ATI.*All-in-Wonder X8.* 2 ATI All-in-Wonder X1800 .*ATI.*All-in-Wonder X18.* 3 ATI All-in-Wonder X1900 .*ATI.*All-in-Wonder X19.* 3 -ATI ASUS X1300 .*ATI.*ASUS X13.* 3 -ATI ASUS X1600 .*ATI.*ASUS X16.* 3 -ATI Diamond X1300 .*ATI.*Diamond X13.* 3 +ATI ASUS X1xxx .*ASUS X1.* 3 +ATI Mobility Radeon X1xxx .*ATI.*Mobility.*X1.* 2 +ATI Radeon OpenGL .*ATI.*Radeon OpenGL.* 3 +ATI Diamond X1xxx .*ATI.*Diamond.*X1.* 3 +ATI FireGL 5xxx .*ATI.*FireGL V5.* 3 ATI FireGL .*ATI.*Fire.*GL.* 0 ATI FireMV .*ATI.*FireMV.* 0 ATI Generic .*ATI.*Generic.* 0 @@ -35,14 +38,19 @@ ATI Radeon 9600 .*ATI.*Radeon 96.* 1 ATI Radeon 9700 .*ATI.*Radeon 97.* 1 ATI Radeon 9800 .*ATI.*Radeon 98.* 1 ATI Radeon X1300 .*ATI.*Radeon X13.* 3 +ATI Radeon X1400 .*ATI.*Radeon X14.* 3 +ATI Radeon X1500 .*ATI.*Radeon X15.* 3 ATI Radeon X1600 .*ATI.*Radeon X16.* 3 +ATI Radeon X1700 .*ATI.*Radeon X17.* 3 ATI Radeon X1800 .*ATI.*Radeon X18.* 3 ATI Radeon X1900 .*ATI.*Radeon X19.* 3 ATI Radeon X300 .*ATI.*Radeon X3.* 2 +ATI Radeon X400 .*ATI.*Radeon X4.* 2 ATI Radeon X500 .*ATI.*Radeon X5.* 2 ATI Radeon X600 .*ATI.*Radeon X6.* 2 ATI Radeon X700 .*ATI.*Radeon X7.* 2 ATI Radeon X800 .*ATI.*Radeon X8.* 2 +ATI Radeon X900 .*ATI.*Radeon X9.* 2 ATI Radeon Xpress .*ATI.*Radeon Xpress.* 1 ATI Rage 128 .*ATI.*Rage 128.* 0 Intel 830M .*Intel.*830M 0 @@ -91,7 +99,6 @@ NVIDIA GeForce FX Go5600 .*NVIDIA.*GeForce FX Go56.* 1 NVIDIA GeForce FX Go5700 .*NVIDIA.*GeForce FX Go57.* 1 NVIDIA GeForce FX Go5800 .*NVIDIA.*GeForce FX Go58.* 1 NVIDIA GeForce FX Go5900 .*NVIDIA.*GeForce FX Go59.* 1 -NVIDIA GeForce Go 6 .*GeForce Go 6.* 2 NVIDIA GeForce Go 6100 .*NVIDIA.*GeForce Go 61.* 2 NVIDIA GeForce Go 6200 .*NVIDIA.*GeForce Go 62.* 2 NVIDIA GeForce Go 6500 .*NVIDIA.*GeForce Go 65.* 2 @@ -103,6 +110,7 @@ NVIDIA GeForce Go 7400 .*NVIDIA.*GeForce Go 74.* 3 NVIDIA GeForce Go 7600 .*NVIDIA.*GeForce Go 76.* 3 NVIDIA GeForce Go 7800 .*NVIDIA.*GeForce Go 78.* 3 NVIDIA GeForce Go 7900 .*NVIDIA.*GeForce Go 79.* 3 +NVIDIA GeForce Go 6 .*GeForce Go 6.* 2 NVIDIA GeForce PCX .*GeForce PCX.* 1 NVIDIA Generic .*NVIDIA.*NV.* 0 NVIDIA Generic .*NVIDIA.*Unknown.* 0 diff --git a/indra/newview/linux_tools/wrapper.sh b/indra/newview/linux_tools/wrapper.sh index fd571cacfd..3fd59eb87c 100755 --- a/indra/newview/linux_tools/wrapper.sh +++ b/indra/newview/linux_tools/wrapper.sh @@ -13,8 +13,9 @@ #export LL_BAD_ALSA=x ## - Avoids the optional OpenGL extensions which have proven most problematic -## on some hardware. Disabling this option may cause crashes and hangs on -## some unstable combinations of drivers and hardware. +## on some hardware. Disabling this option may cause BETTER PERFORMANCE but +## may also cause CRASHES and hangs on some unstable combinations of drivers +## and hardware. export LL_GL_BASICEXT=x ## - Avoids *all* optional OpenGL extensions. This is the safest and least- diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 8951d0ef33..07daf89f1c 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -103,7 +103,6 @@ // end Ventrella extern LLMenuBarGL* gMenuBarView; -extern F32 gMinObjectDistance; extern U8 gLastPickAlpha; extern F32 gFrameDTClamped; @@ -3322,7 +3321,7 @@ void LLAgent::updateCamera() attachment; attachment = mAvatarObject->mAttachmentPoints.getNextData()) { - LLViewerObject *attached_object = attachment->getObject(0); + LLViewerObject *attached_object = attachment->getObject(); if (attached_object && !attached_object->isDead() && attached_object->mDrawable.notNull()) { // clear any existing "early" movements of attachment @@ -3432,21 +3431,26 @@ LLVector3d LLAgent::calcFocusPositionTargetGlobal() { LLDrawable* drawablep = mFocusObject->mDrawable; - if (mTrackFocusObject && drawablep && drawablep->isActive()) + if (mTrackFocusObject && + drawablep && + drawablep->isActive()) { - if (mFocusObject->isSelected()) + if (!mFocusObject->isAvatar()) { - gPipeline.updateMoveNormalAsync(drawablep); - } - else - { - if (drawablep->isState(LLDrawable::MOVE_UNDAMPED)) + if (mFocusObject->isSelected()) { gPipeline.updateMoveNormalAsync(drawablep); } else { - gPipeline.updateMoveDampedAsync(drawablep); + if (drawablep->isState(LLDrawable::MOVE_UNDAMPED)) + { + gPipeline.updateMoveNormalAsync(drawablep); + } + else + { + gPipeline.updateMoveDampedAsync(drawablep); + } } } } @@ -3457,11 +3461,6 @@ LLVector3d LLAgent::calcFocusPositionTargetGlobal() } LLVector3 focus_agent = mFocusObject->getRenderPosition() + mFocusObjectOffset; mFocusTargetGlobal.setVec(getPosGlobalFromAgent(focus_agent)); - // *FIX: get camera pointat behavior working - //if (mTrackFocusObject) - //{ - // mCameraFocusOffset = gAgent.getPosGlobalFromAgent(gCamera->getOrigin()) - mFocusTargetGlobal; - //} } return mFocusTargetGlobal; } @@ -3826,8 +3825,6 @@ LLVector3d LLAgent::calcCameraPositionTargetGlobal(BOOL *hit_limit) if (camera_position_global.mdV[VZ] < camera_land_height + camera_min_off_ground) { camera_position_global.mdV[VZ] = camera_land_height + camera_min_off_ground; - - gMinObjectDistance = MIN_NEAR_PLANE; isConstrained = TRUE; } @@ -6572,7 +6569,7 @@ void LLAgent::makeNewOutfit( S32 attachment_pt = attachments_to_include[i]; LLViewerJointAttachment* attachment = mAvatarObject->mAttachmentPoints.getIfThere( attachment_pt ); if(!attachment) continue; - LLViewerObject* attached_object = attachment->getObject(0); + LLViewerObject* attached_object = attachment->getObject(); if(!attached_object) continue; const LLUUID& item_id = attachment->getItemID(); if(item_id.isNull()) continue; @@ -7195,7 +7192,7 @@ void LLAgent::userRemoveAllAttachments( void* userdata ) attachment; attachment = avatarp->mAttachmentPoints.getNextData()) { - LLViewerObject* objectp = attachment->getObject(0); + LLViewerObject* objectp = attachment->getObject(); if (objectp) { gMessageSystem->nextBlockFast(_PREHASH_ObjectData); diff --git a/indra/newview/llcloud.cpp b/indra/newview/llcloud.cpp index cdba49c40d..4548adae91 100644 --- a/indra/newview/llcloud.cpp +++ b/indra/newview/llcloud.cpp @@ -97,16 +97,14 @@ void LLCloudGroup::updatePuffs(const F32 dt) mVOCloudsp->setPositionRegion(mCenterRegion); mVOCloudsp->setScale(LLVector3(256.f/CLOUD_GROUPS_PER_EDGE + CLOUD_PUFF_WIDTH, 256.f/CLOUD_GROUPS_PER_EDGE + CLOUD_PUFF_WIDTH, - CLOUD_HEIGHT_RANGE + CLOUD_PUFF_HEIGHT)); + CLOUD_HEIGHT_RANGE + CLOUD_PUFF_HEIGHT)*0.5f); gPipeline.addObject(mVOCloudsp); } - S32 i; - LLVector3 velocity; LLVector3d vel_d; // Update the positions of all of the clouds - for (i = 0; i < mCloudPuffs.count(); i++) + for (U32 i = 0; i < mCloudPuffs.size(); i++) { LLCloudPuff &puff = mCloudPuffs[i]; velocity = mCloudLayerp->getRegion()->mWind.getCloudVelocity(mCloudLayerp->getRegion()->getPosRegionFromGlobal(puff.mPositionGlobal)); @@ -121,8 +119,8 @@ void LLCloudGroup::updatePuffs(const F32 dt) void LLCloudGroup::updatePuffOwnership() { - S32 i = 0; - while (i < mCloudPuffs.count()) + U32 i = 0; + while (i < mCloudPuffs.size()) { if (mCloudPuffs[i].getLifeState() == LL_PUFF_DYING) { @@ -146,10 +144,11 @@ void LLCloudGroup::updatePuffOwnership() continue; } //llinfos << "Puff handed off!" << llendl; - LLCloudPuff *puffp = new_cgp->mCloudPuffs.reserve_block(1); - puffp->mPositionGlobal = mCloudPuffs[i].mPositionGlobal; - puffp->mAlpha = mCloudPuffs[i].mAlpha; - mCloudPuffs.remove(i); + LLCloudPuff puff; + puff.mPositionGlobal = mCloudPuffs[i].mPositionGlobal; + puff.mAlpha = mCloudPuffs[i].mAlpha; + mCloudPuffs.erase(mCloudPuffs.begin() + i); + new_cgp->mCloudPuffs.push_back(puff); } //llinfos << "Puff count: " << LLCloudPuff::sPuffCount << llendl; @@ -165,7 +164,7 @@ void LLCloudGroup::updatePuffCount() S32 target_puff_count = llround(CLOUD_DENSITY * mDensity); target_puff_count = llmax(0, target_puff_count); target_puff_count = llmin(CLOUD_COUNT_MAX, target_puff_count); - S32 current_puff_count = mCloudPuffs.count(); + S32 current_puff_count = (S32) mCloudPuffs.size(); // Create a new cloud if we need one if (current_puff_count < target_puff_count) { @@ -186,7 +185,7 @@ void LLCloudGroup::updatePuffCount() // Count the number of live puffs S32 live_puff_count = 0; - for (i = 0; i < mCloudPuffs.count(); i++) + for (i = 0; i < (S32) mCloudPuffs.size(); i++) { if (mCloudPuffs[i].getLifeState() != LL_PUFF_DYING) { @@ -212,12 +211,12 @@ void LLCloudGroup::updatePuffCount() // Remove fully dead puffs i = 0; - while (i < mCloudPuffs.count()) + while (i < (S32) mCloudPuffs.size()) { if (mCloudPuffs[i].isDead()) { //llinfos << "Removing dead puff!" << llendl; - mCloudPuffs.remove(i); + mCloudPuffs.erase(mCloudPuffs.begin() + i); LLCloudPuff::sPuffCount--; } else diff --git a/indra/newview/llcloud.h b/indra/newview/llcloud.h index 06c2b5c9ff..3bb06c818b 100644 --- a/indra/newview/llcloud.h +++ b/indra/newview/llcloud.h @@ -110,7 +110,7 @@ public: BOOL inGroup(const LLCloudPuff &puff) const; F32 getDensity() const { return mDensity; } - S32 getNumPuffs() const { return mCloudPuffs.count(); } + S32 getNumPuffs() const { return (S32) mCloudPuffs.size(); } const LLCloudPuff &getPuff(const S32 i) { return mCloudPuffs[i]; } protected: LLCloudLayer *mCloudLayerp; @@ -118,7 +118,7 @@ protected: F32 mDensity; S32 mTargetPuffCount; - LLDynamicArray<LLCloudPuff> mCloudPuffs; + std::vector<LLCloudPuff> mCloudPuffs; LLPointer<LLVOClouds> mVOCloudsp; }; diff --git a/indra/newview/llcolorswatch.h b/indra/newview/llcolorswatch.h index 020f700dfb..999dce1296 100644 --- a/indra/newview/llcolorswatch.h +++ b/indra/newview/llcolorswatch.h @@ -12,6 +12,7 @@ #include "lluictrl.h" #include "v4color.h" #include "llfloater.h" +#include "llviewerimage.h" // // Classes diff --git a/indra/newview/llcylinder.cpp b/indra/newview/llcylinder.cpp index 1774ff4ccf..579fd61daa 100644 --- a/indra/newview/llcylinder.cpp +++ b/indra/newview/llcylinder.cpp @@ -15,7 +15,7 @@ #include "llmath.h" #include "noise.h" #include "v3math.h" - +#include "llvertexbuffer.h" #include "llgl.h" #include "llglheaders.h" @@ -24,6 +24,10 @@ LLCone gCone; GLUquadricObj* gQuadObj = NULL; +static const GLint SLICES[] = { 30, 20, 12, 6 }; // same as sphere slices +static const GLint STACKS = 2; +static const GLfloat RADIUS = 0.5f; + // draws a cylinder or cone // returns approximate number of triangles required U32 draw_cylinder_side(GLint slices, GLint stacks, GLfloat base_radius, GLfloat top_radius) @@ -87,46 +91,27 @@ U32 draw_cylinder_cap(GLint slices, GLfloat base_radius, BOOL is_top) return triangles; } +void LLCylinder::drawSide(S32 detail) +{ + draw_cylinder_side(SLICES[detail], STACKS, RADIUS, RADIUS); +} -void LLCylinder::prerender() +void LLCylinder::drawTop(S32 detail) { - GLint stacks = 2; - GLfloat radius = 0.5f; - GLint slices[CYLINDER_LEVELS_OF_DETAIL] = { 30, 20, 12, 6 }; // same as sphere slices + draw_cylinder_cap(SLICES[detail], RADIUS, TOP); +} - for (S32 detail = 0; detail < CYLINDER_LEVELS_OF_DETAIL; detail++) - { - mTriangleCount[detail] = 0; - - mDisplayListSide[detail] = glGenLists(1); - glNewList(mDisplayListSide[detail], GL_COMPILE); - mTriangleCount[detail] += draw_cylinder_side( slices[detail], stacks, radius, radius ); - glEndList(); - - mDisplayListTop[detail] = glGenLists(1); - glNewList( mDisplayListTop[detail], GL_COMPILE); - mTriangleCount[detail] += draw_cylinder_cap( slices[detail], radius, TOP ); - glEndList(); - - mDisplayListBottom[detail] = glGenLists(1); - glNewList( mDisplayListBottom[detail], GL_COMPILE); - mTriangleCount[detail] += draw_cylinder_cap( slices[detail], radius, BOTTOM ); - glEndList(); - } +void LLCylinder::drawBottom(S32 detail) +{ + draw_cylinder_cap(SLICES[detail], RADIUS, BOTTOM); } -void LLCylinder::cleanupGL() +void LLCylinder::prerender() { - for (S32 detail = 0; detail < CYLINDER_LEVELS_OF_DETAIL; detail++) - { - glDeleteLists(mDisplayListSide[detail], 1); - mDisplayListSide[detail] = 0; - glDeleteLists(mDisplayListTop[detail], 1); - mDisplayListTop[detail] = 0; - glDeleteLists(mDisplayListBottom[detail], 1); - mDisplayListBottom[detail] = 0; - } +} +void LLCylinder::cleanupGL() +{ if (gQuadObj) { gluDeleteQuadric(gQuadObj); @@ -178,19 +163,21 @@ void LLCylinder::renderface(F32 pixel_area, S32 face) return; } + LLVertexBuffer::unbind(); + switch(face) { case 0: glTranslatef(0.f, 0.f, -0.5f); - glCallList(mDisplayListSide[level_of_detail]); + drawSide(level_of_detail); break; case 1: glTranslatef(0.0f, 0.f, 0.5f); - glCallList(mDisplayListTop[level_of_detail]); + drawTop(level_of_detail); break; case 2: glTranslatef(0.0f, 0.f, -0.5f); - glCallList(mDisplayListBottom[level_of_detail]); + drawBottom(level_of_detail); break; default: llerror("LLCylinder::renderface() fell out of switch", 0); @@ -208,37 +195,10 @@ void LLCylinder::renderface(F32 pixel_area, S32 face) void LLCone::prerender() { - GLint stacks = 2; - GLfloat radius = 0.5f; - GLint slices[CONE_LEVELS_OF_DETAIL] = { 32, 18, 12, 6 }; - - for (S32 detail = 0; detail < CONE_LEVELS_OF_DETAIL; detail++) - { - mTriangleCount[detail] = 0; - - mDisplayListSide[detail] = glGenLists(1); - glNewList(mDisplayListSide[detail], GL_COMPILE); - mTriangleCount[detail] += draw_cylinder_side( slices[detail], stacks, radius, 0.f ); - glEndList(); - - mDisplayListBottom[detail] = glGenLists(1); - glNewList( mDisplayListBottom[detail], GL_COMPILE); - mTriangleCount[detail] += draw_cylinder_cap( slices[detail], radius, BOTTOM ); - glEndList(); - } } void LLCone::cleanupGL() { - for (S32 detail = 0; detail < CYLINDER_LEVELS_OF_DETAIL; detail++) - { - glDeleteLists(mDisplayListSide[detail], 1); - mDisplayListSide[detail] = 0; - - glDeleteLists(mDisplayListBottom[detail], 1); - mDisplayListBottom[detail] = 0; - } - if (gQuadObj) { gluDeleteQuadric(gQuadObj); @@ -246,6 +206,15 @@ void LLCone::cleanupGL() } } +void LLCone::drawSide(S32 detail) +{ + draw_cylinder_side( SLICES[detail], STACKS, RADIUS, 0.f ); +} + +void LLCone::drawBottom(S32 detail) +{ + draw_cylinder_cap( SLICES[detail], RADIUS, BOTTOM ); +} void LLCone::render(S32 level_of_detail) { @@ -263,8 +232,9 @@ void LLCone::render(S32 level_of_detail) // center object at 0 glTranslatef(0.f, 0.f, - height / 2.0f); - glCallList(mDisplayListSide[level_of_detail]); - glCallList(mDisplayListBottom[level_of_detail]); + LLVertexBuffer::unbind(); + drawSide(level_of_detail); + drawBottom(level_of_detail); glMatrixMode(GL_MODELVIEW); glPopMatrix(); @@ -288,15 +258,17 @@ void LLCone::renderface(S32 level_of_detail, S32 face) glMatrixMode(GL_MODELVIEW); glPushMatrix(); + LLVertexBuffer::unbind(); + switch(face) { case 0: glTranslatef(0.f, 0.f, -0.5f); - glCallList(mDisplayListSide[level_of_detail]); + drawSide(level_of_detail); break; case 1: glTranslatef(0.f, 0.f, -0.5f); - glCallList(mDisplayListBottom[level_of_detail]); + drawBottom(level_of_detail); break; default: llerror("LLCylinder::renderface() fell out of switch", 0); diff --git a/indra/newview/llcylinder.h b/indra/newview/llcylinder.h index 9150db4fb1..94f3219607 100644 --- a/indra/newview/llcylinder.h +++ b/indra/newview/llcylinder.h @@ -20,20 +20,15 @@ const S32 CYLINDER_FACES = 3; class LLCylinder { -protected: - U32 mDisplayListSide[CYLINDER_LEVELS_OF_DETAIL]; - U32 mDisplayListTop[CYLINDER_LEVELS_OF_DETAIL]; - U32 mDisplayListBottom[CYLINDER_LEVELS_OF_DETAIL]; - U32 mTriangleCount[CYLINDER_LEVELS_OF_DETAIL]; - public: void prerender(); + void drawTop(S32 detail); + void drawSide(S32 detail); + void drawBottom(S32 detail); void cleanupGL(); void render(F32 pixel_area); void renderface(F32 pixel_area, S32 face); - - U32 getTriangleCount(S32 level_of_detail) { return mTriangleCount[level_of_detail]; } }; @@ -46,20 +41,14 @@ const S32 CONE_LEVELS_OF_DETAIL = 4; const S32 CONE_FACES = 2; class LLCone -{ -protected: - U32 mDisplayListSide[CONE_LEVELS_OF_DETAIL]; - U32 mDisplayListBottom[CONE_LEVELS_OF_DETAIL]; - U32 mTriangleCount[CONE_LEVELS_OF_DETAIL]; - +{ public: void prerender(); void cleanupGL(); - + void drawSide(S32 detail); + void drawBottom(S32 detail); void render(S32 level_of_detail); void renderface(S32 level_of_detail, S32 face); - - U32 getTriangleCount(S32 level_of_detail) { return mTriangleCount[level_of_detail]; } }; extern LLCylinder gCylinder; diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp index c4ee6acb8c..868d61942d 100644 --- a/indra/newview/lldrawable.cpp +++ b/indra/newview/lldrawable.cpp @@ -14,8 +14,6 @@ #include "material_codes.h" // viewer includes -#include "llagparray.h" -#include "llagparray.inl" #include "llcriticaldamp.h" #include "llface.h" #include "lllightconstants.h" @@ -58,6 +56,8 @@ U32 LLDrawable::sNumZombieDrawables = 0; F32 LLDrawable::sCurPixelAngle = 0; LLDynamicArrayPtr<LLPointer<LLDrawable> > LLDrawable::sDeadList; +#define FORCE_INVISIBLE_AREA 16.f + // static void LLDrawable::incrementVisible() { @@ -108,12 +108,11 @@ void LLDrawable::destroy() std::for_each(mFaces.begin(), mFaces.end(), DeletePointer()); mFaces.clear(); - /* - if (!(sNumZombieDrawables % 10)) + + /*if (!(sNumZombieDrawables % 10)) { llinfos << "- Zombie drawables: " << sNumZombieDrawables << llendl; - } - */ + }*/ } void LLDrawable::markDead() @@ -250,7 +249,7 @@ void LLDrawable::removeFace(const S32 i) } #endif -LLFace* LLDrawable::addFace(LLDrawPool *poolp, LLViewerImage *texturep, const BOOL shared_geom) +LLFace* LLDrawable::addFace(LLFacePool *poolp, LLViewerImage *texturep) { LLMemType mt(LLMemType::MTYPE_DRAWABLE); @@ -259,16 +258,12 @@ LLFace* LLDrawable::addFace(LLDrawPool *poolp, LLViewerImage *texturep, const BO if (face) { mFaces.push_back(face); - face->setPool(poolp, texturep); - if (shared_geom) + if (poolp) { - face->setState(LLFace::SHARED_GEOM); - } - else if (!isVisible()) - { - face->setState(LLFace::BACKLIST); + face->setPool(poolp, texturep); } + if (isState(UNLIT)) { face->setState(LLFace::FULLBRIGHT); @@ -277,7 +272,27 @@ LLFace* LLDrawable::addFace(LLDrawPool *poolp, LLViewerImage *texturep, const BO return face; } -void LLDrawable::setNumFaces(const S32 newFaces, LLDrawPool *poolp, LLViewerImage *texturep) +LLFace* LLDrawable::addFace(const LLTextureEntry *te, LLViewerImage *texturep) +{ + LLMemType mt(LLMemType::MTYPE_DRAWABLE); + + LLFace *face = new LLFace(this, mVObjp); + + face->setTEOffset(mFaces.size()); + face->setTexture(texturep); + face->setPoolType(gPipeline.getPoolTypeFromTE(te, texturep)); + mFaces.push_back(face); + + if (isState(UNLIT)) + { + face->setState(LLFace::FULLBRIGHT); + } + + return face; + +} + +void LLDrawable::setNumFaces(const S32 newFaces, LLFacePool *poolp, LLViewerImage *texturep) { if (newFaces == (S32)mFaces.size()) { @@ -298,7 +313,7 @@ void LLDrawable::setNumFaces(const S32 newFaces, LLDrawPool *poolp, LLViewerImag } } -void LLDrawable::setNumFacesFast(const S32 newFaces, LLDrawPool *poolp, LLViewerImage *texturep) +void LLDrawable::setNumFacesFast(const S32 newFaces, LLFacePool *poolp, LLViewerImage *texturep) { if (newFaces <= (S32)mFaces.size() && newFaces >= (S32)mFaces.size()/2) { @@ -353,21 +368,43 @@ void LLDrawable::updateMaterial() void LLDrawable::makeActive() { +#if !LL_RELEASE_FOR_DOWNLOAD + if (mVObjp.notNull()) + { + U32 pcode = mVObjp->getPCode(); + if (pcode == LLViewerObject::LL_VO_WATER || + pcode == LLViewerObject::LL_VO_SURFACE_PATCH || + pcode == LLViewerObject::LL_VO_PART_GROUP || + pcode == LLViewerObject::LL_VO_CLOUDS || + pcode == LLViewerObject::LL_VO_STARS || + pcode == LLViewerObject::LL_VO_GROUND || + pcode == LLViewerObject::LL_VO_SKY) + { + llerrs << "Static viewer object has active drawable!" << llendl; + } + } +#endif + if (!isState(ACTIVE)) // && mGeneration > 0) { setState(ACTIVE); + //parent must be made active first if (!isRoot() && !mParent->isActive()) { mParent->makeActive(); } - + gPipeline.setActive(this, TRUE); //all child objects must also be active for (U32 i = 0; i < getChildCount(); i++) { - getChild(i)->makeActive(); + LLDrawable* drawable = getChild(i); + if (drawable) + { + drawable->makeActive(); + } } if (mVObjp->getPCode() == LL_PCODE_VOLUME) @@ -384,7 +421,15 @@ void LLDrawable::makeActive() gPipeline.markRebuild(this, LLDrawable::REBUILD_VOLUME, TRUE); } } - mQuietCount = 0; + updatePartition(); + if (isRoot()) + { + mQuietCount = 0; + } + else + { + getParent()->mQuietCount = 0; + } } @@ -397,7 +442,7 @@ void LLDrawable::makeStatic() if (mParent.notNull() && mParent->isActive()) { - llerrs << "Drawable became static with active parent!" << llendl; + llwarns << "Drawable becamse static with active parent!" << llendl; } S32 child_count = mVObjp->mChildList.size(); @@ -406,6 +451,10 @@ void LLDrawable::makeStatic() LLDrawable* child_drawable = mVObjp->mChildList[child_num]->mDrawable; if (child_drawable) { + if (child_drawable->getParent() != this) + { + llwarns << "Child drawable has unknown parent." << llendl; + } child_drawable->makeStatic(); } } @@ -422,6 +471,7 @@ void LLDrawable::makeStatic() setSpatialBridge(NULL); } } + updatePartition(); } // Returns "distance" between target destination and resulting xfrom @@ -480,9 +530,8 @@ F32 LLDrawable::updateXform(BOOL undamped) if (scaled >= MIN_INTERPOLATE_DISTANCE_SQUARED) { //scaling requires an immediate rebuild - gPipeline.markRebuild(this, LLDrawable::REBUILD_VOLUME, TRUE); + gPipeline.markRebuild(this, LLDrawable::REBUILD_POSITION, TRUE); } - } else { @@ -498,20 +547,6 @@ F32 LLDrawable::updateXform(BOOL undamped) mXform.updateMatrix(); mCurrentScale = target_scale; - - if (!getVOVolume()) - { - movePartition(); - } - else if (mSpatialBridge) - { - gPipeline.markMoved(mSpatialBridge, FALSE); - } - else - { - //a child prim moved and needs its verts regenerated - gPipeline.markRebuild(this, LLDrawable::REBUILD_VOLUME, TRUE); - } return dist_squared; } @@ -521,11 +556,6 @@ void LLDrawable::setRadius(F32 radius) if (mRadius != radius) { mRadius = radius; - updateBinRadius(); - if (!getVOVolume()) - { - movePartition(); - } } } @@ -554,13 +584,10 @@ void LLDrawable::moveUpdatePipeline(BOOL moved) void LLDrawable::movePartition() { - if (getSpatialGroup() || getVOVolume()) + LLSpatialPartition* part = getSpatialPartition(); + if (part) { - LLSpatialPartition* part = getSpatialPartition(); - if (part) - { - part->move(this, getSpatialGroup()); - } + part->move(this, getSpatialGroup()); } } @@ -606,10 +633,27 @@ BOOL LLDrawable::updateMoveUndamped() } mVObjp->clearChanged(LLXform::MOVED); - + return TRUE; } +void LLDrawable::updatePartition() +{ + if (!getVOVolume()) + { + movePartition(); + } + else if (mSpatialBridge) + { + gPipeline.markMoved(mSpatialBridge, FALSE); + } + else + { + //a child prim moved and needs its verts regenerated + gPipeline.markRebuild(this, LLDrawable::REBUILD_POSITION, TRUE); + } +} + BOOL LLDrawable::updateMoveDamped() { F32 dist_squared = updateXform(FALSE); @@ -635,25 +679,42 @@ BOOL LLDrawable::updateMoveDamped() void LLDrawable::updateDistance(LLCamera& camera) { - if (mVObjp->isHUDAttachment()) - { - mDistanceWRTCamera = 1.0f; - if (sCurVisible % 16 == 0) - { - mVObjp->updateLOD(); - } - return; - } - - LLVector3 pos(getPositionGroup()); - - pos -= camera.getOrigin(); - mDistanceWRTCamera = pos.magVec(); - //switch LOD with the spatial group to avoid artifacts LLSpatialGroup* sg = getSpatialGroup(); + + LLVector3 pos; + if (!sg || sg->changeLOD()) { + LLVOVolume* volume = getVOVolume(); + if (volume) + { + volume->updateRelativeXform(); + pos = LLVector3(0,0,0) * volume->getRelativeXform(); + + for (S32 i = 0; i < getNumFaces(); i++) + { + LLFace* facep = getFace(i); + if (facep->getPoolType() == LLDrawPool::POOL_ALPHA) + { + LLVector3 box = (facep->mExtents[1] - facep->mExtents[0]) * 0.25f; + LLVector3 v = (facep->mCenterLocal-camera.getOrigin()); + LLVector3 at = camera.getAtAxis(); + for (U32 j = 0; j < 3; j++) + { + v.mV[j] -= box.mV[j] * at.mV[j]; + } + facep->mDistance = v * camera.getAtAxis(); + } + } + } + else + { + pos = LLVector3(getPositionGroup()); + } + + pos -= camera.getOrigin(); + mDistanceWRTCamera = llround(pos.magVec(), 0.01f); mVObjp->updateLOD(); } } @@ -668,67 +729,33 @@ void LLDrawable::updateTexture() return; } - // *FIX: this updates textures on all faces in this drawable, not - // just the viewer object we care about - if (mVObjp->getNumTEs()) + if (getNumFaces() != mVObjp->getNumTEs()) + { //drawable is transitioning its face count + return; + } + + if (getVOVolume()) { - // For each face in this drawable, change the drawpool if necessary. - for (S32 i = 0; i < getNumFaces(); i++) + if (!isActive()) + { + gPipeline.markMoved(this); + } + else { - LLFace *facep = mFaces[i]; - U32 pool_type = facep->getPool()->getType(); - - if ((pool_type == LLDrawPool::POOL_SIMPLE) || - (pool_type == LLDrawPool::POOL_ALPHA) || - (pool_type == LLDrawPool::POOL_HUD) || - (pool_type == LLDrawPool::POOL_MEDIA) || - (pool_type == LLDrawPool::POOL_BUMP)) + if (isRoot()) { - LLViewerObject* objp = facep->getViewerObject(); - S32 te_offset = facep->getTEOffset(); - - if (te_offset >= objp->getNumTEs()) // Shouldn't happen - { - llwarns << "TE offsets don't match!" << llendl; - facep->setTEOffset(-1); - continue; - } - - LLDrawPool* poolp = NULL; - LLViewerImage* imagep = (te_offset >= 0) ? objp->getTEImage(te_offset) : facep->getTexture(); - if (facep->isState(LLFace::HUD_RENDER)) - { - poolp = gPipeline.getPool(LLDrawPool::POOL_HUD); - } - else if (te_offset >= 0) - { - // This face actually uses texture entries... - const LLTextureEntry* te = facep->getTextureEntry(); - poolp = LLPipeline::getPoolFromTE(te, imagep); - } - else - { - // No texture entry for this face. - if (!imagep) - { - poolp = gPipeline.getPool(LLDrawPool::POOL_SIMPLE, NULL); - } - else if ((imagep->getComponents() == 4) || (imagep->getComponents() == 2)) - { - poolp = gPipeline.getPool(LLDrawPool::POOL_ALPHA); - } - else - { - poolp = gPipeline.getPool(LLDrawPool::POOL_SIMPLE, imagep); - } - } - facep->setPool(poolp, imagep); + mQuietCount = 0; + } + else + { + getParent()->mQuietCount = 0; } } + + gPipeline.markRebuild(this, LLDrawable::REBUILD_MATERIAL, TRUE); } } - BOOL LLDrawable::updateGeometry(BOOL priority) { llassert(mVObjp.notNull()); @@ -769,12 +796,9 @@ void LLDrawable::shiftPos(const LLVector3 &shift_vector) mXform.setScale(1,1,1); mXform.updateMatrix(); - if (isStatic() || // *FIX: don't know why this is happening, but - // some terrain patches are becoming active - // (earth quake, maybe?) DP - getRenderType() == LLPipeline::RENDER_TYPE_TERRAIN) + if (isStatic()) { - LLStrider<LLVector3> verticesp; + gPipeline.markRebuild(this, LLDrawable::REBUILD_GEOMETRY, TRUE); for (S32 i = 0; i < getNumFaces(); i++) { @@ -783,34 +807,13 @@ void LLDrawable::shiftPos(const LLVector3 &shift_vector) facep->mExtents[0] += shift_vector; facep->mExtents[1] += shift_vector; - if (facep->hasGeometry() && !facep->isState(LLFace::SHARED_GEOM)) + if (facep->hasGeometry()) { - S32 index = facep->getVertices(verticesp); - if (index >= 0) - { - S32 vertex_count = facep->getGeomCount(); - for (S32 j = 0; j < vertex_count; j++) - { - *verticesp += shift_vector; - verticesp++; - } - } + facep->mVertexBuffer = NULL; + facep->mLastVertexBuffer = NULL; } } - } - else - { - // Update the face centers. - for (S32 i = 0; i < getNumFaces(); i++) - { - LLFace *facep = getFace(i); - facep->mCenterAgent += shift_vector; - } - } - - //update spatial extents - if (!getVOVolume() || isStatic()) - { + mExtents[0] += shift_vector; mExtents[1] += shift_vector; mPositionGroup += LLVector3d(shift_vector); @@ -855,6 +858,8 @@ void LLDrawable::updateSpatialExtents() mVObjp->updateSpatialExtents(mExtents[0], mExtents[1]); } + updateBinRadius(); + if (mSpatialBridge.notNull()) { mPositionGroup.setVec(0,0,0); @@ -864,11 +869,14 @@ void LLDrawable::updateSpatialExtents() void LLDrawable::updateBinRadius() { - S32 binLOD = mVObjp ? mVObjp->getLOD() : 2; - static F64 detail_bins[] = { 8, 4, 2, 1 }; - F32 radius = getVOVolume() && isStatic() ? - (mExtents[1]-mExtents[0]).magVec() : getRadius(); - mBinRadius = detail_bins[binLOD] * llmax((F64) radius, (3-binLOD)*0.25); + if (mVObjp.notNull()) + { + mBinRadius = mVObjp->getBinRadius(); + } + else + { + mBinRadius = getRadius()*4.f; + } } void LLDrawable::updateLightSet() @@ -879,6 +887,7 @@ void LLDrawable::updateLightSet() return; } + LLSpatialPartition* part = gPipeline.getSpatialPartition(LLPipeline::PARTITION_VOLUME); LLVOVolume* light = getVOVolume(); if (isLight() && light) { @@ -888,7 +897,7 @@ void LLDrawable::updateLightSet() gPipeline.markRelight(*iter); } mLightSet.clear(); - gPipeline.mObjectPartition->getObjects(getPositionAgent(), light->getLightRadius(), mLightSet); + part->getObjects(getPositionAgent(), light->getLightRadius(), mLightSet); for (drawable_set_t::iterator iter = mLightSet.begin(); iter != mLightSet.end(); iter++) { gPipeline.markRelight(*iter); @@ -898,8 +907,8 @@ void LLDrawable::updateLightSet() { // mLightSet points to nearby lights mLightSet.clear(); - gPipeline.mObjectPartition->getLights(getPositionAgent(), getRadius(), mLightSet); - const U32 max_lights = 16; + part->getLights(getPositionAgent(), getRadius(), mLightSet); + const S32 max_lights = 16; if (mLightSet.size() > max_lights) { typedef std::set<std::pair<F32,LLPointer<LLDrawable> > > sorted_pair_set_t; @@ -1034,28 +1043,28 @@ LLSpatialPartition* LLDrawable::getSpatialPartition() { LLSpatialPartition* retval = NULL; - if (mVObjp->isHUDAttachment()) - { //HUD attachments don't get space partitioned - return NULL; - } - if (!mVObjp || !getVOVolume() || isStatic()) { - retval = gPipeline.mObjectPartition; + retval = gPipeline.getSpatialPartition((LLViewerObject*) mVObjp); } - - //must be an active volume - if (!retval && isRoot()) - { + else if (isRoot()) + { //must be an active volume if (!mSpatialBridge) { - setSpatialBridge(new LLSpatialBridge(this)); + if (mVObjp->isHUDAttachment()) + { + setSpatialBridge(new LLHUDBridge(this)); + } + else + { + setSpatialBridge(new LLVolumeBridge(this)); + } } return mSpatialBridge->asPartition(); } - else if (!retval) + else { retval = getParent()->getSpatialPartition(); } @@ -1069,27 +1078,73 @@ LLSpatialPartition* LLDrawable::getSpatialPartition() return retval; } + +BOOL LLDrawable::isVisible() const +{ + if (mVisible == sCurVisible) + { + return TRUE; + } + + if (isActive()) + { + if (isRoot()) + { + LLSpatialGroup* group = mSpatialBridge.notNull() ? mSpatialBridge->getSpatialGroup() : + getSpatialGroup(); + if (!group || group->isVisible()) + { + mVisible = sCurVisible; + return TRUE; + } + } + else + { + if (getParent()->isVisible()) + { + mVisible = sCurVisible; + return TRUE; + } + } + } + else + { + LLSpatialGroup* group = getSpatialGroup(); + if (!group || group->isVisible()) + { + mVisible = sCurVisible; + return TRUE; + } + } + + return FALSE; +} + //======================================= // Spatial Partition Bridging Drawable //======================================= -LLSpatialBridge::LLSpatialBridge(LLDrawable* root) +LLSpatialBridge::LLSpatialBridge(LLDrawable* root, U32 data_mask) +: LLSpatialPartition(data_mask, FALSE) { mDrawable = root; root->setSpatialBridge(this); - mRenderType = mDrawable->mRenderType; //w00! magic! - + mRenderType = mDrawable->mRenderType; + mDrawableType = mDrawable->mRenderType; + + mPartitionType = LLPipeline::PARTITION_VOLUME; + mOctree->balance(); - gPipeline.mObjectPartition->put(this); + gPipeline.getSpatialPartition(mPartitionType)->put(this); } LLSpatialBridge::~LLSpatialBridge() { if (getSpatialGroup()) { - gPipeline.mObjectPartition->remove(this, getSpatialGroup()); + gPipeline.getSpatialPartition(mPartitionType)->remove(this, getSpatialGroup()); } } @@ -1097,7 +1152,6 @@ void LLSpatialBridge::updateSpatialExtents() { LLSpatialGroup* root = (LLSpatialGroup*) mOctree->getListener(0); - if (mOctree->getChildCount() > 0) { LLFastTimer ftm(LLFastTimer::FTM_CULL_REBOUND); root->rebound(); @@ -1145,6 +1199,9 @@ void LLSpatialBridge::updateSpatialExtents() } } } + + LLVector3 diagonal = newMax - newMin; + mRadius = diagonal.magVec() * 0.5f; mPositionGroup.setVec((newMin + newMax) * 0.5f); updateBinRadius(); @@ -1152,9 +1209,7 @@ void LLSpatialBridge::updateSpatialExtents() void LLSpatialBridge::updateBinRadius() { - F32 rad = ((mExtents[1]-mExtents[0])*0.5f).magVec(); - mBinRadius = llmax(rad, 2.f); - mRadius = rad; + mBinRadius = llmin((F32) mOctree->getSize().mdV[0]*0.5f, 256.f); } LLCamera LLSpatialBridge::transformCamera(LLCamera& camera) @@ -1162,39 +1217,123 @@ LLCamera LLSpatialBridge::transformCamera(LLCamera& camera) LLCamera ret = camera; LLXformMatrix* mat = mDrawable->getXform(); LLVector3 center = LLVector3(0,0,0) * mat->getWorldMatrix(); - //LLQuaternion rotation = LLQuaternion(mat->getWorldMatrix()); + LLQuaternion rotation = LLQuaternion(mat->getWorldMatrix()); - //ret.rotate(~mat->getRotation()); LLVector3 delta = ret.getOrigin() - center; - delta *= ~mat->getRotation(); - ret.setOrigin(delta); + LLQuaternion rot = ~mat->getRotation(); + + delta *= rot; + LLVector3 lookAt = ret.getAtAxis(); + LLVector3 up_axis = ret.getUpAxis(); + LLVector3 left_axis = ret.getLeftAxis(); + lookAt *= rot; + up_axis *= rot; + left_axis *= rot; + + ret.setOrigin(delta); + ret.setAxes(lookAt, left_axis, up_axis); + return ret; } void LLDrawable::setVisible(LLCamera& camera, std::vector<LLDrawable*>* results, BOOL for_select) { mVisible = sCurVisible; + +#if 0 && !LL_RELEASE_FOR_DOWNLOAD + //crazy paranoid rules checking + if (getVOVolume()) + { + if (!isRoot()) + { + if (isActive() && !mParent->isActive()) + { + llerrs << "Active drawable has static parent!" << llendl; + } + + if (isStatic() && !mParent->isStatic()) + { + llerrs << "Static drawable has active parent!" << llendl; + } + + if (mSpatialBridge) + { + llerrs << "Child drawable has spatial bridge!" << llendl; + } + } + else if (isActive() && !mSpatialBridge) + { + llerrs << "Active root drawable has no spatial bridge!" << llendl; + } + else if (isStatic() && mSpatialBridge.notNull()) + { + llerrs << "Static drawable has spatial bridge!" << llendl; + } + } +#endif } +class LLOctreeMarkNotCulled: public LLOctreeTraveler<LLDrawable> +{ +public: + LLCamera* mCamera; + + LLOctreeMarkNotCulled(LLCamera* camera_in) : mCamera(camera_in) { } + + virtual void traverse(const LLOctreeNode<LLDrawable>* node) + { + LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0); + group->clearState(LLSpatialGroup::OCCLUDED | LLSpatialGroup::CULLED); + LLOctreeTraveler<LLDrawable>::traverse(node); + } + + void visit(const LLOctreeState<LLDrawable>* branch) + { + gPipeline.markNotCulled((LLSpatialGroup*) branch->getListener(0), *mCamera, TRUE); + } +}; + void LLSpatialBridge::setVisible(LLCamera& camera_in, std::vector<LLDrawable*>* results, BOOL for_select) { + if (!gPipeline.hasRenderType(mDrawableType)) + { + return; + } + + LLViewerObject *vobj = mDrawable->getVObj(); + if (vobj && vobj->isAttachment() && !vobj->isHUDAttachment()) + { + LLVOAvatar* av; + LLDrawable* parent = mDrawable->getParent(); + + if (parent) + { + av = (LLVOAvatar*) parent->getVObj(); + + if (!av->isVisible()) + { + return; + } + } + } + + + LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0); + group->rebound(); + LLVector3 center = (mExtents[0] + mExtents[1]) * 0.5f; LLVector3 size = (mExtents[1]-mExtents[0]) * 0.5f; if (camera_in.AABBInFrustum(center, size)) { - LLVector3 lookAt = center - camera_in.getOrigin(); - F32 distSqr = lookAt.magVecSquared(); - F32 objRad = size.magVecSquared(); - - if (objRad/distSqr < SG_MIN_DIST_RATIO*4) + if (LLPipeline::calcPixelArea(center, size, camera_in) < FORCE_INVISIBLE_AREA) { return; } LLDrawable::setVisible(camera_in); - + if (for_select) { results->push_back(mDrawable); @@ -1203,42 +1342,36 @@ void LLSpatialBridge::setVisible(LLCamera& camera_in, std::vector<LLDrawable*>* results->push_back(mDrawable->getChild(i)); } } - else + else { - const LLVector3* extents = mDrawable->getSpatialExtents(); - objRad = mDrawable->getRadius(); - objRad *= objRad; - - if (objRad/distSqr > SG_MIN_DIST_RATIO) - { - gPipeline.markNotCulled(mDrawable, camera_in); - } - - for (U32 i = 0; i < mDrawable->getChildCount(); i++) - { - LLDrawable* child = mDrawable->getChild(i); - extents = child->getSpatialExtents(); - objRad = child->getRadius(); - objRad *= objRad; - - if (objRad/distSqr > SG_MIN_DIST_RATIO) - { - gPipeline.markNotCulled(mDrawable->getChild(i), camera_in); - } - } - } + LLCamera trans_camera = transformCamera(camera_in); + LLOctreeMarkNotCulled culler(&trans_camera); + culler.traverse(mOctree); + } } } void LLSpatialBridge::updateDistance(LLCamera& camera_in) { + if (mDrawable == NULL) + { + markDead(); + return; + } + LLCamera camera = transformCamera(camera_in); mDrawable->updateDistance(camera); for (U32 i = 0; i < mDrawable->getChildCount(); ++i) { - mDrawable->getChild(i)->updateDistance(camera); + LLDrawable* child = mDrawable->getChild(i); + if (!child) + { + llwarns << "Corrupt drawable found while updating spatial bridge distance." << llendl; + continue; + } + child->updateDistance(camera); } } @@ -1261,7 +1394,7 @@ void LLSpatialBridge::move(LLDrawable *drawablep, LLSpatialGroup *curp, BOOL imm BOOL LLSpatialBridge::updateMove() { mOctree->balance(); - gPipeline.mObjectPartition->move(this, getSpatialGroup(), TRUE); + gPipeline.getSpatialPartition(mPartitionType)->move(this, getSpatialGroup(), TRUE); return TRUE; } @@ -1319,3 +1452,81 @@ const LLVector3 LLDrawable::getPositionAgent() const } } +BOOL LLDrawable::isAnimating() const +{ + if (!getVObj()) + { + return TRUE; + } + + if (getScale() != mVObjp->getScale()) + { + return TRUE; + } + + if (mVObjp->isFlexible()) + { + return TRUE; + } + + if (mVObjp->getPCode() == LLViewerObject::LL_VO_PART_GROUP) + { + return TRUE; + } + + if (mVObjp->getPCode() == LLViewerObject::LL_VO_CLOUDS) + { + return TRUE; + } + + LLVOVolume* vol = getVOVolume(); + if (vol && vol->mTextureAnimp) + { + return TRUE; + } + + if (!isRoot() && !mVObjp->getAngularVelocity().isExactlyZero()) + { + return TRUE; + } + + return FALSE; +} + +void LLDrawable::updateFaceSize(S32 idx) +{ + if (mVObjp.notNull()) + { + mVObjp->updateFaceSize(idx); + } +} + +LLBridgePartition::LLBridgePartition() +: LLSpatialPartition(0, TRUE) +{ + mRenderByGroup = FALSE; + mDrawableType = LLPipeline::RENDER_TYPE_AVATAR; + mPartitionType = LLPipeline::PARTITION_BRIDGE; + mLODPeriod = 1; + mSlopRatio = 0.f; +} + +LLHUDBridge::LLHUDBridge(LLDrawable* drawablep) +: LLVolumeBridge(drawablep) +{ + mDrawableType = LLPipeline::RENDER_TYPE_HUD; + mPartitionType = LLPipeline::PARTITION_HUD; + mSlopRatio = 0.0f; +} + +F32 LLHUDBridge::calcPixelArea(LLSpatialGroup* group, LLCamera& camera) +{ + return 1024.f; +} + + +void LLHUDBridge::shiftPos(const LLVector3& vec) +{ + //don't shift hud bridges on region crossing +} + diff --git a/indra/newview/lldrawable.h b/indra/newview/lldrawable.h index cb9f970106..fef8b02ad5 100644 --- a/indra/newview/lldrawable.h +++ b/indra/newview/lldrawable.h @@ -19,8 +19,8 @@ #include "v4coloru.h" #include "llquaternion.h" #include "xform.h" +#include "llmemtype.h" #include "llprimitive.h" -#include "llviewerimage.h" #include "lldarray.h" #include "llstat.h" #include "llviewerobject.h" @@ -33,6 +33,7 @@ class LLSpatialGroup; class LLSpatialBridge; class LLSpatialPartition; class LLVOVolume; +class LLViewerImage; extern F32 gFrameTimeSeconds; @@ -55,7 +56,7 @@ public: BOOL isLight() const; - BOOL isVisible() const { return (mVisible == sCurVisible); } + BOOL isVisible() const; virtual void setVisible(LLCamera& camera_in, std::vector<LLDrawable*>* results = NULL, BOOL for_select = FALSE); @@ -102,10 +103,11 @@ public: inline S32 getNumFaces() const; //void removeFace(const S32 i); // SJB: Avoid using this, it's slow - LLFace* addFace(LLDrawPool *poolp, LLViewerImage *texturep, const BOOL shared_geom = FALSE); + LLFace* addFace(LLFacePool *poolp, LLViewerImage *texturep); + LLFace* addFace(const LLTextureEntry *te, LLViewerImage *texturep); void deleteFaces(S32 offset, S32 count); - void setNumFaces(const S32 numFaces, LLDrawPool *poolp, LLViewerImage *texturep); - void setNumFacesFast(const S32 numFaces, LLDrawPool *poolp, LLViewerImage *texturep); + void setNumFaces(const S32 numFaces, LLFacePool *poolp, LLViewerImage *texturep); + void setNumFacesFast(const S32 numFaces, LLFacePool *poolp, LLViewerImage *texturep); void mergeFaces(LLDrawable* src); void init(); @@ -119,6 +121,8 @@ public: BOOL isActive() const { return isState(ACTIVE); } BOOL isStatic() const { return !isActive(); } + BOOL isAnimating() const; + virtual BOOL updateMove(); virtual void movePartition(); @@ -127,6 +131,7 @@ public: virtual void updateDistance(LLCamera& camera); BOOL updateGeometry(BOOL priority); BOOL updateLighting(BOOL priority); + void updateFaceSize(S32 idx); void updateLightSet(); F32 getSunShadowFactor() const { return mSunShadowFactor; } @@ -176,6 +181,7 @@ public: protected: virtual ~LLDrawable() { destroy(); } void moveUpdatePipeline(BOOL moved); + void updatePartition(); BOOL updateMoveDamped(); BOOL updateMoveUndamped(); @@ -187,6 +193,7 @@ public: typedef std::set<LLPointer<LLDrawable> > drawable_set_t; typedef std::vector<LLPointer<LLDrawable> > drawable_vector_t; typedef std::list<LLPointer<LLDrawable> > drawable_list_t; + typedef std::queue<LLPointer<LLDrawable> > drawable_queue_t; struct CompareDistanceGreater { @@ -227,11 +234,14 @@ public: UNLIT = 0x00000200, LIGHT = 0x00000400, LIGHTING_BUILT = 0x00000800, - REBUILD_VOLUME = 0x00001000, - REBUILD_TCOORD = 0x00002000, - REBUILD_GEOMETRY= REBUILD_VOLUME|REBUILD_TCOORD, - REBUILD_LIGHTING= 0x00008000, - REBUILD_ALL = REBUILD_GEOMETRY|REBUILD_LIGHTING, + REBUILD_VOLUME = 0x00001000, //volume changed LOD or parameters, or vertex buffer changed + REBUILD_TCOORD = 0x00002000, //texture coordinates changed + REBUILD_COLOR = 0x00004000, //color changed + REBUILD_LIGHTING= 0x00008000, //lighting information changed + REBUILD_POSITION= 0x00010000, //vertex positions/normals changed + REBUILD_GEOMETRY= REBUILD_POSITION|REBUILD_TCOORD|REBUILD_COLOR, + REBUILD_MATERIAL= REBUILD_TCOORD|REBUILD_COLOR, + REBUILD_ALL = REBUILD_GEOMETRY|REBUILD_LIGHTING|REBUILD_VOLUME, ON_SHIFT_LIST = 0x00100000, // NO_INTERP_COLOR = 0x00200000, BLOCKER = 0x00400000, @@ -266,6 +276,8 @@ public: void setSpatialBridge(LLSpatialBridge* bridge) { mSpatialBridge = (LLDrawable*) bridge; } LLSpatialBridge* getSpatialBridge() { return (LLSpatialBridge*) (LLDrawable*) mSpatialBridge; } + static F32 sCurPixelAngle; //current pixels per radian + protected: typedef std::vector<LLFace*> face_list_t; @@ -277,7 +289,7 @@ protected: LLPointer<LLDrawable> mSpatialBridge; S32 mSpatialGroupOffset; - U32 mVisible; + mutable U32 mVisible; F32 mRadius; LLVector3 mExtents[2]; LLVector3d mPositionGroup; @@ -289,7 +301,6 @@ protected: LLVector3 mCurrentScale; static U32 sCurVisible; // Counter for what value of mVisible means currently visible - static F32 sCurPixelAngle; //current pixels per radian static U32 sNumZombieDrawables; static LLDynamicArrayPtr<LLPointer<LLDrawable> > sDeadList; @@ -299,6 +310,7 @@ protected: inline LLFace* LLDrawable::getFace(const S32 i) const { llassert((U32)i < mFaces.size()); + llassert(mFaces[i]); return mFaces[i]; } diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp index 899d49f380..9ab6c700ab 100644 --- a/indra/newview/lldrawpool.cpp +++ b/indra/newview/lldrawpool.cpp @@ -13,7 +13,6 @@ #include "llfasttimer.h" #include "llviewercontrol.h" -#include "llagparray.h" #include "lldrawable.h" #include "lldrawpoolalpha.h" #include "lldrawpoolavatar.h" @@ -24,53 +23,38 @@ #include "lldrawpoolsky.h" #include "lldrawpoolstars.h" #include "lldrawpooltree.h" -#include "lldrawpooltreenew.h" #include "lldrawpoolterrain.h" #include "lldrawpoolwater.h" -#include "lldrawpoolhud.h" #include "llface.h" #include "llviewerobjectlist.h" // For debug listing. -#include "llvotreenew.h" #include "pipeline.h" -#include "llagparray.inl" - -U32 LLDrawPool::sDataSizes[LLDrawPool::DATA_MAX_TYPES] = -{ - 12, // DATA_VERTICES - 8, // DATA_TEX_COORDS0 - 8, // DATA_TEX_COORDS1 - 8, // DATA_TEX_COORDS2 - 8, // DATA_TEX_COORDS3 - 12, // DATA_NORMALS - 4, // DATA_VERTEX_WEIGHTS, - 16, // DATA_CLOTHING_WEIGHTS - 12, // DATA_BINORMALS - 4, // DATA_COLORS -}; - S32 LLDrawPool::sNumDrawPools = 0; + +//============================= +// Draw Pool Implementation +//============================= LLDrawPool *LLDrawPool::createPool(const U32 type, LLViewerImage *tex0) { LLDrawPool *poolp = NULL; switch (type) { case POOL_SIMPLE: - poolp = new LLDrawPoolSimple(tex0); + poolp = new LLDrawPoolSimple(); break; case POOL_ALPHA: poolp = new LLDrawPoolAlpha(); break; + case POOL_ALPHA_POST_WATER: + poolp = new LLDrawPoolAlphaPostWater(); + break; case POOL_AVATAR: poolp = new LLDrawPoolAvatar(); break; case POOL_TREE: poolp = new LLDrawPoolTree(tex0); break; - case POOL_TREE_NEW: - poolp = new LLDrawPoolTreeNew(tex0); - break; case POOL_TERRAIN: poolp = new LLDrawPoolTerrain(tex0); break; @@ -80,9 +64,6 @@ LLDrawPool *LLDrawPool::createPool(const U32 type, LLViewerImage *tex0) case POOL_STARS: poolp = new LLDrawPoolStars(); break; - case POOL_CLOUDS: - poolp = new LLDrawPoolClouds(); - break; case POOL_WATER: poolp = new LLDrawPoolWater(); break; @@ -90,10 +71,7 @@ LLDrawPool *LLDrawPool::createPool(const U32 type, LLViewerImage *tex0) poolp = new LLDrawPoolGround(); break; case POOL_BUMP: - poolp = new LLDrawPoolBump(tex0); - break; - case POOL_HUD: - poolp = new LLDrawPoolHUD(); + poolp = new LLDrawPoolBump(); break; default: llerrs << "Unknown draw pool type!" << llendl; @@ -104,183 +82,86 @@ LLDrawPool *LLDrawPool::createPool(const U32 type, LLViewerImage *tex0) return poolp; } -LLDrawPool::LLDrawPool(const U32 type, const U32 data_mask_il, const U32 data_mask_nil) +LLDrawPool::LLDrawPool(const U32 type) { - llassert(data_mask_il & DATA_VERTICES_MASK); - S32 i; mType = type; sNumDrawPools++; mId = sNumDrawPools; - - mDataMaskIL = data_mask_il; - mDataMaskNIL = data_mask_nil; - - U32 cur_mask = 0x01; - U32 cur_offset = 0; - for (i = 0; i < DATA_MAX_TYPES; i++) - { - mDataOffsets[i] = cur_offset; - if (cur_mask & mDataMaskIL) - { - cur_offset += sDataSizes[i]; - } - cur_mask <<= 1; - } - - mStride = cur_offset; - - mCleanupUnused = FALSE; + mVertexShaderLevel = 0; mIndicesDrawn = 0; - mRebuildFreq = 128 + rand() % 5; - mRebuildTime = 0; - mGeneration = 1; - mSkippedVertices = 0; - - resetDrawOrders(); - resetVertexData(0); - - if (gGLManager.mHasATIVAO && !gGLManager.mIsRadeon9700) - { - // ATI 8500 doesn't like indices > 15 bit. - mMaxVertices = DEFAULT_MAX_VERTICES/2; - } - else - { - mMaxVertices = DEFAULT_MAX_VERTICES; - } +} - // JC: This must happen last, as setUseAGP reads many of the - // above variables. - mUseAGP = FALSE; - setUseAGP(gPipeline.usingAGP()); +LLDrawPool::~LLDrawPool() +{ - for (i=0; i<NUM_BUCKETS; i++) - { - mFreeListGeomHead[i] = -1; - mFreeListIndHead[i] = -1; - } - mVertexShaderLevel = 0; } -void LLDrawPool::destroy() +LLViewerImage *LLDrawPool::getDebugTexture() { - if (!mReferences.empty()) - { - llinfos << mReferences.size() << " references left on deletion of draw pool!" << llendl; - } + return NULL; } - -LLDrawPool::~LLDrawPool() +//virtual +void LLDrawPool::beginRenderPass( S32 pass ) { - destroy(); - - llassert( gPipeline.findPool( getType(), getTexture() ) == NULL ); } -BOOL LLDrawPool::setUseAGP(BOOL use_agp) +//virtual +void LLDrawPool::endRenderPass( S32 pass ) { - BOOL ok = TRUE; - S32 vertex_count = mMemory.count() / mStride; - if (vertex_count > mMaxVertices && use_agp) - { -#ifdef DEBUG_AGP - llwarns << "Allocating " << vertex_count << " vertices in pool type " << getType() << ", disabling AGP!" << llendl -#endif - use_agp = FALSE; - ok = FALSE; - } - - if (mUseAGP != use_agp) - { - mUseAGP = use_agp; - - BOOL ok = TRUE; - ok &= mMemory.setUseAGP(use_agp); - - if (mDataMaskNIL & DATA_VERTEX_WEIGHTS_MASK) - { - ok &= mWeights.setUseAGP(use_agp); - } - if (mDataMaskNIL & DATA_CLOTHING_WEIGHTS_MASK) - { - ok &= mClothingWeights.setUseAGP(use_agp); - } - - if (!ok) - { - // Disable AGP if any one of these doesn't have AGP, we don't want to try - // mixing AGP and non-agp arrays in a single pool. -#ifdef DEBUG_AGP - llinfos << "Aborting using AGP because set failed on a mem block!" << llendl; -#endif - setUseAGP(FALSE); - ok = FALSE; - } - } - return ok; + glDisableClientState ( GL_TEXTURE_COORD_ARRAY ); + glDisableClientState ( GL_COLOR_ARRAY ); + glDisableClientState ( GL_NORMAL_ARRAY ); } -void LLDrawPool::flushAGP() +U32 LLDrawPool::getTrianglesDrawn() const { - mMemory.flushAGP(); - - if (mDataMaskNIL & DATA_VERTEX_WEIGHTS_MASK) - { - mWeights.flushAGP(); - } - if (mDataMaskNIL & DATA_CLOTHING_WEIGHTS_MASK) - { - mClothingWeights.flushAGP(); - } + return mIndicesDrawn / 3; } -void LLDrawPool::syncAGP() +void LLDrawPool::resetTrianglesDrawn() { - if (!getVertexCount()) - { - return; - } - setUseAGP(gPipeline.usingAGP()); + mIndicesDrawn = 0; +} - BOOL all_agp_on = TRUE; - mMemory.sync(); - all_agp_on &= mMemory.isAGP(); +void LLDrawPool::addIndicesDrawn(const U32 indices) +{ + mIndicesDrawn += indices; +} - if (mDataMaskNIL & DATA_VERTEX_WEIGHTS_MASK) - { - mWeights.sync(); - all_agp_on &= mWeights.isAGP(); - } +//============================= +// Face Pool Implementation +//============================= +LLFacePool::LLFacePool(const U32 type) +: LLDrawPool(type) +{ + resetDrawOrders(); +} - if (mDataMaskNIL & DATA_CLOTHING_WEIGHTS_MASK) - { - mClothingWeights.sync(); - all_agp_on &= mClothingWeights.isAGP(); - } +LLFacePool::~LLFacePool() +{ + destroy(); +} - // Since sometimes AGP allocation is done during syncs, we need - // to make sure that if AGP allocation fails, we fallback to non-agp. - if (mUseAGP && !all_agp_on) +void LLFacePool::destroy() +{ + if (!mReferences.empty()) { -#ifdef DEBUG_AGP - llinfos << "setUseAGP false because of AGP sync failure!" << llendl; -#endif - setUseAGP(FALSE); + llinfos << mReferences.size() << " references left on deletion of draw pool!" << llendl; } } -void LLDrawPool::dirtyTexture(const LLViewerImage *imagep) +void LLFacePool::dirtyTextures(const std::set<LLViewerImage*>& textures) { } -BOOL LLDrawPool::moveFace(LLFace *face, LLDrawPool *poolp, BOOL copy_data) +BOOL LLFacePool::moveFace(LLFace *face, LLDrawPool *poolp, BOOL copy_data) { return TRUE; } // static -S32 LLDrawPool::drawLoop(face_array_t& face_list, const U32* index_array) +S32 LLFacePool::drawLoop(face_array_t& face_list) { S32 res = 0; if (!face_list.empty()) @@ -289,19 +170,15 @@ S32 LLDrawPool::drawLoop(face_array_t& face_list, const U32* index_array) iter != face_list.end(); iter++) { LLFace *facep = *iter; - if (facep->mSkipRender) - { - continue; - } - facep->enableLights(); - res += facep->renderIndexed(index_array); + //facep->enableLights(); + res += facep->renderIndexed(); } } return res; } // static -S32 LLDrawPool::drawLoopSetTex(face_array_t& face_list, const U32* index_array, S32 stage) +S32 LLFacePool::drawLoopSetTex(face_array_t& face_list, S32 stage) { S32 res = 0; if (!face_list.empty()) @@ -310,117 +187,30 @@ S32 LLDrawPool::drawLoopSetTex(face_array_t& face_list, const U32* index_array, iter != face_list.end(); iter++) { LLFace *facep = *iter; - if (facep->mSkipRender) - { - continue; - } facep->bindTexture(stage); facep->enableLights(); - res += facep->renderIndexed(index_array); + res += facep->renderIndexed(); } } return res; } -void LLDrawPool::drawLoop() +void LLFacePool::drawLoop() { - const U32* index_array = getRawIndices(); if (!mDrawFace.empty()) { - mIndicesDrawn += drawLoop(mDrawFace, index_array); + mIndicesDrawn += drawLoop(mDrawFace); } } -BOOL LLDrawPool::getVertexStrider(LLStrider<LLVector3> &vertices, const U32 index) -{ - llassert(mDataMaskIL & LLDrawPool::DATA_VERTICES_MASK); - vertices = (LLVector3*)(mMemory.getMem() + mDataOffsets[DATA_VERTICES] + index * mStride); - vertices.setStride(mStride); - return TRUE; -} - -BOOL LLDrawPool::getTexCoordStrider(LLStrider<LLVector2> &tex_coords, const U32 index, const U32 pass) -{ - llassert(mDataMaskIL & (LLDrawPool::DATA_TEX_COORDS0_MASK << pass)); - tex_coords = (LLVector2*)(mMemory.getMem() + mDataOffsets[DATA_TEX_COORDS0 + pass] + index * mStride); - tex_coords.setStride(mStride); - return TRUE; -} - - -BOOL LLDrawPool::getVertexWeightStrider(LLStrider<F32> &vertex_weights, const U32 index) -{ - llassert(mDataMaskNIL & LLDrawPool::DATA_VERTEX_WEIGHTS_MASK); - - vertex_weights = &mWeights[index]; - vertex_weights.setStride( 0 ); - return TRUE; -} - -BOOL LLDrawPool::getClothingWeightStrider(LLStrider<LLVector4> &clothing_weights, const U32 index) -{ - llassert(mDataMaskNIL & LLDrawPool::DATA_CLOTHING_WEIGHTS_MASK); - - clothing_weights= &mClothingWeights[index]; - clothing_weights.setStride( 0 ); - - return TRUE; -} - -BOOL LLDrawPool::getNormalStrider(LLStrider<LLVector3> &normals, const U32 index) -{ - llassert((mDataMaskIL) & LLDrawPool::DATA_NORMALS_MASK); - - normals = (LLVector3*)(mMemory.getMem() + mDataOffsets[DATA_NORMALS] + index * mStride); - - normals.setStride( mStride ); - - return TRUE; -} - - -BOOL LLDrawPool::getBinormalStrider(LLStrider<LLVector3> &binormals, const U32 index) -{ - llassert((mDataMaskIL) & LLDrawPool::DATA_BINORMALS_MASK); - - binormals = (LLVector3*)(mMemory.getMem() + mDataOffsets[DATA_BINORMALS] + index * mStride); - - binormals.setStride( mStride ); - - return TRUE; -} - -BOOL LLDrawPool::getColorStrider(LLStrider<LLColor4U> &colors, const U32 index) -{ - llassert((mDataMaskIL) & LLDrawPool::DATA_COLORS_MASK); - - colors = (LLColor4U*)(mMemory.getMem() + mDataOffsets[DATA_COLORS] + index * mStride); - - colors.setStride( mStride ); - - return TRUE; -} - -//virtual -void LLDrawPool::beginRenderPass( S32 pass ) -{ -} - -//virtual -void LLDrawPool::endRenderPass( S32 pass ) -{ - glDisableClientState ( GL_TEXTURE_COORD_ARRAY ); - glDisableClientState ( GL_COLOR_ARRAY ); - glDisableClientState ( GL_NORMAL_ARRAY ); -} -void LLDrawPool::renderFaceSelected(LLFace *facep, +void LLFacePool::renderFaceSelected(LLFace *facep, LLImageGL *image, const LLColor4 &color, const S32 index_offset, const S32 index_count) { } -void LLDrawPool::renderVisibility() +void LLFacePool::renderVisibility() { if (mDrawFace.empty()) { @@ -506,893 +296,284 @@ void LLDrawPool::renderVisibility() } -void LLDrawPool::enqueue(LLFace* facep) -{ - if (facep->isState(LLFace::BACKLIST)) - { - mMoveFace.put(facep); - } - else - { -#if ENABLE_FACE_LINKING - facep->mSkipRender = FALSE; - facep->mNextFace = NULL; - - if (mDrawFace.size() > 0) - { - LLFace* last_face = mDrawFace[mDrawFace.size()-1]; - if (match(last_face, facep)) - { - last_face->link(facep); - } - } -#endif - mDrawFace.put(facep); - } -} - -void LLDrawPool::bindGLVertexPointer() -{ - mMemory.bindGLVertexPointer(getStride(DATA_VERTICES), mDataOffsets[DATA_VERTICES]); -} - -void LLDrawPool::bindGLTexCoordPointer(const U32 pass) -{ - mMemory.bindGLTexCoordPointer(getStride(DATA_TEX_COORDS0+pass), mDataOffsets[DATA_TEX_COORDS0+pass]); -} - -void LLDrawPool::bindGLNormalPointer() -{ - mMemory.bindGLNormalPointer(getStride(DATA_NORMALS), mDataOffsets[DATA_NORMALS]); -} - -void LLDrawPool::bindGLBinormalPointer(S32 index) -{ - mMemory.bindGLBinormalPointer(index, getStride(DATA_BINORMALS), mDataOffsets[DATA_BINORMALS]); -} - -void LLDrawPool::bindGLColorPointer() +void LLFacePool::enqueue(LLFace* facep) { - mMemory.bindGLColorPointer(getStride(DATA_COLORS), mDataOffsets[DATA_COLORS]); + mDrawFace.push_back(facep); } -void LLDrawPool::bindGLVertexWeightPointer(S32 index) -{ - mWeights.bindGLVertexWeightPointer(index, 0, 0); -} - -void LLDrawPool::bindGLVertexClothingWeightPointer(S32 index) -{ - mClothingWeights.bindGLVertexClothingWeightPointer(index, 0, 0); -} - - -U32* LLDrawPool::getIndices(S32 index) -{ - return &mIndices[index]; -} - -const LLVector3& LLDrawPool::getVertex(const S32 index) -{ - llassert(mDataMaskIL & DATA_VERTICES_MASK); - llassert(index < mMemory.count()); - llassert(mMemory.getMem()); - return *(LLVector3*)(mMemory.getMem() + mDataOffsets[DATA_VERTICES] + index * mStride); -} - -const LLVector2& LLDrawPool::getTexCoord(const S32 index, const U32 pass) +// virtual +BOOL LLFacePool::addFace(LLFace *facep) { - llassert(mDataMaskIL & (LLDrawPool::DATA_TEX_COORDS0_MASK << pass)); - llassert(index < mMemory.count()); - return *(LLVector2*)(mMemory.getMem() + mDataOffsets[DATA_TEX_COORDS0 + pass] + index * mStride); + addFaceReference(facep); + return TRUE; } -const LLVector3& LLDrawPool::getNormal(const S32 index) +// virtual +BOOL LLFacePool::removeFace(LLFace *facep) { - llassert(mDataMaskIL & DATA_NORMALS_MASK); - llassert(index < mMemory.count()); - return *(LLVector3*)(mMemory.getMem() + mDataOffsets[DATA_NORMALS] + index * mStride); -} + removeFaceReference(facep); -const LLVector3& LLDrawPool::getBinormal(const S32 index) -{ - llassert(mDataMaskIL & DATA_BINORMALS_MASK); - llassert(index < mMemory.count()); - return *(LLVector3*)(mMemory.getMem() + mDataOffsets[DATA_BINORMALS] + index * mStride); -} + vector_replace_with_last(mDrawFace, facep); -const LLColor4U& LLDrawPool::getColor(const S32 index) -{ - llassert(mDataMaskIL & DATA_COLORS_MASK); - llassert(index < mMemory.count()); - return *(LLColor4U*)(mMemory.getMem() + mDataOffsets[DATA_COLORS] + index * mStride); + return TRUE; } -const F32& LLDrawPool::getVertexWeight(const S32 index) +// Not absolutely sure if we should be resetting all of the chained pools as well - djs +void LLFacePool::resetDrawOrders() { - llassert(mDataMaskNIL & DATA_VERTEX_WEIGHTS_MASK); - llassert(index < mWeights.count()); - llassert(mWeights.getMem()); - return mWeights[index]; + mDrawFace.resize(0); } -const LLVector4& LLDrawPool::getClothingWeight(const S32 index) +LLViewerImage *LLFacePool::getTexture() { - llassert(mDataMaskNIL & DATA_CLOTHING_WEIGHTS_MASK); - llassert(index < mClothingWeights.count()); - llassert(mClothingWeights.getMem()); - return mClothingWeights[index]; + return NULL; } -////////////////////////////////////////////////////////////////////////////// - -#define USE_FREE_LIST 0 -#define DEBUG_FREELIST 0 - -struct tFreeListNode +void LLFacePool::removeFaceReference(LLFace *facep) { - U32 count; - S32 next; -}; - -#if DEBUG_FREELIST -static void check_list(U8 *pool, S32 stride, S32 head, S32 max) -{ - int count = 0; - - while (head >= 0) + if (facep->getReferenceIndex() != -1) { - tFreeListNode *node = (tFreeListNode *)(pool + head*stride); - count++; - if ((count > max) || ((node->count>>20) != 0xabc) || ((node->count&0xfffff) < 2)) - llerrs << "Bad Ind List" << llendl; - head = node->next; + if (facep->getReferenceIndex() != (S32)mReferences.size()) + { + LLFace *back = mReferences.back(); + mReferences[facep->getReferenceIndex()] = back; + back->setReferenceIndex(facep->getReferenceIndex()); + } + mReferences.pop_back(); } + facep->setReferenceIndex(-1); } -#define CHECK_LIST(x) check_list##x -#else -#define CHECK_LIST(x) -#endif -// DEBUG! -void LLDrawPool::CheckIntegrity() +void LLFacePool::addFaceReference(LLFace *facep) { -#if DEBUG_FREELIST - int bucket; - for (bucket=0; bucket<NUM_BUCKETS; bucket++) + if (-1 == facep->getReferenceIndex()) { - CHECK_LIST(((U8 *)mMemory.getMem(), mStride, mFreeListGeomHead[bucket], mMemory.count() / mStride)); - CHECK_LIST(((U8 *)mIndices.getMem(), 4, mFreeListIndHead[bucket], mIndices.count())); + facep->setReferenceIndex(mReferences.size()); + mReferences.push_back(facep); } -#endif } -int LLDrawPool::freeListBucket(U32 count) +BOOL LLFacePool::verify() const { - int bucket; - - // llassert(NUM_BUCKETS == 8) + BOOL ok = TRUE; - if (count & ~511) // >= 512 - bucket = 7; - else if (count & 256) // 256-511 - bucket = 6; - else if (count & 128) - bucket = 5; - else if (count & 64) - bucket = 4; - else if (count & 32) - bucket = 3; - else if (count & 16) - bucket = 2; - else if (count & 8) // 8-15 - bucket = 1; - else // 0-7 - bucket = 0; - return bucket; -} - -void remove_node(int nodeidx, int pidx, U8 *membase, int stride, int *head) -{ - LLDrawPool::FreeListNode *node = (LLDrawPool::FreeListNode *)(membase + nodeidx*stride); - if (pidx >= 0) - { - LLDrawPool::FreeListNode *pnode = (LLDrawPool::FreeListNode *)(membase + pidx*stride); - pnode->next = node->next; - } - else - { - *head = node->next; - } -} - -void LLDrawPool::freeListAddGeom(S32 index, U32 count) -{ -#if USE_FREE_LIST - int i; - U8 *membase = (U8*)mMemory.getMem(); - // See if next block or previous block is free, if so combine them - for (i=0; i<NUM_BUCKETS; i++) - { - int pidx = -1; - int nodeidx = mFreeListGeomHead[i]; - while(nodeidx >= 0) - { - int change = 0; - FreeListNode *node = (FreeListNode *)(membase + nodeidx*mStride); - int nodecount = node->count & 0xffff; - // Check for prev block - if (nodeidx + nodecount == index) - { - remove_node(nodeidx, pidx, membase, mStride, &mFreeListGeomHead[i]); - // Combine nodes - index = nodeidx; - count += nodecount; - i = 0; // start over ; i = NUM_BUCKETS // done - change = 1; - //break; - } - // Check for next block - if (nodeidx == index + count) - { - remove_node(nodeidx, pidx, membase, mStride, &mFreeListGeomHead[i]); - // Combine nodes - count += nodecount; - i = 0; // start over ; i = NUM_BUCKETS // done - change = 1; - //break; - } - if (change) - break; - pidx = nodeidx; - nodeidx = node->next; - } - } - // Add (extended) block to free list - if (count >= 2) // need 2 words to store free list (theoreticly mStride could = 4) + for (std::vector<LLFace*>::const_iterator iter = mDrawFace.begin(); + iter != mDrawFace.end(); iter++) { - CheckIntegrity(); - if ((index + count)*mStride >= mMemory.count()) + const LLFace* facep = *iter; + if (facep->getPool() != this) { - mMemory.shrinkTo(index*mStride); + llinfos << "Face in wrong pool!" << llendl; + facep->printDebugInfo(); + ok = FALSE; } - else + else if (!facep->verify()) { - int bucket = freeListBucket(count); - FreeListNode *node = (FreeListNode *)(membase + index*mStride); - node->count = count | (0xabc<<20); - node->next = mFreeListGeomHead[bucket]; - mFreeListGeomHead[bucket] = index; + ok = FALSE; } - CheckIntegrity(); } -#endif -} -void LLDrawPool::freeListAddInd(S32 index, U32 count) -{ -#if USE_FREE_LIST - int i; - const U32 *membase = mIndices.getMem(); - // See if next block or previous block is free, if so combine them - for (i=0; i<NUM_BUCKETS; i++) - { - int pidx = -1; - int nodeidx = mFreeListIndHead[i]; - while(nodeidx >= 0) - { - int change = 0; - FreeListNode *node = (FreeListNode *)(membase + nodeidx); - int nodecount = node->count & 0xffff; - // Check for prev block - if (nodeidx + nodecount == index) - { - remove_node(nodeidx, pidx, (U8*)membase, 4, &mFreeListIndHead[i]); - // Combine nodes - index = nodeidx; - count += nodecount; - i = 0; // start over ; i = NUM_BUCKETS // done - change = 1; - //break; - } - // Check for next block - if (nodeidx == index + count) - { - remove_node(nodeidx, pidx, (U8*)membase, 4, &mFreeListIndHead[i]); - // Combine nodes - count += nodecount; - i = 0; // start over ; i = NUM_BUCKETS // done - change = 1; - //break; - } - if (change) - break; - pidx = nodeidx; - nodeidx = node->next; - } - } - // Add (extended) block to free list - if (count >= 2) // need 2 words to store free list - { - CheckIntegrity(); - if (index + count >= mIndices.count()) - { - mIndices.shrinkTo(index); - } - else - { - int bucket = freeListBucket(count); - FreeListNode *node = (FreeListNode *)(membase + index); - node->count = count | (0xabc<<20); - node->next = mFreeListIndHead[bucket]; - mFreeListIndHead[bucket] = index; - } - CheckIntegrity(); - } -#endif + return ok; } -S32 LLDrawPool::freeListFindGeom(U32 count) +void LLFacePool::printDebugInfo() const { -#if USE_FREE_LIST - int i, nodeidx, pidx; - int firstbucket = freeListBucket(count); - U8 *membase = (U8*)mMemory.getMem(); - for (i=firstbucket; i<NUM_BUCKETS; i++) - { - pidx = -1; - nodeidx = mFreeListGeomHead[i]; - CHECK_LIST(((U8 *)mMemory.getMem(), mStride, mFreeListGeomHead[i], mMemory.count() / mStride)); - while(nodeidx >= 0) - { - FreeListNode *node = (FreeListNode *)(membase + nodeidx*mStride); - int nodecount = node->count & 0xffff; - llassert((node->count>>20) == 0xabc); - if (nodecount >= count) - { - remove_node(nodeidx, pidx, membase, mStride, &mFreeListGeomHead[i]); -#if 1 - if (nodecount > count) - { - int leftover = nodecount - count; - freeListAddGeom(nodeidx + count, leftover); - } -#endif - return nodeidx; - } - pidx = nodeidx; - nodeidx = node->next; - } - } -#endif // USE_FREE_LIST - return -1; + llinfos << "Pool " << this << " Type: " << getType() << llendl; } -S32 LLDrawPool::freeListFindInd(U32 count) +BOOL LLFacePool::LLOverrideFaceColor::sOverrideFaceColor = FALSE; + +void LLFacePool::LLOverrideFaceColor::setColor(const LLColor4& color) { -#if USE_FREE_LIST - int i, nodeidx, pidx; - int firstbucket = freeListBucket(count); - U32 *membase = (U32 *)mIndices.getMem(); - for (i=firstbucket; i<NUM_BUCKETS; i++) + if (mPool->getVertexShaderLevel() > 0 && mPool->getMaterialAttribIndex() > 0) { - pidx = -1; - nodeidx = mFreeListIndHead[i]; - CHECK_LIST(((U8 *)mIndices.getMem(), 4, mFreeListIndHead[i], mIndices.count())); - while(nodeidx >= 0) - { - FreeListNode *node = (FreeListNode *)(membase + nodeidx); - int nodecount = node->count & 0xffff; - llassert((node->count>>20) == 0xabc); - if (nodecount >= count) - { - remove_node(nodeidx, pidx, (U8*)membase, 4, &mFreeListIndHead[i]); -#if 1 - if (nodecount > count) - { - int leftover = nodecount - count; - freeListAddInd(nodeidx + count, leftover); - } -#endif - return nodeidx; - } - pidx = nodeidx; - nodeidx = node->next; - } + glVertexAttrib4fvARB(mPool->getMaterialAttribIndex(), color.mV); } -#endif // USE_FREE_LIST - return -1; -} - -////////////////////////////////////////////////////////////////////////////// - -S32 LLDrawPool::reserveGeom(const U32 geom_count) -{ - LLFastTimer t(LLFastTimer::FTM_GEO_RESERVE); - - S32 index; - index = freeListFindGeom(geom_count); - if (index < 0) + else { - index = mMemory.count() / mStride; - if (!geom_count) - { - llwarns << "Attempting to reserve zero bytes!" << llendl; - return index; - } - - S32 bytes = geom_count * mStride; - - if ((index + (S32)geom_count) > (S32)mMaxVertices) - { - // - // Various drivers have issues with the number of indices being greater than a certain number. - // if you're using AGP. Disable AGP if we've got more vertices than in the pool. - // -#ifdef DEBUG_AGP - llinfos << "setUseAGP false because of large vertex count in reserveGeom" << llendl; -#endif - setUseAGP(FALSE); - } - - mMemory.reserve_block(bytes); - if (mDataMaskNIL & DATA_VERTEX_WEIGHTS_MASK) - { - mWeights.reserve_block(geom_count); - } - if (mDataMaskNIL & DATA_CLOTHING_WEIGHTS_MASK) - { - mClothingWeights.reserve_block(geom_count); - } + glColor4fv(color.mV); } - CHECK_LIST(((U8 *)mMemory.getMem(), mStride, mFreeListGeomHead[0], mMemory.count() / mStride)); - return index; } -S32 LLDrawPool::reserveInd(U32 indCount) +void LLFacePool::LLOverrideFaceColor::setColor(const LLColor4U& color) { - S32 index; - index = freeListFindInd(indCount); - if (index < 0) + if (mPool->getVertexShaderLevel() > 0 && mPool->getMaterialAttribIndex() > 0) { - index = mIndices.count(); - - if (indCount) - { - mIndices.reserve_block(indCount); - } + glVertexAttrib4ubvARB(mPool->getMaterialAttribIndex(), color.mV); } - for (U32 i=0;i<indCount;i++) + else { - mIndices[index+i]=0; + glColor4ubv(color.mV); } - CHECK_LIST(((U8 *)mIndices.getMem(), 4, mFreeListIndHead[0], mIndices.count())); - return index; } -S32 LLDrawPool::unReserveGeom(const S32 index, const U32 count) +void LLFacePool::LLOverrideFaceColor::setColor(F32 r, F32 g, F32 b, F32 a) { - if (index < 0 || count == 0) - return -1; - - freeListAddGeom(index, count); - -#if 0 - int i; - S32 bytes,words; - U32 *memp; - // Fill mem with bad data (for testing only) - bytes = count * mStride; - bytes -= sizeof(FreeListNode); - memp = (U32*)(mMemory.getMem() + index * mStride); - memp += sizeof(FreeListNode)>>2; - words = bytes >> 2; - for (i=0; i<words; i++) - *memp++ = 0xffffffff; - - words = count; // (sizeof each array is a word) - if (mDataMaskNIL & DATA_VERTEX_WEIGHTS_MASK) + if (mPool->getVertexShaderLevel() > 0 && mPool->getMaterialAttribIndex() > 0) { - memp = (U32*)(&mWeights[index]); - for (i=0; i<words; i++) - *memp++ = 0xffffffff; + glVertexAttrib4fARB(mPool->getMaterialAttribIndex(), r,g,b,a); } - if (mDataMaskNIL & DATA_CLOTHING_WEIGHTS_MASK) + else { - memp = (U32*)(&mClothingWeights[index]); - for (i=0; i<count; i++) - *memp++ = 0xffffffff; + glColor4f(r,g,b,a); } -#endif - return -1; } -S32 LLDrawPool::unReserveInd(const S32 index, const U32 count) -{ - if (index < 0 || count == 0) - return -1; - freeListAddInd(index, count); - -#if 0 - int i; - U32 *memp = &mIndices[index]; - for (i=0; i<count; i++) - *memp++ = 0xffffffff; -#endif - return -1; -} - -////////////////////////////////////////////////////////////////////////////// - -const U32 LLDrawPool::getIndexCount() const +//============================= +// Render Pass Implementation +//============================= +LLRenderPass::LLRenderPass(const U32 type) +: LLDrawPool(type) { - return mIndices.count(); -} -const U32 LLDrawPool::getVertexCount() const -{ - return mMemory.count() / mStride; } -const U32 LLDrawPool::getTexCoordCount(U32 pass) const +LLRenderPass::~LLRenderPass() { - return mMemory.count() / mStride; -} - -const U32 LLDrawPool::getNormalCount() const -{ - return mMemory.count() / mStride; } - -const U32 LLDrawPool::getBinormalCount() const +LLDrawPool* LLRenderPass::instancePool() { - return mMemory.count() / mStride; -} - -const U32 LLDrawPool::getColorCount() const -{ - return mMemory.count() / mStride; -} - -const U32 LLDrawPool::getVertexWeightCount() const -{ - return mWeights.count(); +#if LL_RELEASE_FOR_DOWNLOAD + llwarns << "Attempting to instance a render pass. Invalid operation." << llendl; +#else + llerrs << "Attempting to instance a render pass. Invalid operation." << llendl; +#endif + return NULL; } -// virtual -BOOL LLDrawPool::addFace(LLFace *facep) -{ - addFaceReference(facep); - return TRUE; +void LLRenderPass::renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture) +{ + std::vector<LLDrawInfo*>& draw_info = group->mDrawMap[type]; + + for (std::vector<LLDrawInfo*>::const_iterator k = draw_info.begin(); k != draw_info.end(); ++k) + { + LLDrawInfo& params = **k; + pushBatch(params, mask, texture); + } } -// virtual -BOOL LLDrawPool::removeFace(LLFace *facep) +void LLRenderPass::renderInvisible(U32 mask) { - removeFaceReference(facep); - - vector_replace_with_last(mDrawFace, facep); - - facep->unReserve(); +#if !LL_RELEASE_FOR_DOWNLOAD + LLGLState::checkClientArrays(mask); +#endif - return TRUE; -} + std::vector<LLDrawInfo*>& draw_info = gPipeline.mRenderMap[LLRenderPass::PASS_INVISIBLE]; -// Not absolutely sure if we should be resetting all of the chained pools as well - djs -void LLDrawPool::resetDrawOrders() -{ - mDrawFace.resize(0); + U32* indices_pointer = NULL; + for (std::vector<LLDrawInfo*>::iterator i = draw_info.begin(); i != draw_info.end(); ++i) + { + LLDrawInfo& params = **i; + params.mVertexBuffer->setBuffer(mask); + indices_pointer = (U32*) params.mVertexBuffer->getIndicesPointer(); + glDrawRangeElements(GL_TRIANGLES, params.mStart, params.mEnd, params.mCount, + GL_UNSIGNED_INT, indices_pointer+params.mOffset); + gPipeline.mTrianglesDrawn += params.mCount/3; + } } -void LLDrawPool::resetIndices(S32 indices_count) +void LLRenderPass::renderTexture(U32 type, U32 mask) { - mIndices.reset(indices_count); - for (S32 i=0; i<NUM_BUCKETS; i++) - mFreeListIndHead[i] = -1; -} +#if !LL_RELEASE_FOR_DOWNLOAD + LLGLState::checkClientArrays(mask); +#endif -void LLDrawPool::resetVertexData(S32 reserve_count) -{ - mMemory.reset(reserve_count*mStride); - - for (S32 i=0; i<NUM_BUCKETS; i++) - { - mFreeListGeomHead[i] = -1; - } - if (mDataMaskNIL & DATA_VERTEX_WEIGHTS_MASK) - { - mWeights.reset(reserve_count); - } + std::vector<LLDrawInfo*>& draw_info = gPipeline.mRenderMap[type]; - if (mDataMaskNIL & DATA_CLOTHING_WEIGHTS_MASK) + for (std::vector<LLDrawInfo*>::iterator i = draw_info.begin(); i != draw_info.end(); ++i) { - mClothingWeights.reset(reserve_count); + LLDrawInfo& params = **i; + pushBatch(params, mask, TRUE); } } -void LLDrawPool::resetAll() -{ - resetDrawOrders(); - resetVertexData(0); - mGeneration++; - -} - -S32 LLDrawPool::rebuild() +void LLRenderPass::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture) { - mRebuildTime++; - - BOOL needs_rebuild = FALSE; - S32 rebuild_cost = 0; - - if (mUseAGP) - { - if (getVertexCount() > 0.75f*DEFAULT_MAX_VERTICES) - { - if (mRebuildTime > 8) - { - needs_rebuild = TRUE; - } -#ifdef DEBUG_AGP - llwarns << "More than " << DEFAULT_MAX_VERTICES << " in pool type " << (S32)mType << " at rebuild!" << llendl; -#endif - } - } - - // rebuild de-allocates 'stale' objects, so we still need to do a rebuild periodically - if (mRebuildFreq > 0 && mRebuildTime >= mRebuildFreq) + if (params.mVertexBuffer.isNull()) { - needs_rebuild = TRUE; + return; } - if (needs_rebuild) + if (texture) { - mGeneration++; - - if (mReferences.empty()) + if (params.mTexture.notNull()) { - resetIndices(0); - resetVertexData(0); - } - else - { - for (std::vector<LLFace*>::iterator iter = mReferences.begin(); - iter != mReferences.end(); iter++) - { - LLFace *facep = *iter; - if (facep->hasGeometry() && !facep->isState(LLFace::BACKLIST | LLFace::SHARED_GEOM)) - { - facep->backup(); - } - } - S32 tot_verts = 0; - S32 tot_indices = 0; - for (std::vector<LLFace*>::iterator iter = mDrawFace.begin(); - iter != mDrawFace.end(); iter++) - { - LLFace *facep = *iter; - if (facep->isState(LLFace::BACKLIST)) - { - tot_verts += facep->getGeomCount(); - tot_indices += facep->getIndicesCount(); - } - } - for (std::vector<LLFace*>::iterator iter = mMoveFace.begin(); - iter != mMoveFace.end(); iter++) + params.mTexture->bind(); + if (params.mTextureMatrix) { - LLFace *facep = *iter; - if (facep->isState(LLFace::BACKLIST)) - { - tot_verts += facep->getGeomCount(); - tot_indices += facep->getIndicesCount(); - } - } - - resetIndices(tot_indices); - flushAGP(); - resetVertexData(tot_verts); - - for (std::vector<LLFace*>::iterator iter = mDrawFace.begin(); - iter != mDrawFace.end(); iter++) - { - LLFace *facep = *iter; - llassert(facep->getPool() == this); - facep->restore(); + glMatrixMode(GL_TEXTURE); + glLoadMatrixf((GLfloat*) params.mTextureMatrix->mMatrix); } + params.mTexture->addTextureStats(params.mVSize); } - mRebuildTime = 0; - setDirty(); - } - - if (!mMoveFace.empty()) - { - for (std::vector<LLFace*>::iterator iter = mMoveFace.begin(); - iter != mMoveFace.end(); iter++) - { - LLFace *facep = *iter; - facep->restore(); - enqueue(facep); - } - setDirty(); - mMoveFace.reset(); - rebuild_cost++; - } - return rebuild_cost; -} - -LLViewerImage *LLDrawPool::getTexture() -{ - return NULL; -} - -LLViewerImage *LLDrawPool::getDebugTexture() -{ - return NULL; -} - -void LLDrawPool::removeFaceReference(LLFace *facep) -{ - if (facep->getReferenceIndex() != -1) - { - if (facep->getReferenceIndex() != (S32)mReferences.size()) + else { - LLFace *back = mReferences.back(); - mReferences[facep->getReferenceIndex()] = back; - back->setReferenceIndex(facep->getReferenceIndex()); + LLImageGL::unbindTexture(0); } - mReferences.pop_back(); } - facep->setReferenceIndex(-1); -} + + params.mVertexBuffer->setBuffer(mask); + U32* indices_pointer = (U32*) params.mVertexBuffer->getIndicesPointer(); + glDrawRangeElements(GL_TRIANGLES, params.mStart, params.mEnd, params.mCount, + GL_UNSIGNED_INT, indices_pointer+params.mOffset); + gPipeline.mTrianglesDrawn += params.mCount/3; -void LLDrawPool::addFaceReference(LLFace *facep) -{ - if (-1 == facep->getReferenceIndex()) + if (params.mTextureMatrix && texture && params.mTexture.notNull()) { - facep->setReferenceIndex(mReferences.size()); - mReferences.push_back(facep); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); } } -U32 LLDrawPool::getTrianglesDrawn() const +void LLRenderPass::renderActive(U32 type, U32 mask, BOOL texture) { - return mIndicesDrawn / 3; -} - -void LLDrawPool::resetTrianglesDrawn() -{ - mIndicesDrawn = 0; -} - -void LLDrawPool::addIndicesDrawn(const U32 indices) -{ - mIndicesDrawn += indices; -} +#if !LL_RELEASE_FOR_DOWNLOAD + LLGLState::checkClientArrays(mask); +#endif -BOOL LLDrawPool::verify() const -{ - BOOL ok = TRUE; - // Verify all indices in the pool are in the right range - const U32 *indicesp = getRawIndices(); - for (U32 i = 0; i < getIndexCount(); i++) + LLSpatialBridge* last_bridge = NULL; + glPushMatrix(); + + for (LLSpatialGroup::sg_vector_t::iterator i = gPipeline.mActiveGroups.begin(); i != gPipeline.mActiveGroups.end(); ++i) { - if (indicesp[i] > getVertexCount()) + LLSpatialGroup* group = *i; + if (!group->isDead() && + gPipeline.hasRenderType(group->mSpatialPartition->mDrawableType) && + group->mDrawMap.find(type) != group->mDrawMap.end()) { - ok = FALSE; - llinfos << "Bad index in tree pool!" << llendl; - } - } + LLSpatialBridge* bridge = (LLSpatialBridge*) group->mSpatialPartition; + if (bridge != last_bridge) + { + glPopMatrix(); + glPushMatrix(); + glMultMatrixf((F32*) bridge->mDrawable->getRenderMatrix().mMatrix); + last_bridge = bridge; + } - for (std::vector<LLFace*>::const_iterator iter = mDrawFace.begin(); - iter != mDrawFace.end(); iter++) - { - const LLFace* facep = *iter; - if (facep->getPool() != this) - { - llinfos << "Face in wrong pool!" << llendl; - facep->printDebugInfo(); - ok = FALSE; - } - else if (!facep->verify()) - { - ok = FALSE; + renderGroup(group,type,mask,texture); } } - - return ok; -} - -void LLDrawPool::printDebugInfo() const -{ - llinfos << "Pool " << this << " Type: " << getType() << llendl; - llinfos << "--------------------" << llendl; - llinfos << "Vertex count: " << getVertexCount() << llendl; - llinfos << "Normal count: " << getNormalCount() << llendl; - llinfos << "Indices count: " << getIndexCount() << llendl; - llinfos << llendl; -} - - -S32 LLDrawPool::getMemUsage(const BOOL print) -{ - S32 mem_usage = 0; - - mem_usage += sizeof(this); - - // Usage beyond the pipeline allocated data (color and mMemory) - mem_usage += mIndices.getMax() * sizeof(U32); - mem_usage += mDrawFace.capacity() * sizeof(LLFace *); - mem_usage += mMoveFace.capacity() * sizeof(LLFace *); - mem_usage += mReferences.capacity() * sizeof(LLFace *); - - mem_usage += mMemory.getSysMemUsage(); - mem_usage += mWeights.getSysMemUsage(); - mem_usage += mClothingWeights.getSysMemUsage(); - - return mem_usage; -} - -LLColor3 LLDrawPool::getDebugColor() const -{ - return LLColor3(0.f, 0.f, 0.f); -} - -void LLDrawPool::setDirty() -{ - mMemory.setDirty(); - mWeights.setDirty(); - mClothingWeights.setDirty(); -} - -BOOL LLDrawPool::LLOverrideFaceColor::sOverrideFaceColor = FALSE; - -void LLDrawPool::LLOverrideFaceColor::setColor(const LLColor4& color) -{ - if (mPool->mVertexShaderLevel > 0 && mPool->getMaterialAttribIndex() > 0) - { - glVertexAttrib4fvARB(mPool->getMaterialAttribIndex(), color.mV); - } - else - { - glColor4fv(color.mV); - } + + glPopMatrix(); } -void LLDrawPool::LLOverrideFaceColor::setColor(const LLColor4U& color) +void LLRenderPass::renderStatic(U32 type, U32 mask, BOOL texture) { - if (mPool->mVertexShaderLevel > 0 && mPool->getMaterialAttribIndex() > 0) - { - glVertexAttrib4ubvARB(mPool->getMaterialAttribIndex(), color.mV); - } - else - { - glColor4ubv(color.mV); - } -} +#if !LL_RELEASE_FOR_DOWNLOAD + LLGLState::checkClientArrays(mask); +#endif -void LLDrawPool::LLOverrideFaceColor::setColor(F32 r, F32 g, F32 b, F32 a) -{ - if (mPool->mVertexShaderLevel > 0 && mPool->getMaterialAttribIndex() > 0) - { - glVertexAttrib4fARB(mPool->getMaterialAttribIndex(), r,g,b,a); - } - else + for (LLSpatialGroup::sg_vector_t::iterator i = gPipeline.mVisibleGroups.begin(); i != gPipeline.mVisibleGroups.end(); ++i) { - glColor4f(r,g,b,a); + LLSpatialGroup* group = *i; + if (!group->isDead() && + gPipeline.hasRenderType(group->mSpatialPartition->mDrawableType) && + group->mDrawMap.find(type) != group->mDrawMap.end()) + { + renderGroup(group,type,mask,texture); + } } } - -// virtual -void LLDrawPool::enableShade() -{ } - -// virtual -void LLDrawPool::disableShade() -{ } - -// virtual -void LLDrawPool::setShade(F32 shade) -{ } diff --git a/indra/newview/lldrawpool.h b/indra/newview/lldrawpool.h index c00cbf14e4..007c0a2de3 100644 --- a/indra/newview/lldrawpool.h +++ b/indra/newview/lldrawpool.h @@ -9,270 +9,167 @@ #ifndef LL_LLDRAWPOOL_H #define LL_LLDRAWPOOL_H -#include "llagparray.h" -#include "lldarray.h" -#include "lldlinked.h" -#include "llstrider.h" -#include "llviewerimage.h" #include "v4coloru.h" #include "v2math.h" #include "v3math.h" -#include "llstrider.h" +#include "llvertexbuffer.h" class LLFace; class LLImageGL; class LLViewerImage; +class LLSpatialGroup; +class LLDrawInfo; #define DEFAULT_MAX_VERTICES 65535 class LLDrawPool { public: - typedef LLDynamicArray<LLFace*, 128> face_array_t; - + static S32 sNumDrawPools; + enum { - SHADER_LEVEL_SCATTERING = 2 + // Correspond to LLPipeline render type + POOL_SKY = 1, + POOL_STARS, + POOL_GROUND, + POOL_TERRAIN, + POOL_SIMPLE, + POOL_BUMP, + POOL_AVATAR, + POOL_TREE, + POOL_ALPHA, + POOL_WATER, + POOL_ALPHA_POST_WATER, + NUM_POOL_TYPES, }; - -public: - LLDrawPool(const U32 type, const U32 data_mask_il, const U32 data_mask_nil); + + LLDrawPool(const U32 type); virtual ~LLDrawPool(); - static LLDrawPool* createPool(const U32 type, LLViewerImage *tex0 = NULL); + virtual BOOL isDead() = 0; - void flushAGP(); // Flush the AGP buffers so they can be repacked and reallocated. - void syncAGP(); + S32 getId() const { return mId; } + U32 getType() const { return mType; } - virtual LLDrawPool *instancePool() = 0; // Create an empty new instance of the pool. + virtual LLViewerImage *getDebugTexture(); virtual void beginRenderPass( S32 pass ); virtual void endRenderPass( S32 pass ); virtual S32 getNumPasses() { return 1; } virtual void render(S32 pass = 0) = 0; + virtual void prerender() = 0; + virtual S32 getMaterialAttribIndex() = 0; + virtual U32 getVertexDataMask() = 0; + virtual BOOL verify() const { return TRUE; } // Verify that all data in the draw pool is correct! + virtual S32 getVertexShaderLevel() const { return mVertexShaderLevel; } + + static LLDrawPool* createPool(const U32 type, LLViewerImage *tex0 = NULL); + virtual LLDrawPool *instancePool() = 0; // Create an empty new instance of the pool. + virtual LLViewerImage* getTexture() = 0; + virtual BOOL isFacePool() { return FALSE; } + virtual void resetDrawOrders() = 0; + + U32 getTrianglesDrawn() const; + void resetTrianglesDrawn(); + void addIndicesDrawn(const U32 indices); + +protected: + S32 mVertexShaderLevel; + S32 mId; + U32 mType; // Type of draw pool + S32 mIndicesDrawn; +}; + +class LLRenderPass : public LLDrawPool +{ +public: + enum + { + PASS_SIMPLE = NUM_POOL_TYPES, + PASS_FULLBRIGHT, + PASS_INVISIBLE, + PASS_SHINY, + PASS_BUMP, + PASS_GRASS, + PASS_ALPHA, + NUM_RENDER_TYPES, + }; + + LLRenderPass(const U32 type); + virtual ~LLRenderPass(); + /*virtual*/ LLDrawPool* instancePool(); + /*vritual*/ S32 getMaterialAttribIndex() { return -1; } + /*virtual*/ LLViewerImage* getDebugTexture() { return NULL; } + LLViewerImage* getTexture() { return NULL; } + BOOL isDead() { return FALSE; } + void resetDrawOrders() { } + + virtual void pushBatch(LLDrawInfo& params, U32 mask, BOOL texture); + virtual void renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture = TRUE); + virtual void renderStatic(U32 type, U32 mask, BOOL texture = TRUE); + virtual void renderActive(U32 type, U32 mask, BOOL texture = TRUE); + virtual void renderInvisible(U32 mask); + virtual void renderTexture(U32 type, U32 mask); + +}; + +class LLFacePool : public LLDrawPool +{ +public: + typedef std::vector<LLFace*> face_array_t; + + enum + { + SHADER_LEVEL_SCATTERING = 2 + }; + +public: + LLFacePool(const U32 type); + virtual ~LLFacePool(); + virtual void renderForSelect() = 0; - virtual BOOL match(LLFace* last_face, LLFace* facep) { return FALSE; } + BOOL isDead() { return mReferences.empty(); } virtual void renderFaceSelected(LLFace *facep, LLImageGL *image, const LLColor4 &color, const S32 index_offset = 0, const S32 index_count = 0); - virtual void prerender() = 0; - virtual S32 rebuild(); - - virtual S32 getMaterialAttribIndex() = 0; - virtual LLViewerImage *getTexture(); - virtual LLViewerImage *getDebugTexture(); - virtual void dirtyTexture(const LLViewerImage* texturep); + virtual void dirtyTextures(const std::set<LLViewerImage*>& textures); virtual void enqueue(LLFace *face); virtual BOOL addFace(LLFace *face); virtual BOOL removeFace(LLFace *face); virtual BOOL verify() const; // Verify that all data in the draw pool is correct! - virtual LLColor3 getDebugColor() const; // For AGP debug display - + virtual void resetDrawOrders(); - virtual void resetVertexData(S32 reserve_count); - virtual void resetIndices(S32 num_indices); void resetAll(); BOOL moveFace(LLFace *face, LLDrawPool *poolp, BOOL copy_data = FALSE); - - S32 getId() const { return mId; } - U32 getType() const { return mType; } - - const U32 getStride() const; - inline const U32 getStride(const U32 data_type) const; - inline const U32 getOffset(const U32 data_type) const; - - S32 reserveGeom(U32 count); - S32 reserveInd (U32 count); - S32 unReserveGeom(const S32 index, const U32 count); - S32 unReserveInd(const S32 index, const U32 count); - - void bindGLVertexPointer(); - void bindGLTexCoordPointer(const U32 pass=0); - void bindGLNormalPointer(); - void bindGLBinormalPointer(S32 index); - void bindGLColorPointer(); - void bindGLVertexWeightPointer(S32 index); - void bindGLVertexClothingWeightPointer(S32 index); - - const U32 getIndexCount() const; - const U32 getTexCoordCount(const U32 pass=0) const; - const U32 getVertexCount() const; - const U32 getNormalCount() const; - const U32 getBinormalCount() const; - const U32 getColorCount() const; - const U32 getVertexWeightCount() const; - - void setDirty(); - void setDirtyMemory() { mMemory.setDirty(); } - void setDirtyWeights() { mWeights.setDirty(); } - - const U32* getRawIndices() const { return mIndices.getMem(); } - - U32 getIndex(const S32 index) { return mIndices[index]; } // Use to get one index - U32 *getIndices(const S32 index); // Used to get an array of indices for reading/writing - void CheckIntegrity(); // DEBUG - - const LLVector3& getVertex(const S32 index); - const LLVector2& getTexCoord(const S32 index, const U32 pass); - const LLVector3& getNormal(const S32 index); - const LLVector3& getBinormal(const S32 index); - const LLColor4U& getColor(const S32 index); - const F32& getVertexWeight(const S32 index); - const LLVector4& getClothingWeight(const S32 index); - - void setRebuild(const BOOL rebuild); - void destroy(); void buildEdges(); - static S32 drawLoop(face_array_t& face_list, const U32* index_array); - static S32 drawLoopSetTex(face_array_t& face_list, const U32* index_array, S32 stage); + static S32 drawLoop(face_array_t& face_list); + static S32 drawLoopSetTex(face_array_t& face_list, S32 stage); void drawLoop(); void renderVisibility(); void addFaceReference(LLFace *facep); void removeFaceReference(LLFace *facep); - U32 getTrianglesDrawn() const; - void resetTrianglesDrawn(); - void addIndicesDrawn(const U32 indices); void printDebugInfo() const; - S32 getMemUsage(const BOOL print = FALSE); - BOOL setUseAGP(BOOL use_agp); - BOOL canUseAGP() const { return mMemory.isAGP(); } // Return TRUE if this pool can use AGP + BOOL isFacePool() { return TRUE; } - S32 getMaxVertices() const { return mMaxVertices; } - S32 getVertexShaderLevel() const { return mVertexShaderLevel; } - friend class LLFace; friend class LLPipeline; public: - - enum - { - // Correspond to LLPipeline render type - POOL_SKY = 1, - POOL_STARS, - POOL_GROUND, - POOL_TERRAIN, - POOL_SIMPLE, - POOL_MEDIA, // unused - POOL_BUMP, - POOL_AVATAR, - POOL_TREE, - POOL_TREE_NEW, - POOL_WATER, - POOL_CLOUDS, - POOL_ALPHA, - POOL_HUD, - }; - - - // If you change the order or add params to these, you also need to adjust the sizes in the - // mDataSizes array defined in lldrawpool.cpp - typedef enum e_data_type - { - DATA_VERTICES = 0, - DATA_TEX_COORDS0 = 1, - DATA_TEX_COORDS1 = 2, - DATA_TEX_COORDS2 = 3, - DATA_TEX_COORDS3 = 4, - DATA_NORMALS = 5, - DATA_VERTEX_WEIGHTS = 6, - DATA_CLOTHING_WEIGHTS = 7, - DATA_BINORMALS = 8, - DATA_COLORS = 9, - DATA_MAX_TYPES = 10 - } EDataType; - - typedef enum e_data_mask - { - DATA_VERTICES_MASK = 1 << DATA_VERTICES, - DATA_TEX_COORDS0_MASK = 1 << DATA_TEX_COORDS0, - DATA_TEX_COORDS1_MASK = 1 << DATA_TEX_COORDS1, - DATA_TEX_COORDS2_MASK = 1 << DATA_TEX_COORDS2, - DATA_TEX_COORDS3_MASK = 1 << DATA_TEX_COORDS3, - DATA_NORMALS_MASK = 1 << DATA_NORMALS, - DATA_VERTEX_WEIGHTS_MASK = 1 << DATA_VERTEX_WEIGHTS, - DATA_CLOTHING_WEIGHTS_MASK = 1 << DATA_CLOTHING_WEIGHTS, - DATA_BINORMALS_MASK = 1 << DATA_BINORMALS, - DATA_COLORS_MASK = 1 << DATA_COLORS, - - // Masks for standard types. - // IL for interleaved, NIL for non-interleaved. - DATA_SIMPLE_IL_MASK = DATA_VERTICES_MASK | DATA_TEX_COORDS0_MASK | DATA_NORMALS_MASK, - DATA_SIMPLE_NIL_MASK = 0, - DATA_BUMP_IL_MASK = DATA_SIMPLE_IL_MASK | DATA_BINORMALS_MASK | DATA_TEX_COORDS1_MASK, - } EDataMask; - face_array_t mDrawFace; face_array_t mMoveFace; face_array_t mReferences; - U32 mDataMaskIL; // Interleaved data - U32 mDataMaskNIL; // Non-interleaved data - U32 mDataOffsets[DATA_MAX_TYPES]; - S32 mStride; - - S32 mRebuildFreq; - S32 mRebuildTime; - S32 mGeneration; - - - S32 mSkippedVertices; - - static U32 sDataSizes[DATA_MAX_TYPES]; - static S32 sNumDrawPools; - -protected: - LLAGPArray<U8> mMemory; - LLAGPArray<F32> mWeights; - LLAGPArray<LLVector4> mClothingWeights; - LLAGPArray<U32> mIndices; - -public: - - BOOL getVertexStrider (LLStrider<LLVector3> &vertices, const U32 index = 0); - BOOL getTexCoordStrider (LLStrider<LLVector2> &tex_coords, const U32 index = 0, const U32 pass=0); - BOOL getNormalStrider (LLStrider<LLVector3> &normals, const U32 index = 0); - BOOL getBinormalStrider (LLStrider<LLVector3> &binormals, const U32 index = 0); - BOOL getColorStrider (LLStrider<LLColor4U> &colors, const U32 index = 0); - BOOL getVertexWeightStrider(LLStrider<F32> &vertex_weights, const U32 index = 0); - BOOL getClothingWeightStrider(LLStrider<LLVector4> &clothing_weights, const U32 index = 0); - -public: - enum { NUM_BUCKETS = 8 }; // Need to change freeListBucket() if NUM_BUCKETS changes - struct FreeListNode - { - U32 count; - S32 next; - }; -protected: - int freeListBucket(U32 count); - void freeListAddGeom(S32 index, U32 count); - void freeListAddInd(S32 index, U32 count); - S32 freeListFindGeom(U32 count); - S32 freeListFindInd(U32 count); - -protected: - BOOL mUseAGP; - S32 mVertexShaderLevel; - S32 mId; - U32 mType; // Type of draw pool - S32 mMaxVertices; - S32 mIndicesDrawn; - BOOL mCleanupUnused; // Cleanup unused data when too full - - S32 mFreeListGeomHead[8]; - S32 mFreeListIndHead[8]; - public: class LLOverrideFaceColor { @@ -311,38 +208,6 @@ public: LLDrawPool* mPool; static BOOL sOverrideFaceColor; }; - - virtual void enableShade(); - virtual void disableShade(); - virtual void setShade(F32 shade); - }; -inline const U32 LLDrawPool::getStride() const -{ - return mStride; -} - -inline const U32 LLDrawPool::getOffset(const U32 data_type) const -{ - return mDataOffsets[data_type]; -} - -inline const U32 LLDrawPool::getStride(const U32 data_type) const -{ - if (mDataMaskIL & (1 << data_type)) - { - return mStride; - } - else if (mDataMaskNIL & (1 << data_type)) - { - return 0; - } - else - { - llerrs << "Getting stride for unsupported data type " << data_type << llendl; - return 0; - } -} - #endif //LL_LLDRAWPOOL_H diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp index 8c520f6638..5cb914c37e 100644 --- a/indra/newview/lldrawpoolalpha.cpp +++ b/indra/newview/lldrawpoolalpha.cpp @@ -10,11 +10,11 @@ #include "lldrawpoolalpha.h" +#include "llglheaders.h" #include "llviewercontrol.h" #include "llcriticaldamp.h" #include "llfasttimer.h" -#include "llagparray.h" #include "llcubemap.h" #include "llsky.h" #include "llagent.h" @@ -25,104 +25,25 @@ #include "llviewerobjectlist.h" // For debugging #include "llviewerwindow.h" #include "pipeline.h" - -const F32 MAX_DIST = 512.f; -const F32 ALPHA_FALLOFF_START_DISTANCE = 0.8f; +#include "llviewerregion.h" BOOL LLDrawPoolAlpha::sShowDebugAlpha = FALSE; -LLDrawPoolAlpha::LLDrawPoolAlpha() : - LLDrawPool(POOL_ALPHA, - DATA_SIMPLE_IL_MASK | DATA_COLORS_MASK, - DATA_SIMPLE_NIL_MASK) +LLDrawPoolAlpha::LLDrawPoolAlpha(U32 type) : + LLRenderPass(type) { - mRebuiltLastFrame = FALSE; - mMinDistance = 0.f; - mMaxDistance = MAX_DIST; - mInvBinSize = NUM_ALPHA_BINS/(mMaxDistance - mMinDistance); - mCleanupUnused = TRUE; - //mRebuildFreq = -1 ; // Only rebuild if nearly full - -// for (S32 i = 0; i < NUM_ALPHA_BINS; i++) -// { -// mDistanceBins[i].realloc(200); -// } -} -LLDrawPoolAlpha::~LLDrawPoolAlpha() -{ } -LLDrawPool *LLDrawPoolAlpha::instancePool() +LLDrawPoolAlphaPostWater::LLDrawPoolAlphaPostWater() +: LLDrawPoolAlpha(POOL_ALPHA_POST_WATER) { - llerrs << "Should never be calling instancePool on an alpha pool!" << llendl; - return NULL; } -void LLDrawPoolAlpha::enqueue(LLFace *facep) +LLDrawPoolAlpha::~LLDrawPoolAlpha() { - if (!facep->isState(LLFace::GLOBAL)) - { - facep->mCenterAgent = facep->mCenterLocal * facep->getRenderMatrix(); - } - facep->mDistance = (facep->mCenterAgent - gCamera->getOrigin()) * gCamera->getAtAxis(); - - if (facep->isState(LLFace::BACKLIST)) - { - mMoveFace.put(facep); - } - else - { - mDrawFace.put(facep); - } - - { - S32 dist_bin = lltrunc( (mMaxDistance - (facep->mDistance+32))*mInvBinSize ); - - if (dist_bin >= NUM_ALPHA_BINS) - { - mDistanceBins[NUM_ALPHA_BINS-1].put(facep); - //mDistanceBins[NUM_ALPHA_BINS-1].push(facep, (U32)(void*)facep->getTexture()); - } - else if (dist_bin > 0) - { - mDistanceBins[dist_bin].put(facep); - //mDistanceBins[dist_bin].push(facep, (U32)(void*)facep->getTexture()); - } - else - { - mDistanceBins[0].put(facep); - //mDistanceBins[0].push(facep, (U32)(void*)facep->getTexture()); - } - } } -BOOL LLDrawPoolAlpha::removeFace(LLFace *facep) -{ - BOOL removed = FALSE; - - LLDrawPool::removeFace(facep); - - { - for (S32 i = 0; i < NUM_ALPHA_BINS; i++) - { - if (mDistanceBins[i].removeObj(facep) != -1) - { - if (removed) - { - llerrs << "Warning! " << "Face in multiple distance bins on removal" << llendl; - } - removed = TRUE; - } - } - } - if (removed) - { - return TRUE; - } - - return FALSE; -} void LLDrawPoolAlpha::prerender() { @@ -131,442 +52,270 @@ void LLDrawPoolAlpha::prerender() void LLDrawPoolAlpha::beginRenderPass(S32 pass) { - if (mDrawFace.empty()) - { - // No alpha objects, early exit. - return; - } - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); - if (gPipeline.getLightingDetail() >= 2) - { - glEnableClientState(GL_COLOR_ARRAY); - } + glEnableClientState(GL_COLOR_ARRAY); } - -void LLDrawPoolAlpha::render(S32 pass) +void setup_clip_plane(BOOL pre_water) { - LLFastTimer t(LLFastTimer::FTM_RENDER_ALPHA); + F32 height = gAgent.getRegion()->getWaterHeight(); + BOOL above = gCamera->getOrigin().mV[2] > height ? TRUE : FALSE; - if (mDrawFace.empty()) - { - // No alpha objects, early exit. - return; - } - - GLfloat shiny[4] = - { - 0.00f, - 0.25f, - 0.5f, - 0.75f - }; - - GLint specularIndex = (mVertexShaderLevel > 0) ? - gPipeline.mObjectAlphaProgram.mAttribute[LLPipeline::GLSL_SPECULAR_COLOR] : 0; + F64 plane[4]; + + plane[0] = 0; + plane[1] = 0; + plane[2] = above == pre_water ? -1.0 : 1.0; + plane[3] = -plane[2] * height; + + glClipPlane(GL_CLIP_PLANE0, plane); +} - S32 diffTex = 0; - S32 envTex = -1; +void LLDrawPoolAlphaPostWater::render(S32 pass) +{ + LLFastTimer t(LLFastTimer::FTM_RENDER_ALPHA); - if (mVertexShaderLevel > 0) //alpha pass uses same shader as shiny/bump + if (gPipeline.hasRenderType(LLDrawPool::POOL_ALPHA)) { - envTex = gPipeline.mObjectAlphaProgram.enableTexture(LLPipeline::GLSL_ENVIRONMENT_MAP, GL_TEXTURE_CUBE_MAP_ARB); - LLCubeMap* cube_map = gSky.mVOSkyp->getCubeMap(); - if (envTex >= 0 && cube_map) - { - cube_map->bind(); - cube_map->setMatrix(1); - } - - if (specularIndex > 0) - { - glVertexAttrib4fARB(specularIndex, 0, 0, 0, 0); - } - - S32 scatterTex = gPipeline.mObjectAlphaProgram.enableTexture(LLPipeline::GLSL_SCATTER_MAP); - LLViewerImage::bindTexture(gSky.mVOSkyp->getScatterMap(), scatterTex); - - diffTex = gPipeline.mObjectAlphaProgram.enableTexture(LLPipeline::GLSL_DIFFUSE_MAP); + LLGLEnable clip(GL_CLIP_PLANE0); + setup_clip_plane(FALSE); + LLDrawPoolAlpha::render(gPipeline.mAlphaGroupsPostWater); } - - bindGLVertexPointer(); - bindGLTexCoordPointer(); - bindGLNormalPointer(); - if (gPipeline.getLightingDetail() >= 2) + else { - bindGLColorPointer(); + LLDrawPoolAlpha::render(gPipeline.mAlphaGroupsPostWater); } +} - S32 i, j; - glAlphaFunc(GL_GREATER,0.01f); - // This needs to be turned off or there will be lots of artifacting with the clouds - djs - LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE); +void LLDrawPoolAlpha::render(S32 pass) +{ + LLFastTimer t(LLFastTimer::FTM_RENDER_ALPHA); + + LLGLEnable clip(GL_CLIP_PLANE0); + setup_clip_plane(TRUE); + render(gPipeline.mAlphaGroups); +} +void LLDrawPoolAlpha::render(std::vector<LLSpatialGroup*>& groups) +{ + LLGLDepthTest gls_depth(GL_TRUE); LLGLSPipelineAlpha gls_pipeline_alpha; - LLDynamicArray<LLFace*>* distance_bins; - distance_bins = mDistanceBins; + gPipeline.enableLightsDynamic(1.f); + renderAlpha(getVertexDataMask(), groups); - S32 num_bins_no_alpha_test = ((gPickAlphaThreshold != 0.f) && gUsePickAlpha) ? - (NUM_ALPHA_BINS - llmax(2, (S32)(ALPHA_FALLOFF_START_DISTANCE * mInvBinSize))) : - NUM_ALPHA_BINS; - - typedef std::vector<LLFace*> face_list_t; - - for (i = 0; i < num_bins_no_alpha_test; i++) + if (sShowDebugAlpha) { - S32 obj_count = distance_bins[i].count(); - - if (!obj_count) - { - continue; - } - else if (i > (NUM_ALPHA_BINS / 2) && obj_count < 100) - { - face_list_t pri_queue; - pri_queue.reserve(distance_bins[i].count()); - for (j = 0; j < distance_bins[i].count(); j++) - { - pri_queue.push_back(distance_bins[i][j]); - } - std::sort(pri_queue.begin(), pri_queue.end(), LLFace::CompareDistanceGreater()); - - for (face_list_t::iterator iter = pri_queue.begin(); iter != pri_queue.end(); iter++) - { - const LLFace &face = *(*iter); - face.enableLights(); - face.bindTexture(diffTex); - if ((mVertexShaderLevel > 0) && face.getTextureEntry() && specularIndex > 0) - { - U8 s = face.getTextureEntry()->getShiny(); - glVertexAttrib4fARB(specularIndex, shiny[s], shiny[s], shiny[s], shiny[s]); - } - face.renderIndexed(getRawIndices()); - mIndicesDrawn += face.getIndicesCount(); - } - } - else - { - S32 count = distance_bins[i].count(); - for (j = 0; j < count; j++) - { - const LLFace &face = *distance_bins[i][j]; - face.enableLights(); - face.bindTexture(diffTex); - if ((mVertexShaderLevel > 0) && face.getTextureEntry() && specularIndex > 0) - { - U8 s = face.getTextureEntry()->getShiny(); - glVertexAttrib4fARB(specularIndex, shiny[s], shiny[s], shiny[s], shiny[s]); - } - face.renderIndexed(getRawIndices()); - mIndicesDrawn += face.getIndicesCount(); - } - } + glDisableClientState(GL_NORMAL_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); + gPipeline.enableLightsFullbright(LLColor4(1,1,1,1)); + glColor4f(1,0,0,1); + LLViewerImage::sSmokeImagep->addTextureStats(1024.f*1024.f); + LLViewerImage::sSmokeImagep->bind(); + renderAlphaHighlight(LLVertexBuffer::MAP_VERTEX | + LLVertexBuffer::MAP_TEXCOORD, groups); } +} - GLfloat ogl_matrix[16]; - gCamera->getOpenGLTransform(ogl_matrix); +void LLDrawPoolAlpha::renderAlpha(U32 mask, std::vector<LLSpatialGroup*>& groups) +{ +#if !LL_RELEASE_FOR_DOWNLOAD + LLGLState::checkClientArrays(mask); +#endif - for (i = num_bins_no_alpha_test; i < NUM_ALPHA_BINS; i++) - { - BOOL use_pri_queue = distance_bins[i].count() < 100; + LLSpatialBridge* last_bridge = NULL; + LLSpatialPartition* last_part = NULL; + glPushMatrix(); + LLGLDepthTest depth(GL_TRUE, GL_FALSE); - face_list_t pri_queue; - - if (use_pri_queue) - { - pri_queue.reserve(distance_bins[i].count()); - for (j = 0; j < distance_bins[i].count(); j++) - { - pri_queue.push_back(distance_bins[i][j]); - } - std::sort(pri_queue.begin(), pri_queue.end(), LLFace::CompareDistanceGreater()); - } - - S32 count = distance_bins[i].count(); - for (j = 0; j < count; j++) + for (std::vector<LLSpatialGroup*>::iterator i = groups.begin(); i != groups.end(); ++i) + { + LLSpatialGroup* group = *i; + if (group->mSpatialPartition->mRenderByGroup && + !group->isDead()) { - const LLFace &face = use_pri_queue ? *pri_queue[j] : *distance_bins[i][j]; - F32 fade_value = face.mAlphaFade * gPickAlphaThreshold; - - face.enableLights(); - - if (fade_value < 1.f) + LLSpatialPartition* part = group->mSpatialPartition; + if (part != last_part) { + LLSpatialBridge* bridge = part->asBridge(); + if (bridge != last_bridge) { - LLGLDepthTest gls_depth(GL_TRUE, GL_TRUE); - glAlphaFunc(GL_LESS, fade_value); - glBlendFunc(GL_ZERO, GL_ONE); - LLViewerImage::bindTexture(gPipeline.mAlphaSizzleImagep, diffTex); - LLVector4 s_params(ogl_matrix[2], ogl_matrix[6], ogl_matrix[10], ogl_matrix[14]); - LLVector4 t_params(ogl_matrix[1], ogl_matrix[5], ogl_matrix[9], ogl_matrix[13]); - - LLGLEnable gls_texgen_s(GL_TEXTURE_GEN_S); - LLGLEnable gls_texgen_t(GL_TEXTURE_GEN_T); - glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); - glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); - glTexGenfv(GL_S, GL_OBJECT_PLANE, s_params.mV); - glTexGenfv(GL_T, GL_OBJECT_PLANE, t_params.mV); - if ((mVertexShaderLevel > 0) && face.getTextureEntry() && specularIndex > 0) + glPopMatrix(); + glPushMatrix(); + if (bridge) { - U8 s = face.getTextureEntry()->getShiny(); - glVertexAttrib4fARB(specularIndex, shiny[s], shiny[s], shiny[s], shiny[s]); + glMultMatrixf((F32*) bridge->mDrawable->getRenderMatrix().mMatrix); } - face.renderIndexed(getRawIndices()); + last_bridge = bridge; } - { - // should get GL_GREATER to work, as it's faster - LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE, GL_LESS); - glAlphaFunc(GL_GEQUAL, fade_value); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - face.bindTexture(diffTex); - if ((mVertexShaderLevel > 0) && face.getTextureEntry() && specularIndex > 0) - { - U8 s = face.getTextureEntry()->getShiny(); - glVertexAttrib4fARB(specularIndex, shiny[s], shiny[s], shiny[s], shiny[s]); - } - face.renderIndexed(getRawIndices()); - } +// if (!last_part || part->mDepthMask != last_part->mDepthMask) +// { +// glDepthMask(part->mDepthMask); +// } + last_part = part; } - // render opaque portion of actual texture - glAlphaFunc(GL_GREATER, 0.98f); - - face.bindTexture(diffTex); - face.renderIndexed(getRawIndices()); - - glAlphaFunc(GL_GREATER, 0.01f); - - mIndicesDrawn += face.getIndicesCount(); + renderGroupAlpha(group,LLRenderPass::PASS_ALPHA,mask,TRUE); } } + + glPopMatrix(); +} - if (mVertexShaderLevel > 0) //single pass shader driven shiny/bump - { - gPipeline.mObjectAlphaProgram.disableTexture(LLPipeline::GLSL_ENVIRONMENT_MAP, GL_TEXTURE_CUBE_MAP_ARB); - LLCubeMap* cube_map = gSky.mVOSkyp->getCubeMap(); - if (envTex >= 0 && cube_map) - { - cube_map->restoreMatrix(); - } - gPipeline.mObjectAlphaProgram.disableTexture(LLPipeline::GLSL_SCATTER_MAP); - gPipeline.mObjectAlphaProgram.disableTexture(LLPipeline::GLSL_DIFFUSE_MAP); - - glClientActiveTextureARB(GL_TEXTURE0_ARB); - glActiveTextureARB(GL_TEXTURE0_ARB); - glEnable(GL_TEXTURE_2D); - } +void LLDrawPoolAlpha::renderAlphaHighlight(U32 mask, std::vector<LLSpatialGroup*>& groups) +{ +#if !LL_RELEASE_FOR_DOWNLOAD + LLGLState::checkClientArrays(mask); +#endif - if (sShowDebugAlpha) + LLSpatialBridge* last_bridge = NULL; + LLSpatialPartition* last_part = NULL; + glPushMatrix(); + + for (std::vector<LLSpatialGroup*>::iterator i = groups.begin(); i != groups.end(); ++i) { - gPipeline.disableLights(); - if ((mVertexShaderLevel > 0)) + LLSpatialGroup* group = *i; + if (group->mSpatialPartition->mRenderByGroup && + !group->isDead()) { - gPipeline.mHighlightProgram.bind(); - } - - LLViewerImage::sSmokeImagep->bind(); - LLOverrideFaceColor override_color(this, 1.f, 0.f, 0.f, 1.f); - glColor4f(1.f, 0.f, 0.f, 1.f); // in case vertex shaders are enabled - glDisableClientState(GL_COLOR_ARRAY); - - for (S32 i = 0; i < NUM_ALPHA_BINS; i++) - { - if (distance_bins[i].count() < 100) + LLSpatialPartition* part = group->mSpatialPartition; + if (part != last_part) { - face_list_t pri_queue; - pri_queue.reserve(distance_bins[i].count()); - for (j = 0; j < distance_bins[i].count(); j++) - { - pri_queue.push_back(distance_bins[i][j]); - } - std::sort(pri_queue.begin(), pri_queue.end(), LLFace::CompareDistanceGreater()); - - for (face_list_t::iterator iter = pri_queue.begin(); iter != pri_queue.end(); iter++) + LLSpatialBridge* bridge = part->asBridge(); + if (bridge != last_bridge) { - const LLFace &face = *(*iter); - face.renderIndexed(getRawIndices()); - mIndicesDrawn += face.getIndicesCount(); + glPopMatrix(); + glPushMatrix(); + if (bridge) + { + glMultMatrixf((F32*) bridge->mDrawable->getRenderMatrix().mMatrix); + } + last_bridge = bridge; } + + last_part = part; } - else + + std::vector<LLDrawInfo*>& draw_info = group->mDrawMap[LLRenderPass::PASS_ALPHA]; + + for (std::vector<LLDrawInfo*>::const_iterator k = draw_info.begin(); k != draw_info.end(); ++k) { - for (j = 0; j < distance_bins[i].count(); j++) + LLDrawInfo& params = **k; + + if (params.mParticle) { - const LLFace &face = *distance_bins[i][j]; - face.renderIndexed(getRawIndices()); - mIndicesDrawn += face.getIndicesCount(); + continue; } + params.mVertexBuffer->setBuffer(mask); + U32* indices_pointer = (U32*) params.mVertexBuffer->getIndicesPointer(); + glDrawRangeElements(GL_TRIANGLES, params.mStart, params.mEnd, params.mCount, + GL_UNSIGNED_INT, indices_pointer+params.mOffset); + + addIndicesDrawn(params.mCount); } } - - if ((mVertexShaderLevel > 0)) - { - gPipeline.mHighlightProgram.unbind(); - } - } - + glPopMatrix(); } -void LLDrawPoolAlpha::renderForSelect() -{ - if (mDrawFace.empty() || !mMemory.count()) - { - return; - } - - // force faces on focus object to proper alpha cutoff based on object bbox distance - if (gAgent.getFocusObject()) - { - LLDrawable* drawablep = gAgent.getFocusObject()->mDrawable; - - if (drawablep) - { - const S32 num_faces = drawablep->getNumFaces(); - - for (S32 f = 0; f < num_faces; f++) - { - LLFace* facep = drawablep->getFace(f); - facep->mDistance = gAgent.getFocusObjectDist(); - } - } - } +void LLDrawPoolAlpha::renderGroupAlpha(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture) +{ + BOOL light_enabled = TRUE; - glEnableClientState (GL_VERTEX_ARRAY); - glEnableClientState (GL_TEXTURE_COORD_ARRAY); + std::vector<LLDrawInfo*>& draw_info = group->mDrawMap[type]; + + U32 prim_type = GL_TRIANGLES; - LLGLSObjectSelectAlpha gls_alpha; + //F32 width = (F32) gViewerWindow->getWindowDisplayWidth(); - glBlendFunc(GL_ONE, GL_ZERO); - if (gPickTransparent) + //F32 view = gCamera->getView(); + + if (group->mSpatialPartition->mDrawableType == LLPipeline::RENDER_TYPE_CLOUDS) { - glAlphaFunc(GL_GEQUAL, 0.f); + glAlphaFunc(GL_GREATER, 0.f); } else { - glAlphaFunc(GL_GEQUAL, gPickAlphaThreshold); + glAlphaFunc(GL_GREATER, 0.01f); } - bindGLVertexPointer(); - bindGLTexCoordPointer(); - - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE); - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE); - - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS); - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR); - - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE); - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA); - - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_PRIMARY_COLOR_ARB); - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB, GL_SRC_ALPHA); + /*LLGLEnable point_sprite(GL_POINT_SPRITE_ARB); - LLDynamicArray<LLFace*>* distance_bins; - distance_bins = mDistanceBins; - - S32 i; - S32 j; + if (gGLManager.mHasPointParameters) + { + glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, TRUE); + glPointParameterfARB(GL_POINT_SIZE_MIN_ARB, 0.f); + glPointParameterfARB(GL_POINT_SIZE_MAX_ARB, width*16.f); + glPointSize(width/(view*view)); + }*/ - for (i = 0; i < NUM_ALPHA_BINS; i++) + for (std::vector<LLDrawInfo*>::const_iterator k = draw_info.begin(); k != draw_info.end(); ++k) { - S32 distance_bin_size = distance_bins[i].count(); - if (distance_bin_size) + LLDrawInfo& params = **k; + if (texture && params.mTexture.notNull()) { - for (j = 0; j < distance_bin_size; j++) + params.mTexture->bind(); + params.mTexture->addTextureStats(params.mVSize); + if (params.mTextureMatrix) { - const LLFace &face = *distance_bins[i][j]; - - if (face.getDrawable() && !face.getDrawable()->isDead() && (face.getViewerObject()->mGLName)) - { - face.bindTexture(); - face.renderForSelect(); - } + glMatrixMode(GL_TEXTURE); + glLoadMatrixf((GLfloat*) params.mTextureMatrix->mMatrix); } } - } - - glAlphaFunc(GL_GREATER, 0.01f); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - glDisableClientState (GL_TEXTURE_COORD_ARRAY); -} - - -void LLDrawPoolAlpha::renderFaceSelected(LLFace *facep, - LLImageGL *image, - const LLColor4 &color, - const S32 index_offset, const S32 index_count) -{ - facep->renderSelected(image, color, index_offset, index_count); -} - - -void LLDrawPoolAlpha::resetDrawOrders() -{ - LLDrawPool::resetDrawOrders(); - - for (S32 i = 0; i < NUM_ALPHA_BINS; i++) - { - mDistanceBins[i].resize(0); - } -} - -BOOL LLDrawPoolAlpha::verify() const -{ - S32 i, j; - BOOL ok; - ok = LLDrawPool::verify(); - for (i = 0; i < NUM_ALPHA_BINS; i++) - { - for (j = 0; j < mDistanceBins[i].count(); j++) + + if (params.mFullbright) { - const LLFace &face = *mDistanceBins[i][j]; - if (!face.verify()) + if (light_enabled) { - ok = FALSE; + gPipeline.enableLightsFullbright(LLColor4(1,1,1,1)); + light_enabled = FALSE; } } - } - return ok; -} - -LLViewerImage *LLDrawPoolAlpha::getDebugTexture() -{ - return LLViewerImage::sSmokeImagep; -} + else if (!light_enabled) + { + gPipeline.enableLightsDynamic(1.f); + light_enabled = TRUE; + } + /*if (params.mParticle) + { + F32 size = params.mPartSize; + size *= size; + float param[] = { 0, 0, 0.01f/size*view*view }; + prim_type = GL_POINTS; + glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB, param); + } + else*/ + { + prim_type = GL_TRIANGLES; + } -LLColor3 LLDrawPoolAlpha::getDebugColor() const -{ - return LLColor3(1.f, 0.f, 0.f); -} + params.mVertexBuffer->setBuffer(mask); + U32* indices_pointer = (U32*) params.mVertexBuffer->getIndicesPointer(); + glDrawRangeElements(prim_type, params.mStart, params.mEnd, params.mCount, + GL_UNSIGNED_INT, indices_pointer+params.mOffset); + + addIndicesDrawn(params.mCount); -S32 LLDrawPoolAlpha::getMaterialAttribIndex() -{ - return gPipeline.mObjectAlphaProgram.mAttribute[LLPipeline::GLSL_MATERIAL_COLOR]; -} + if (params.mTextureMatrix && texture && params.mTexture.notNull()) + { + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + } + } -// virtual -void LLDrawPoolAlpha::enableShade() -{ - glDisableClientState(GL_COLOR_ARRAY); -} + if (!light_enabled) + { + gPipeline.enableLightsDynamic(1.f); + } -// virtual -void LLDrawPoolAlpha::disableShade() -{ - glEnableClientState(GL_COLOR_ARRAY); -} + /*glPointSize(1.f); -// virtual -void LLDrawPoolAlpha::setShade(F32 shade) -{ - glColor4f(0,0,0,shade); -} + if (gGLManager.mHasPointParameters) + { + float param[] = {1, 0, 0 }; + glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB, param); + }*/ +} diff --git a/indra/newview/lldrawpoolalpha.h b/indra/newview/lldrawpoolalpha.h index 6f24959e50..e33bbacd82 100644 --- a/indra/newview/lldrawpoolalpha.h +++ b/indra/newview/lldrawpoolalpha.h @@ -10,55 +10,43 @@ #define LL_LLDRAWPOOLALPHA_H #include "lldrawpool.h" -#include "llviewerimage.h" #include "llframetimer.h" class LLFace; class LLColor4; -class LLDrawPoolAlpha: public LLDrawPool +class LLDrawPoolAlpha: public LLRenderPass { public: - LLDrawPoolAlpha(); - /*virtual*/ ~LLDrawPoolAlpha(); - - /*virtual*/ LLDrawPool *instancePool(); - - /*virtual*/ void beginRenderPass(S32 pass = 0); - /*virtual*/ void render(S32 pass = 0); - /*virtual*/ void renderFaceSelected(LLFace *facep, LLImageGL *image, const LLColor4 &color, - const S32 index_offset = 0, const S32 index_count = 0); - /*virtual*/ void prerender(); - /*virtual*/ void renderForSelect(); - - /*virtual*/ void enqueue(LLFace *face); - /*virtual*/ BOOL removeFace(LLFace *face); - /*virtual*/ void resetDrawOrders(); - - /*virtual*/ void enableShade(); - /*virtual*/ void disableShade(); - /*virtual*/ void setShade(F32 shade); - - - virtual S32 getMaterialAttribIndex(); - - BOOL mRebuiltLastFrame; enum { - NUM_ALPHA_BINS = 1024 + VERTEX_DATA_MASK = LLVertexBuffer::MAP_VERTEX | + LLVertexBuffer::MAP_NORMAL | + LLVertexBuffer::MAP_COLOR | + LLVertexBuffer::MAP_TEXCOORD }; + virtual U32 getVertexDataMask() { return VERTEX_DATA_MASK; } + + LLDrawPoolAlpha(U32 type = LLDrawPool::POOL_ALPHA); + /*virtual*/ ~LLDrawPoolAlpha(); - /*virtual*/ BOOL verify() const; - /*virtual*/ LLViewerImage *getDebugTexture(); - /*virtual*/ LLColor3 getDebugColor() const; // For AGP debug display + /*virtual*/ void beginRenderPass(S32 pass = 0); + virtual void render(S32 pass = 0); + void render(std::vector<LLSpatialGroup*>& groups); + /*virtual*/ void prerender(); + void renderGroupAlpha(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture = TRUE); + void renderAlpha(U32 mask, std::vector<LLSpatialGroup*>& groups); + void renderAlphaHighlight(U32 mask, std::vector<LLSpatialGroup*>& groups); + static BOOL sShowDebugAlpha; -protected: - F32 mMinDistance; - F32 mMaxDistance; - F32 mInvBinSize; +}; - LLDynamicArray<LLFace*> mDistanceBins[NUM_ALPHA_BINS]; +class LLDrawPoolAlphaPostWater : public LLDrawPoolAlpha +{ +public: + LLDrawPoolAlphaPostWater(); + virtual void render(S32 pass = 0); }; #endif // LL_LLDRAWPOOLALPHA_H diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp index dfe75084b5..9b9825deff 100644 --- a/indra/newview/lldrawpoolavatar.cpp +++ b/indra/newview/lldrawpoolavatar.cpp @@ -13,7 +13,6 @@ #include "llvoavatar.h" #include "m3math.h" -#include "llagparray.h" #include "llagent.h" #include "lldrawable.h" #include "llface.h" @@ -23,6 +22,11 @@ #include "noise.h" #include "pipeline.h" +static U32 sDataMask = LLDrawPoolAvatar::VERTEX_DATA_MASK; +static U32 sBufferUsage = GL_STREAM_DRAW_ARB; +static U32 sShaderLevel = 0; +static LLGLSLShader* sVertexProgram = NULL; + extern F32 gFrameDTClamped; extern BOOL gUseGLPick; @@ -56,53 +60,13 @@ S32 AVATAR_VERTEX_BYTES = 48; BOOL gAvatarEmbossBumpMap = FALSE; +static BOOL sRenderingSkinned = FALSE; LLDrawPoolAvatar::LLDrawPoolAvatar() : -LLDrawPool(POOL_AVATAR, - DATA_SIMPLE_IL_MASK, - DATA_VERTEX_WEIGHTS_MASK | DATA_CLOTHING_WEIGHTS_MASK ) +LLFacePool(POOL_AVATAR) { - mCleanupUnused = FALSE; - - // Overide the data layout - mDataMaskIL = 0; - mStride = 0; - for (S32 i = 0; i < DATA_MAX_TYPES; i++) - { - mDataOffsets[i] = 0; - } - - // Note: padding is to speed up SSE code - mDataMaskIL |= DATA_VERTICES_MASK; - mDataOffsets[DATA_VERTICES] = mStride; - mStride += sDataSizes[DATA_VERTICES]; - - mStride += 4; - - mDataMaskIL |= DATA_NORMALS_MASK; - mDataOffsets[DATA_NORMALS] = mStride; - mStride += sDataSizes[DATA_NORMALS]; - - mStride += 4; - - // Note: binormals are stripped off in software blending - mDataMaskIL |= DATA_BINORMALS_MASK; - mDataOffsets[DATA_BINORMALS] = mStride; - mStride += sDataSizes[DATA_BINORMALS]; - - mStride += 4; // To keep the structure 16-byte aligned (for SSE happiness) - - mDataMaskIL |= DATA_TEX_COORDS0_MASK; - mDataOffsets[DATA_TEX_COORDS0] = mStride; - mStride += sDataSizes[DATA_TEX_COORDS0]; - - mDataMaskIL |= DATA_TEX_COORDS1_MASK; - mDataOffsets[DATA_TEX_COORDS1] = mStride; - mStride += sDataSizes[DATA_TEX_COORDS1]; - //LLDebugVarMessageBox::show("acceleration", &CLOTHING_ACCEL_FORCE_FACTOR, 10.f, 0.1f); - //LLDebugVarMessageBox::show("gravity", &CLOTHING_GRAVITY_EFFECT, 10.f, 0.1f); - + //LLDebugVarMessageBox::show("gravity", &CLOTHING_GRAVITY_EFFECT, 10.f, 0.1f); } //----------------------------------------------------------------------------- @@ -113,41 +77,194 @@ LLDrawPool *LLDrawPoolAvatar::instancePool() return new LLDrawPoolAvatar(); } +BOOL gRenderAvatar = TRUE; +static LLMatrix4 sModelViewMatrix = LLMatrix4(); -S32 LLDrawPoolAvatar::rebuild() +S32 LLDrawPoolAvatar::getVertexShaderLevel() const { - mRebuildTime++; - if (mRebuildTime > mRebuildFreq) - { - flushAGP(); - - mRebuildTime = 0; - } - - return 0; + return (S32) gPipeline.getVertexShaderLevel(LLPipeline::SHADER_AVATAR); } -BOOL gRenderAvatar = TRUE; - void LLDrawPoolAvatar::prerender() { mVertexShaderLevel = gPipeline.getVertexShaderLevel(LLPipeline::SHADER_AVATAR); + sShaderLevel = mVertexShaderLevel; + + if (sShaderLevel > 0) + { + sBufferUsage = GL_STATIC_DRAW_ARB; + } + else + { + sBufferUsage = GL_STREAM_DRAW_ARB; + } +} + +LLMatrix4& LLDrawPoolAvatar::getModelView() +{ + return sModelViewMatrix; } //----------------------------------------------------------------------------- // render() //----------------------------------------------------------------------------- + +S32 LLDrawPoolAvatar::getNumPasses() +{ + return 3; +} + void LLDrawPoolAvatar::render(S32 pass) { LLFastTimer t(LLFastTimer::FTM_RENDER_CHARACTERS); - renderAvatars(NULL); // render all avatars + renderAvatars(NULL, pass); // render all avatars +} + +void LLDrawPoolAvatar::beginRenderPass(S32 pass) +{ + //reset vertex buffer mappings + LLVertexBuffer::unbind(); + + switch (pass) + { + case 0: + beginFootShadow(); + break; + case 1: + glGetFloatv(GL_MODELVIEW_MATRIX, (F32*) sModelViewMatrix.mMatrix); + beginRigid(); + break; + case 2: + beginSkinned(); + break; + } +} + +void LLDrawPoolAvatar::endRenderPass(S32 pass) +{ + switch (pass) + { + case 0: + endFootShadow(); + break; + case 1: + endRigid(); + break; + case 2: + endSkinned(); + } +} + +void LLDrawPoolAvatar::beginFootShadow() +{ + glDepthMask(GL_FALSE); + gPipeline.enableLightsFullbright(LLColor4(1,1,1,1)); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); +} + +void LLDrawPoolAvatar::endFootShadow() +{ + gPipeline.enableLightsDynamic(1.f); + glDepthMask(GL_TRUE); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); +} + +void LLDrawPoolAvatar::beginRigid() +{ + sVertexProgram = &gPipeline.mAvatarEyeballProgram; + glEnableClientState(GL_NORMAL_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + + if (sShaderLevel > 0) + { //eyeballs render with the specular shader + gPipeline.mAvatarEyeballProgram.bind(); + gPipeline.mMaterialIndex = gPipeline.mAvatarEyeballProgram.mAttribute[LLPipeline::GLSL_MATERIAL_COLOR]; + gPipeline.mSpecularIndex = gPipeline.mAvatarEyeballProgram.mAttribute[LLPipeline::GLSL_SPECULAR_COLOR]; + } +} + +void LLDrawPoolAvatar::endRigid() +{ + glDisableClientState(GL_NORMAL_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); +} + +void LLDrawPoolAvatar::beginSkinned() +{ + glEnableClientState(GL_NORMAL_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + + sVertexProgram = &gPipeline.mAvatarProgram; + + if (sShaderLevel > 0) // for hardware blending + { + sRenderingSkinned = TRUE; + glClientActiveTextureARB(GL_TEXTURE1_ARB); + if (sShaderLevel >= SHADER_LEVEL_BUMP) + { + gPipeline.mMaterialIndex = sVertexProgram->mAttribute[LLPipeline::GLSL_MATERIAL_COLOR]; + gPipeline.mSpecularIndex = sVertexProgram->mAttribute[LLPipeline::GLSL_SPECULAR_COLOR]; + } + sVertexProgram->bind(); + if (sShaderLevel >= SHADER_LEVEL_CLOTH) + { + enable_cloth_weights(sVertexProgram->mAttribute[LLPipeline::GLSL_AVATAR_CLOTHING]); + } + enable_vertex_weighting(sVertexProgram->mAttribute[LLPipeline::GLSL_AVATAR_WEIGHT]); + + if (sShaderLevel >= SHADER_LEVEL_BUMP) + { + enable_binormals(sVertexProgram->mAttribute[LLPipeline::GLSL_BINORMAL]); + } + + sVertexProgram->enableTexture(LLPipeline::GLSL_BUMP_MAP); + glActiveTextureARB(GL_TEXTURE0_ARB); + } } -void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, BOOL no_shaders) +void LLDrawPoolAvatar::endSkinned() { - if (no_shaders) + // if we're in software-blending, remember to set the fence _after_ we draw so we wait till this rendering is done + if (sShaderLevel > 0) { - mVertexShaderLevel = 0; + sRenderingSkinned = FALSE; + sVertexProgram->disableTexture(LLPipeline::GLSL_BUMP_MAP); + glActiveTextureARB(GL_TEXTURE0_ARB); + glClientActiveTextureARB(GL_TEXTURE0_ARB); + disable_vertex_weighting(sVertexProgram->mAttribute[LLPipeline::GLSL_AVATAR_WEIGHT]); + if (sShaderLevel >= SHADER_LEVEL_BUMP) + { + disable_binormals(sVertexProgram->mAttribute[LLPipeline::GLSL_BINORMAL]); + } + if ((sShaderLevel >= SHADER_LEVEL_CLOTH)) + { + disable_cloth_weights(sVertexProgram->mAttribute[LLPipeline::GLSL_AVATAR_CLOTHING]); + } + + sVertexProgram->unbind(); + } + + glActiveTextureARB(GL_TEXTURE0_ARB); + glClientActiveTextureARB(GL_TEXTURE0_ARB); + + glDisableClientState(GL_NORMAL_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); +} + + +void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) +{ + if (pass == -1) + { + for (S32 i = 1; i < getNumPasses(); i++) + { //skip foot shadows + prerender(); + beginRenderPass(i); + renderAvatars(single_avatar, i); + endRenderPass(i); + } + + return; } if (!gRenderAvatar) @@ -176,13 +293,95 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, BOOL no_shaders) avatarp = (LLVOAvatar *)(facep->getDrawable()->getVObj()); } - if (avatarp->isDead() || avatarp->mDrawable.isNull()) + if (avatarp->isDead() || avatarp->mDrawable.isNull()) { return; } LLOverrideFaceColor color(this, 1.0f, 1.0f, 1.0f, 1.0f); + if (pass == 0) + { + if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_FOOT_SHADOWS)) + { + mIndicesDrawn += avatarp->renderFootShadows(); + } + return; + } + + if (avatarp->mSpecialRenderMode == 0) // normal + { + gPipeline.enableLightsAvatar(avatarp->mDrawable->getSunShadowFactor()); + } + else if (avatarp->mSpecialRenderMode == 1) // anim preview + { + gPipeline.enableLightsAvatarEdit(LLColor4(0.7f, 0.6f, 0.3f, 1.f)); + } + else // 2=image preview, 3=morph view + { + gPipeline.enableLightsAvatarEdit(LLColor4(.5f, .5f, .5f, 1.f)); + } + + if (pass == 1) + { + // render rigid meshes (eyeballs) first + mIndicesDrawn += avatarp->renderRigid(); + + if (!gRenderForSelect && avatarp->mIsSelf && LLVOAvatar::sAvatarLoadTest) + { + LLVector3 orig_pos_root = avatarp->mRoot.getPosition(); + LLVector3 next_pos_root = orig_pos_root; + for (S32 i = 0; i < NUM_TEST_AVATARS; i++) + { + next_pos_root.mV[VX] += 1.f; + if (i % 5 == 0) + { + next_pos_root.mV[VY] += 1.f; + next_pos_root.mV[VX] = orig_pos_root.mV[VX]; + } + + avatarp->mRoot.setPosition(next_pos_root); // avatar load test + avatarp->mRoot.updateWorldMatrixChildren(); // avatar load test + + mIndicesDrawn += avatarp->renderRigid(); + } + avatarp->mRoot.setPosition(orig_pos_root); // avatar load test + avatarp->mRoot.updateWorldMatrixChildren(); // avatar load test + } + return; + } + + + if (sShaderLevel > 0) + { + gPipeline.mAvatarMatrixParam = sVertexProgram->mUniform[LLPipeline::GLSL_AVATAR_MATRIX]; + } + + if ((sShaderLevel >= SHADER_LEVEL_CLOTH)) + { + LLMatrix4 rot_mat; + gCamera->getMatrixToLocal(rot_mat); + LLMatrix4 cfr(OGL_TO_CFR_ROTATION); + rot_mat *= cfr; + + LLVector4 wind; + wind.setVec(avatarp->mWindVec); + wind.mV[VW] = 0; + wind = wind * rot_mat; + wind.mV[VW] = avatarp->mWindVec.mV[VW]; + + sVertexProgram->vertexAttrib4fv(LLPipeline::GLSL_AVATAR_WIND, wind.mV); + F32 phase = -1.f * (avatarp->mRipplePhase); + + F32 freq = 7.f + (noise1(avatarp->mRipplePhase) * 2.f); + LLVector4 sin_params(freq, freq, freq, phase); + sVertexProgram->vertexAttrib4fv(LLPipeline::GLSL_AVATAR_SINWAVE, sin_params.mV); + + LLVector4 gravity(0.f, 0.f, -CLOTHING_GRAVITY_EFFECT, 0.f); + gravity = gravity * rot_mat; + sVertexProgram->vertexAttrib4fv(LLPipeline::GLSL_AVATAR_GRAVITY, gravity.mV); + } + if( !single_avatar || (avatarp == single_avatar) ) { if (LLVOAvatar::sShowCollisionVolumes) @@ -191,8 +390,6 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, BOOL no_shaders) avatarp->renderCollisionVolumes(); } - LLGLEnable normalize(GL_NORMALIZE); - if (avatarp->mIsSelf && LLAgent::sDebugDisplayTarget) { LLGLSNoTexture gls_no_texture; @@ -248,171 +445,8 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, BOOL no_shaders) color.setColor(1.0f, 1.0f, 1.0f, 1.0f); } - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_NORMAL_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - - LLGLSLShader* vertex_program = &gPipeline.mAvatarProgram; - if (mVertexShaderLevel > 0) - { - gPipeline.mAvatarMatrixParam = vertex_program->mUniform[LLPipeline::GLSL_AVATAR_MATRIX]; - } - - //-------------------------------------------------------------------------------- - // this is where we first hit the software blending path - // if enabled, we need to set up the proper buffers and avoid setting other state - //-------------------------------------------------------------------------------- - if (!(mVertexShaderLevel > 0)) - { - - // performance could be increased by better utilizing the buffers, for example, only using 1k buffers for lo-res - // avatars. But the only problem with using fewer buffers is that we're more likely to wait for a fence to complete - - // vertex format: - // vertices 12 - // texcoords 8 - // normals 12 - // binormals 12 - // padding 4 - // total 48 - - // Rotate to the next buffer, round-robin. - gPipeline.bufferRotate(); - - // Wait until the hardware is done reading the last set of vertices from the buffer before writing the next set. - gPipeline.bufferWaitFence(); - - // Need to do this because we may be rendering without AGP even in AGP mode - U8* buffer_offset_start = gPipeline.bufferGetScratchMemory(); - glVertexPointer( 3, GL_FLOAT, AVATAR_VERTEX_BYTES, buffer_offset_start + AVATAR_OFFSET_POS); - glTexCoordPointer(2, GL_FLOAT, AVATAR_VERTEX_BYTES, buffer_offset_start + AVATAR_OFFSET_TEX0); - glNormalPointer( GL_FLOAT, AVATAR_VERTEX_BYTES, buffer_offset_start + AVATAR_OFFSET_NORMAL); - - } - - if ((mVertexShaderLevel > 0)) // for hardware blending - { - bindGLVertexPointer(); - bindGLNormalPointer(); - bindGLTexCoordPointer(0); - } - - if ((mVertexShaderLevel > 0)) - { //eyeballs render with the specular shader - gPipeline.mAvatarEyeballProgram.bind(); - gPipeline.mMaterialIndex = gPipeline.mAvatarEyeballProgram.mAttribute[LLPipeline::GLSL_MATERIAL_COLOR]; - gPipeline.mSpecularIndex = gPipeline.mAvatarEyeballProgram.mAttribute[LLPipeline::GLSL_SPECULAR_COLOR]; - - S32 index = gPipeline.mAvatarEyeballProgram.enableTexture(LLPipeline::GLSL_SCATTER_MAP); - gSky.mVOSkyp->getScatterMap()->bind(index); - - glActiveTextureARB(GL_TEXTURE0_ARB); - } - - if (avatarp->mSpecialRenderMode == 0) // normal - { - gPipeline.enableLightsAvatar(avatarp->mDrawable->getSunShadowFactor()); - } - else if (avatarp->mSpecialRenderMode == 1) // anim preview - { - gPipeline.enableLightsAvatarEdit(LLColor4(0.7f, 0.6f, 0.3f, 1.f)); - } - else // 2=image preview, 3=morph view - { - gPipeline.enableLightsAvatarEdit(LLColor4(.5f, .5f, .5f, 1.f)); - } - - // render rigid meshes (eyeballs) first - mIndicesDrawn += avatarp->renderRigid(); - - if ((mVertexShaderLevel > 0)) - { - gPipeline.mAvatarEyeballProgram.disableTexture(LLPipeline::GLSL_SCATTER_MAP); - glActiveTextureARB(GL_TEXTURE0_ARB); - } - - if (!gRenderForSelect && avatarp->mIsSelf && LLVOAvatar::sAvatarLoadTest) - { - LLVector3 orig_pos_root = avatarp->mRoot.getPosition(); - LLVector3 next_pos_root = orig_pos_root; - for (S32 i = 0; i < NUM_TEST_AVATARS; i++) - { - next_pos_root.mV[VX] += 1.f; - if (i % 5 == 0) - { - next_pos_root.mV[VY] += 1.f; - next_pos_root.mV[VX] = orig_pos_root.mV[VX]; - } - - avatarp->mRoot.setPosition(next_pos_root); // avatar load test - avatarp->mRoot.updateWorldMatrixChildren(); // avatar load test - - mIndicesDrawn += avatarp->renderRigid(); - } - avatarp->mRoot.setPosition(orig_pos_root); // avatar load test - avatarp->mRoot.updateWorldMatrixChildren(); // avatar load test - } - - if ((mVertexShaderLevel > 0)) // for hardware blending - { - glClientActiveTextureARB(GL_TEXTURE1_ARB); - if ((mVertexShaderLevel >= SHADER_LEVEL_BUMP)) - { - bindGLTexCoordPointer(1); - - bindGLBinormalPointer(vertex_program->mAttribute[LLPipeline::GLSL_BINORMAL]); - gPipeline.mMaterialIndex = vertex_program->mAttribute[LLPipeline::GLSL_MATERIAL_COLOR]; - gPipeline.mSpecularIndex = vertex_program->mAttribute[LLPipeline::GLSL_SPECULAR_COLOR]; - } - glClientActiveTextureARB(GL_TEXTURE0_ARB); - bindGLTexCoordPointer(0); - vertex_program->bind(); - bindGLVertexWeightPointer(vertex_program->mAttribute[LLPipeline::GLSL_AVATAR_WEIGHT]); - if ((mVertexShaderLevel >= SHADER_LEVEL_CLOTH)) - { - bindGLVertexClothingWeightPointer(vertex_program->mAttribute[LLPipeline::GLSL_AVATAR_CLOTHING]); - enable_cloth_weights(vertex_program->mAttribute[LLPipeline::GLSL_AVATAR_CLOTHING]); - } - enable_vertex_weighting(vertex_program->mAttribute[LLPipeline::GLSL_AVATAR_WEIGHT]); - - if ((mVertexShaderLevel >= SHADER_LEVEL_BUMP)) - { - enable_binormals(vertex_program->mAttribute[LLPipeline::GLSL_BINORMAL]); - } - - vertex_program->enableTexture(LLPipeline::GLSL_BUMP_MAP); - S32 index = vertex_program->enableTexture(LLPipeline::GLSL_SCATTER_MAP); - gSky.mVOSkyp->getScatterMap()->bind(index); - glActiveTextureARB(GL_TEXTURE0_ARB); - } - - if ((mVertexShaderLevel >= SHADER_LEVEL_CLOTH)) - { - LLMatrix4 rot_mat; - gCamera->getMatrixToLocal(rot_mat); - LLMatrix4 cfr(OGL_TO_CFR_ROTATION); - rot_mat *= cfr; - - LLVector4 wind; - wind.setVec(avatarp->mWindVec); - wind.mV[VW] = 0; - wind = wind * rot_mat; - wind.mV[VW] = avatarp->mWindVec.mV[VW]; - - vertex_program->vertexAttrib4fv(LLPipeline::GLSL_AVATAR_WIND, wind.mV); - F32 phase = -1.f * (avatarp->mRipplePhase); - - F32 freq = 7.f + (noise1(avatarp->mRipplePhase) * 2.f); - LLVector4 sin_params(freq, freq, freq, phase); - vertex_program->vertexAttrib4fv(LLPipeline::GLSL_AVATAR_SINWAVE, sin_params.mV); - - LLVector4 gravity(0.f, 0.f, -CLOTHING_GRAVITY_EFFECT, 0.f); - gravity = gravity * rot_mat; - vertex_program->vertexAttrib4fv(LLPipeline::GLSL_AVATAR_GRAVITY, gravity.mV); - } - mIndicesDrawn += avatarp->renderSkinned(AVATAR_RENDER_PASS_SINGLE); - + if (!gRenderForSelect && avatarp->mIsSelf && LLVOAvatar::sAvatarLoadTest) { LLVector3 orig_pos_root = avatarp->mRoot.getPosition(); @@ -434,31 +468,6 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, BOOL no_shaders) avatarp->mRoot.setPosition(orig_pos_root); // avatar load test avatarp->mRoot.updateWorldMatrixChildren(); // avatar load test } - - // if we're in software-blending, remember to set the fence _after_ we draw so we wait till this rendering is done - if (!(mVertexShaderLevel > 0)) - { - // want for the previously bound fence to finish - gPipeline.bufferSendFence(); - } - else - { - vertex_program->disableTexture(LLPipeline::GLSL_BUMP_MAP); - vertex_program->disableTexture(LLPipeline::GLSL_SCATTER_MAP); - glActiveTextureARB(GL_TEXTURE0_ARB); - glClientActiveTextureARB(GL_TEXTURE0_ARB); - disable_vertex_weighting(vertex_program->mAttribute[LLPipeline::GLSL_AVATAR_WEIGHT]); - if ((mVertexShaderLevel >= SHADER_LEVEL_BUMP)) - { - disable_binormals(vertex_program->mAttribute[LLPipeline::GLSL_BINORMAL]); - } - if ((mVertexShaderLevel >= SHADER_LEVEL_CLOTH)) - { - disable_cloth_weights(vertex_program->mAttribute[LLPipeline::GLSL_AVATAR_CLOTHING]); - } - - vertex_program->unbind(); - } } } @@ -471,14 +480,13 @@ void LLDrawPoolAvatar::renderForSelect() { return; } - //gGLSObjectSelectDepthAlpha.set(); - + if (!gRenderAvatar) { return; } - if (mDrawFace.empty() || !mMemory.count()) + if (mDrawFace.empty()) { return; } @@ -498,80 +506,38 @@ void LLDrawPoolAvatar::renderForSelect() glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); - - LLGLSLShader* vertex_program = &gPipeline.mAvatarPickProgram; - if (mVertexShaderLevel > 0) + glGetFloatv(GL_MODELVIEW_MATRIX, (F32*) sModelViewMatrix.mMatrix); + sVertexProgram = &gPipeline.mAvatarPickProgram; + if (sShaderLevel > 0) { - gPipeline.mAvatarMatrixParam = vertex_program->mUniform[LLPipeline::GLSL_AVATAR_MATRIX]; + gPipeline.mAvatarMatrixParam = sVertexProgram->mUniform[LLPipeline::GLSL_AVATAR_MATRIX]; } glAlphaFunc(GL_GEQUAL, 0.2f); glBlendFunc(GL_ONE, GL_ZERO); - //-------------------------------------------------------------------------------- - // this is where we first hit the software blending path - // if enabled, we need to set up the proper buffers and avoid setting other state - //-------------------------------------------------------------------------------- - if (!(mVertexShaderLevel > 0) || gUseGLPick) - { - - // Rotate to the next buffer, round-robin. - gPipeline.bufferRotate(); - - // Wait until the hardware is done reading the last set of vertices from the buffer before writing the next set. - gPipeline.bufferWaitFence(); - - // Need to do this because we may be rendering without AGP even in AGP mode - U8* buffer_offset_start = gPipeline.bufferGetScratchMemory(); - glVertexPointer( 3, GL_FLOAT, AVATAR_VERTEX_BYTES, buffer_offset_start + AVATAR_OFFSET_POS); - glTexCoordPointer(2, GL_FLOAT, AVATAR_VERTEX_BYTES, buffer_offset_start + AVATAR_OFFSET_TEX0); - glNormalPointer( GL_FLOAT, AVATAR_VERTEX_BYTES, buffer_offset_start + AVATAR_OFFSET_NORMAL); - } - S32 name = avatarp->mDrawable->getVObj()->mGLName; LLColor4U color((U8)(name >> 16), (U8)(name >> 8), (U8)name); glColor4ubv(color.mV); - if ((mVertexShaderLevel > 0) && !gUseGLPick) // for hardware blending - { - bindGLVertexPointer(); - bindGLNormalPointer(); - bindGLTexCoordPointer(0); - } - // render rigid meshes (eyeballs) first - mIndicesDrawn += avatarp->renderRigid(); + //mIndicesDrawn += avatarp->renderRigid(); - if ((mVertexShaderLevel > 0) && !gUseGLPick) // for hardware blending + if ((sShaderLevel > 0) && !gUseGLPick) // for hardware blending { glClientActiveTextureARB(GL_TEXTURE0_ARB); - bindGLTexCoordPointer(0); - vertex_program->bind(); - bindGLVertexWeightPointer(vertex_program->mAttribute[LLPipeline::GLSL_AVATAR_WEIGHT]); - /*if ((mVertexShaderLevel >= SHADER_LEVEL_CLOTH)) - { - bindGLVertexClothingWeightPointer(); - enable_cloth_weights(); - }*/ - enable_vertex_weighting(vertex_program->mAttribute[LLPipeline::GLSL_AVATAR_WEIGHT]); + sRenderingSkinned = TRUE; + sVertexProgram->bind(); + enable_vertex_weighting(sVertexProgram->mAttribute[LLPipeline::GLSL_AVATAR_WEIGHT]); } - + mIndicesDrawn += avatarp->renderSkinned(AVATAR_RENDER_PASS_SINGLE); // if we're in software-blending, remember to set the fence _after_ we draw so we wait till this rendering is done - if (!(mVertexShaderLevel > 0) || gUseGLPick) + if ((sShaderLevel > 0) && !gUseGLPick) { - // want for the previously bound fence to finish - gPipeline.bufferSendFence(); - } - else - { - vertex_program->unbind(); - disable_vertex_weighting(vertex_program->mAttribute[LLPipeline::GLSL_AVATAR_WEIGHT]); - - /*if ((mVertexShaderLevel >= SHADER_LEVEL_CLOTH)) - { - disable_cloth_weights(); - }*/ + sRenderingSkinned = FALSE; + sVertexProgram->unbind(); + disable_vertex_weighting(sVertexProgram->mAttribute[LLPipeline::GLSL_AVATAR_WEIGHT]); } glAlphaFunc(GL_GREATER, 0.01f); @@ -608,3 +574,46 @@ LLColor3 LLDrawPoolAvatar::getDebugColor() const { return LLColor3(0.f, 1.f, 0.f); } + +LLVertexBufferAvatar::LLVertexBufferAvatar() +: LLVertexBuffer(sDataMask, + gPipeline.getVertexShaderLevel(LLPipeline::SHADER_AVATAR) > 0 ? + GL_STATIC_DRAW_ARB : + GL_STREAM_DRAW_ARB) +{ + +} + + +void LLVertexBufferAvatar::setupVertexBuffer(U32 data_mask) const +{ + if (sRenderingSkinned) + { + U8* base = useVBOs() ? NULL : mMappedData; + + glVertexPointer(3,GL_FLOAT, mStride, (void*)(base + 0)); + glNormalPointer(GL_FLOAT, mStride, (void*)(base + mOffsets[TYPE_NORMAL])); + + glClientActiveTextureARB(GL_TEXTURE1_ARB); + glTexCoordPointer(2,GL_FLOAT, mStride, (void*)(base + mOffsets[TYPE_TEXCOORD2])); + glClientActiveTextureARB(GL_TEXTURE0_ARB); + glTexCoordPointer(2,GL_FLOAT, mStride, (void*)(base + mOffsets[TYPE_TEXCOORD])); + + set_vertex_weights(sVertexProgram->mAttribute[LLPipeline::GLSL_AVATAR_WEIGHT], mStride, (F32*)(base + mOffsets[TYPE_WEIGHT])); + + if (sShaderLevel >= LLDrawPoolAvatar::SHADER_LEVEL_BUMP) + { + set_binormals(sVertexProgram->mAttribute[LLPipeline::GLSL_BINORMAL], mStride, (LLVector3*)(base + mOffsets[TYPE_BINORMAL])); + } + + if (sShaderLevel >= LLDrawPoolAvatar::SHADER_LEVEL_CLOTH) + { + set_vertex_clothing_weights(sVertexProgram->mAttribute[LLPipeline::GLSL_AVATAR_CLOTHING], mStride, (LLVector4*)(base + mOffsets[TYPE_CLOTHWEIGHT])); + } + } + else + { + LLVertexBuffer::setupVertexBuffer(data_mask); + } +} + diff --git a/indra/newview/lldrawpoolavatar.h b/indra/newview/lldrawpoolavatar.h index 0d706b012b..e0b1f2098d 100644 --- a/indra/newview/lldrawpoolavatar.h +++ b/indra/newview/lldrawpoolavatar.h @@ -13,7 +13,7 @@ class LLVOAvatar; -class LLDrawPoolAvatar : public LLDrawPool +class LLDrawPoolAvatar : public LLFacePool { protected: S32 mNumFaces; @@ -24,21 +24,48 @@ public: SHADER_LEVEL_CLOTH = 3 }; + enum + { + VERTEX_DATA_MASK = LLVertexBuffer::MAP_VERTEX | + LLVertexBuffer::MAP_NORMAL | + LLVertexBuffer::MAP_TEXCOORD | + LLVertexBuffer::MAP_WEIGHT | + LLVertexBuffer::MAP_CLOTHWEIGHT | + LLVertexBuffer::MAP_BINORMAL + + }; + + virtual U32 getVertexDataMask() { return VERTEX_DATA_MASK; } + + virtual S32 getVertexShaderLevel() const; + LLDrawPoolAvatar(); + static LLMatrix4& getModelView(); + /*virtual*/ LLDrawPool *instancePool(); + /*virtual*/ S32 getNumPasses(); + /*virtual*/ void beginRenderPass(S32 pass); + /*virtual*/ void endRenderPass(S32 pass); /*virtual*/ void prerender(); /*virtual*/ void render(S32 pass = 0); /*virtual*/ void renderForSelect(); - /*virtual*/ S32 rebuild(); + void beginRigid(); + void beginFootShadow(); + void beginSkinned(); + + void endRigid(); + void endFootShadow(); + void endSkinned(); + /*virtual*/ LLViewerImage *getDebugTexture(); /*virtual*/ LLColor3 getDebugColor() const; // For AGP debug display virtual S32 getMaterialAttribIndex() { return 0; } - void renderAvatars(LLVOAvatar *single_avatar, BOOL no_shaders = FALSE); // renders only one avatar if single_avatar is not null. + void renderAvatars(LLVOAvatar *single_avatar, S32 pass = -1); // renders only one avatar if single_avatar is not null. }; diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp index 68fa88c456..377dbea2d0 100644 --- a/indra/newview/lldrawpoolbump.cpp +++ b/indra/newview/lldrawpoolbump.cpp @@ -18,12 +18,10 @@ #include "m4math.h" #include "llagent.h" -#include "llagparray.h" #include "llcubemap.h" #include "lldrawable.h" #include "lldrawpoolsimple.h" #include "llface.h" -#include "llgl.h" #include "llsky.h" #include "lltextureentry.h" #include "llviewercamera.h" @@ -45,9 +43,11 @@ LLBumpImageList gBumpImageList; const S32 STD_BUMP_LATEST_FILE_VERSION = 1; -S32 LLDrawPoolBump::sBumpTex = -1; -S32 LLDrawPoolBump::sDiffTex = -1; -S32 LLDrawPoolBump::sEnvTex = -1; +const U32 VERTEX_MASK_SHINY = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_COLOR; +const U32 VERTEX_MASK_BUMP = LLVertexBuffer::MAP_VERTEX |LLVertexBuffer::MAP_TEXCOORD | LLVertexBuffer::MAP_TEXCOORD2; + +U32 LLDrawPoolBump::sVertexMask = VERTEX_MASK_SHINY; +static LLCubeMap* sCubeMap = NULL; // static void LLStandardBumpmap::init() @@ -109,7 +109,7 @@ void LLStandardBumpmap::restoreGL() return; } - llinfos << "Loading bumpmap: " << bump_file << " from viewerart" << llendl; +// llinfos << "Loading bumpmap: " << bump_file << " from viewerart" << llendl; gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount].mLabel = label; gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount].mImage = gImageList.getImage( LLUUID(gViewerArt.getString(bump_file)) ); LLStandardBumpmap::sStandardBumpmapCount++; @@ -133,15 +133,9 @@ void LLStandardBumpmap::destroyGL() //////////////////////////////////////////////////////////////// -LLDrawPoolBump::LLDrawPoolBump(LLViewerImage *texturep) : - LLDrawPool(POOL_BUMP, DATA_BUMP_IL_MASK | DATA_COLORS_MASK, DATA_SIMPLE_NIL_MASK), - mTexturep(texturep) -{ -} - -LLDrawPool *LLDrawPoolBump::instancePool() +LLDrawPoolBump::LLDrawPoolBump() +: LLRenderPass(LLDrawPool::POOL_BUMP) { - return new LLDrawPoolBump(mTexturep); } @@ -150,51 +144,16 @@ void LLDrawPoolBump::prerender() mVertexShaderLevel = gPipeline.getVertexShaderLevel(LLPipeline::SHADER_OBJECT); } -BOOL LLDrawPoolBump::match(LLFace* last_face, LLFace* facep) -{ - if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_CHAIN_FACES) && - !last_face->isState(LLFace::LIGHT | LLFace::FULLBRIGHT) && - !facep->isState(LLFace::LIGHT | LLFace::FULLBRIGHT) && - facep->getIndicesStart() == last_face->getIndicesStart()+last_face->getIndicesCount() && - facep->getRenderColor() == last_face->getRenderColor() && - facep->getTextureEntry()->getShiny() == last_face->getTextureEntry()->getShiny() && - facep->getTextureEntry()->getBumpmap() == last_face->getTextureEntry()->getBumpmap()) - { - if (facep->isState(LLFace::GLOBAL)) - { - if (last_face->isState(LLFace::GLOBAL)) - { - return TRUE; - } - } - else - { - if (!last_face->isState(LLFace::GLOBAL)) - { - if (last_face->getRenderMatrix() == facep->getRenderMatrix()) - { - return TRUE; - } - } - } - } - - return FALSE; -} - // static S32 LLDrawPoolBump::numBumpPasses() { - if (gPipeline.getVertexShaderLevel(LLPipeline::SHADER_OBJECT) > 0) + if (gSavedSettings.getBOOL("RenderObjectBump")) { - return 1; // single pass for shaders + return 2; } - else + else { - if (gSavedSettings.getBOOL("RenderObjectBump")) - return 3; - else - return 1; + return 0; } } @@ -208,13 +167,10 @@ void LLDrawPoolBump::beginRenderPass(S32 pass) switch( pass ) { case 0: - beginPass0(this); + beginShiny(); break; case 1: - beginPass1(); - break; - case 2: - beginPass2(); + beginBump(); break; default: llassert(0); @@ -225,66 +181,17 @@ void LLDrawPoolBump::beginRenderPass(S32 pass) void LLDrawPoolBump::render(S32 pass) { LLFastTimer t(LLFastTimer::FTM_RENDER_BUMP); - if (!mTexturep) - { - return; - } - - if (mDrawFace.empty()) - { - return; - } - - const U32* index_array = getRawIndices(); - S32 indices = 0; switch( pass ) { case 0: { - stop_glerror(); - - bindGLVertexPointer(); - bindGLTexCoordPointer(); - bindGLNormalPointer(); - if (gPipeline.getLightingDetail() >= 2) - { - bindGLColorPointer(); - } - - stop_glerror(); - - LLGLState alpha_test(GL_ALPHA_TEST, FALSE); - LLGLState blend(GL_BLEND, FALSE); - LLViewerImage* tex = getTexture(); - if (tex && tex->getPrimaryFormat() == GL_ALPHA) - { - // Enable Invisibility Hack - alpha_test.enable(); - blend.enable(); - } - indices += renderPass0(this, mDrawFace, index_array, mTexturep); + renderShiny(); break; } case 1: { - bindGLVertexPointer(); - bindGLNormalPointer(); - indices += renderPass1(mDrawFace, index_array, mTexturep); - break; - } - case 2: - { - bindGLVertexPointer(); - // Texture unit 0 - glActiveTextureARB(GL_TEXTURE0_ARB); - glClientActiveTextureARB(GL_TEXTURE0_ARB); - bindGLTexCoordPointer(); - // Texture unit 1 - glActiveTextureARB(GL_TEXTURE1_ARB); - glClientActiveTextureARB(GL_TEXTURE1_ARB); - bindGLTexCoordPointer(1); - indices += renderPass2(mDrawFace, index_array, mTexturep); + renderBump(); break; } default: @@ -293,7 +200,6 @@ void LLDrawPoolBump::render(S32 pass) break; } } - mIndicesDrawn += indices; } void LLDrawPoolBump::endRenderPass(S32 pass) @@ -301,13 +207,10 @@ void LLDrawPoolBump::endRenderPass(S32 pass) switch( pass ) { case 0: - endPass0(this); + endShiny(); break; case 1: - endPass1(); - break; - case 2: - endPass2(); + endBump(); break; default: llassert(0); @@ -316,252 +219,171 @@ void LLDrawPoolBump::endRenderPass(S32 pass) } //static -void LLDrawPoolBump::beginPass0(LLDrawPool* pool) +void LLDrawPoolBump::beginShiny() { - stop_glerror(); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); + sVertexMask = VERTEX_MASK_SHINY; + // Second pass: environment map glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); - if (gPipeline.getLightingDetail() >= 2) - { - glEnableClientState(GL_COLOR_ARRAY); - } + glEnableClientState(GL_COLOR_ARRAY); - if (pool->getVertexShaderLevel() > 0) + LLCubeMap* cube_map = gSky.mVOSkyp->getCubeMap(); + if( cube_map ) { - enable_binormals(gPipeline.mObjectBumpProgram.mAttribute[LLPipeline::GLSL_BINORMAL]); + cube_map->enable(0); + cube_map->setMatrix(0); + cube_map->bind(); - sEnvTex = gPipeline.mObjectBumpProgram.enableTexture(LLPipeline::GLSL_ENVIRONMENT_MAP, GL_TEXTURE_CUBE_MAP_ARB); - LLCubeMap* cube_map = gSky.mVOSkyp->getCubeMap(); - if (sEnvTex >= 0 && cube_map) + if (gPipeline.getVertexShaderLevel(LLPipeline::SHADER_OBJECT) > 0) { - cube_map->bind(); - cube_map->setMatrix(1); + LLMatrix4 mat; + glGetFloatv(GL_MODELVIEW_MATRIX, (F32*) mat.mMatrix); + gPipeline.mObjectShinyProgram.bind(); + LLVector3 vec = LLVector3(gPipeline.mShinyOrigin) * mat; + LLVector4 vec4(vec, gPipeline.mShinyOrigin.mV[3]); + glUniform4fvARB(gPipeline.mObjectShinyProgram.mUniform[LLPipeline::GLSL_SHINY_ORIGIN], 1, + vec4.mV); + } + else + { + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); + + //use RGB from texture + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR); + + // use alpha from color + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PRIMARY_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA); } - - sBumpTex = gPipeline.mObjectBumpProgram.enableTexture(LLPipeline::GLSL_BUMP_MAP); - sDiffTex = gPipeline.mObjectBumpProgram.enableTexture(LLPipeline::GLSL_DIFFUSE_MAP); - S32 scatterTex = gPipeline.mObjectBumpProgram.enableTexture(LLPipeline::GLSL_SCATTER_MAP); - LLViewerImage::bindTexture(gSky.mVOSkyp->getScatterMap(), scatterTex); } - stop_glerror(); } -//static -S32 LLDrawPoolBump::renderPass0(LLDrawPool* pool, face_array_t& face_list, const U32* index_array, LLViewerImage* tex) +void LLDrawPoolBump::renderShiny() { - if (!tex) - { - return 0; - } + LLFastTimer t(LLFastTimer::FTM_RENDER_SHINY); - if (face_list.empty()) + sCubeMap = NULL; + + if( gSky.mVOSkyp->getCubeMap() ) { - return 0; + LLGLEnable blend_enable(GL_BLEND); + renderStatic(LLRenderPass::PASS_SHINY, sVertexMask); + renderActive(LLRenderPass::PASS_SHINY, sVertexMask); } +} - stop_glerror(); +void LLDrawPoolBump::renderActive(U32 type, U32 mask, BOOL texture) +{ +#if !LL_RELEASE_FOR_DOWNLOAD + LLGLState::checkClientArrays(mask); +#endif - S32 res = 0; - if (pool->getVertexShaderLevel() > 0) + LLSpatialBridge* last_bridge = NULL; + glPushMatrix(); + + for (LLSpatialGroup::sg_vector_t::iterator i = gPipeline.mActiveGroups.begin(); i != gPipeline.mActiveGroups.end(); ++i) { - LLFastTimer t(LLFastTimer::FTM_RENDER_BUMP); - pool->bindGLBinormalPointer(gPipeline.mObjectBumpProgram.mAttribute[LLPipeline::GLSL_BINORMAL]); - - LLViewerImage::bindTexture(tex, sDiffTex); - - //single pass shader driven shiny/bump - LLGLDisable(GL_ALPHA_TEST); - - LLViewerImage::sWhiteImagep->bind(sBumpTex); - - GLfloat alpha[4] = + LLSpatialGroup* group = *i; + if (!group->isDead() && + gPipeline.hasRenderType(group->mSpatialPartition->mDrawableType) && + group->mDrawMap.find(type) != group->mDrawMap.end()) { - 0.00f, - 0.25f, - 0.5f, - 0.75f - }; - - LLImageGL* last_bump = NULL; - - for (std::vector<LLFace*>::iterator iter = face_list.begin(); - iter != face_list.end(); iter++) - { - LLFace *facep = *iter; - if (facep->mSkipRender) - { - continue; - } - - const LLTextureEntry* te = facep->getTextureEntry(); - if (te) + LLSpatialBridge* bridge = (LLSpatialBridge*) group->mSpatialPartition; + if (bridge != last_bridge) { - U8 index = te->getShiny(); - LLColor4 col = te->getColor(); - - gPipeline.mObjectBumpProgram.vertexAttrib4f(LLPipeline::GLSL_MATERIAL_COLOR, - col.mV[0], col.mV[1], col.mV[2], alpha[index]); - gPipeline.mObjectBumpProgram.vertexAttrib4f(LLPipeline::GLSL_SPECULAR_COLOR, - alpha[index], alpha[index], alpha[index], alpha[index]); - - LLImageGL* bump = getBumpMap(te, tex); - if (bump != last_bump) + glPopMatrix(); + glPushMatrix(); + glMultMatrixf((F32*) bridge->mDrawable->getRenderMatrix().mMatrix); + last_bridge = bridge; + + if (LLPipeline::sDynamicReflections) { - if (bump) + LLSpatialPartition* part = gPipeline.getSpatialPartition(LLPipeline::PARTITION_VOLUME); + LLSpatialGroup::OctreeNode* node = part->mOctree->getNodeAt(LLVector3d(bridge->mDrawable->getPositionAgent()), 32.0); + if (node) { - bump->bind(sBumpTex); - } - else - { - LLViewerImage::sWhiteImagep->bind(sBumpTex); + sCubeMap = ((LLSpatialGroup*) node->getListener(0))->mReflectionMap; } } - last_bump = bump; - - // Draw the geometry - facep->enableLights(); - res += facep->renderIndexed(index_array); - stop_glerror(); - } - else - { - llwarns << "DrawPoolBump has face with invalid texture entry." << llendl; } - } - } - else - { - LLFastTimer t(LLFastTimer::FTM_RENDER_SIMPLE); - LLViewerImage::bindTexture(tex); - res = LLDrawPool::drawLoop(face_list, index_array); - } - return res; -} - -//static -void LLDrawPoolBump::endPass0(LLDrawPool* pool) -{ - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - if (pool->getVertexShaderLevel() > 0) - { - gPipeline.mObjectBumpProgram.disableTexture(LLPipeline::GLSL_ENVIRONMENT_MAP, GL_TEXTURE_CUBE_MAP_ARB); - LLCubeMap* cube_map = gSky.mVOSkyp->getCubeMap(); - if (sEnvTex >= 0 && cube_map) - { - cube_map->restoreMatrix(); + renderGroup(group,type,mask,texture); } - - gPipeline.mObjectBumpProgram.disableTexture(LLPipeline::GLSL_SCATTER_MAP); - gPipeline.mObjectBumpProgram.disableTexture(LLPipeline::GLSL_BUMP_MAP); - gPipeline.mObjectBumpProgram.disableTexture(LLPipeline::GLSL_DIFFUSE_MAP); - - disable_binormals(gPipeline.mObjectBumpProgram.mAttribute[LLPipeline::GLSL_BINORMAL]); - - glActiveTextureARB(GL_TEXTURE0_ARB); - glEnable(GL_TEXTURE_2D); } + + glPopMatrix(); } -//static -void LLDrawPoolBump::beginPass1() -{ - // Second pass: environment map - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_NORMAL_ARRAY); - LLCubeMap* cube_map = gSky.mVOSkyp->getCubeMap(); - if( cube_map ) - { - cube_map->enable(0); - cube_map->setMatrix(0); - cube_map->bind(); - } -} - -//static -S32 LLDrawPoolBump::renderPass1(face_array_t& face_list, const U32* index_array, LLViewerImage* tex) -{ - LLFastTimer t(LLFastTimer::FTM_RENDER_SHINY); - if (gPipeline.getVertexShaderLevel(LLPipeline::SHADER_OBJECT) > 0) //everything happens in pass0 - { - return 0; - } - - S32 res = 0; - if( gSky.mVOSkyp->getCubeMap() ) +void LLDrawPoolBump::renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture = TRUE) +{ + std::vector<LLDrawInfo*>& draw_info = group->mDrawMap[type]; + + for (std::vector<LLDrawInfo*>::const_iterator k = draw_info.begin(); k != draw_info.end(); ++k) { - //LLGLSPipelineAlpha gls; - //LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE, GL_EQUAL); - LLGLEnable blend_enable(GL_BLEND); - - GLfloat alpha[4] = + LLDrawInfo& params = **k; + if (LLPipeline::sDynamicReflections) { - 0.00f, - 0.25f, - 0.5f, - 0.75f - }; - - for (std::vector<LLFace*>::iterator iter = face_list.begin(); - iter != face_list.end(); iter++) - { - LLFace *facep = *iter; - if (facep->mSkipRender) + if (params.mReflectionMap.notNull()) { - continue; + params.mReflectionMap->bind(); } - - const LLTextureEntry* te = facep->getTextureEntry(); - if (te) + else { - U8 index = te->getShiny(); - if( index > 0 ) + if (sCubeMap) { - LLOverrideFaceColor override_color(facep->getPool(), 1, 1, 1, alpha[index]); - - // Draw the geometry - facep->enableLights(); - res += facep->renderIndexed(index_array); - stop_glerror(); + sCubeMap->bind(); + } + else + { + gSky.mVOSkyp->getCubeMap()->bind(); } - } - else - { - llwarns << "DrawPoolBump has face with invalid texture entry." << llendl; } } + + params.mVertexBuffer->setBuffer(mask); + U32* indices_pointer = (U32*) params.mVertexBuffer->getIndicesPointer(); + glDrawRangeElements(GL_TRIANGLES, params.mStart, params.mEnd, params.mCount, + GL_UNSIGNED_INT, indices_pointer+params.mOffset); + gPipeline.mTrianglesDrawn += params.mCount/3; } - return res; } -//static -void LLDrawPoolBump::endPass1() +void LLDrawPoolBump::endShiny() { LLCubeMap* cube_map = gSky.mVOSkyp->getCubeMap(); if( cube_map ) { cube_map->disable(); cube_map->restoreMatrix(); + + if (gPipeline.getVertexShaderLevel(LLPipeline::SHADER_OBJECT) > 0) + { + gPipeline.mObjectShinyProgram.unbind(); + } + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); } LLImageGL::unbindTexture(0, GL_TEXTURE_2D); - + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glDisableClientState(GL_NORMAL_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); } // static -LLImageGL* LLDrawPoolBump::getBumpMap(const LLTextureEntry* te, LLViewerImage* tex) +BOOL LLDrawPoolBump::bindBumpMap(LLDrawInfo& params) { - U32 bump_code = te->getBumpmap(); LLImageGL* bump = NULL; + U8 bump_code = params.mBump; + LLViewerImage* tex = params.mTexture; + switch( bump_code ) { case BE_NO_BUMP: @@ -579,28 +401,33 @@ LLImageGL* LLDrawPoolBump::getBumpMap(const LLTextureEntry* te, LLViewerImage* t if( bump_code < LLStandardBumpmap::sStandardBumpmapCount ) { bump = gStandardBumpmapList[bump_code].mImage; + gBumpImageList.addTextureStats(bump_code, tex->getID(), params.mVSize, 1, 1); } break; } - return bump; + if (bump) + { + bump->bind(1); + bump->bind(0); + return TRUE; + } + return FALSE; } //static -void LLDrawPoolBump::beginPass2() +void LLDrawPoolBump::beginBump() { + sVertexMask = VERTEX_MASK_BUMP; LLFastTimer t(LLFastTimer::FTM_RENDER_BUMP); - // Optional third pass: emboss bump map + // Optional second pass: emboss bump map stop_glerror(); // TEXTURE UNIT 0 // Output.rgb = texture at texture coord 0 glActiveTextureARB(GL_TEXTURE0_ARB); glClientActiveTextureARB(GL_TEXTURE0_ARB); - - glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE); @@ -613,14 +440,10 @@ void LLDrawPoolBump::beginPass2() glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA); - // TEXTURE UNIT 1 glActiveTextureARB(GL_TEXTURE1_ARB); glClientActiveTextureARB(GL_TEXTURE1_ARB); - - glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); glEnable(GL_TEXTURE_2D); // Texture unit 1 @@ -650,68 +473,25 @@ void LLDrawPoolBump::beginPass2() // = dst.rgb + dst.rgb * (bump0 - bump1) glBlendFunc(GL_DST_COLOR, GL_SRC_COLOR); // glBlendFunc(GL_ONE, GL_ZERO); // temp - + glActiveTextureARB(GL_TEXTURE0_ARB); stop_glerror(); } //static -S32 LLDrawPoolBump::renderPass2(face_array_t& face_list, const U32* index_array, LLViewerImage* tex) +void LLDrawPoolBump::renderBump() { - if (gPipeline.getVertexShaderLevel(LLPipeline::SHADER_OBJECT) > 0) //everything happens in pass0 - { - return 0; - } - + LLFastTimer ftm(LLFastTimer::FTM_RENDER_BUMP); LLGLDisable fog(GL_FOG); LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE, GL_EQUAL); LLGLEnable tex2d(GL_TEXTURE_2D); LLGLEnable blend(GL_BLEND); - S32 res = 0; - - LLImageGL* last_bump = NULL; - - for (std::vector<LLFace*>::iterator iter = face_list.begin(); - iter != face_list.end(); iter++) - { - LLFace *facep = *iter; - if (facep->mSkipRender) - { - continue; - } - LLOverrideFaceColor override_color(facep->getPool(), 1,1,1,1); - - const LLTextureEntry* te = facep->getTextureEntry(); - LLImageGL* bump = getBumpMap(te, tex); - - if( bump ) - { - if( bump != last_bump ) - { - last_bump = bump; - - // Texture unit 0 - bump->bind(0); - stop_glerror(); - - // Texture unit 1 - bump->bind(1); - stop_glerror(); - } - - // Draw the geometry - res += facep->renderIndexed(index_array); - stop_glerror(); - } - else - { -// llwarns << "Skipping invalid bump code " << (S32) te->getBumpmap() << llendl; - } - } - return res; + glColor4f(1,1,1,1); + renderBump(LLRenderPass::PASS_BUMP, sVertexMask); + renderBumpActive(LLRenderPass::PASS_BUMP, sVertexMask); } //static -void LLDrawPoolBump::endPass2() +void LLDrawPoolBump::endBump() { // Disable texture unit 1 glActiveTextureARB(GL_TEXTURE1_ARB); @@ -729,67 +509,6 @@ void LLDrawPoolBump::endPass2() glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); } - -void LLDrawPoolBump::renderForSelect() -{ - if (mDrawFace.empty() || !mMemory.count()) - { - return; - } - - glEnableClientState ( GL_VERTEX_ARRAY ); - - bindGLVertexPointer(); - - for (std::vector<LLFace*>::iterator iter = mDrawFace.begin(); - iter != mDrawFace.end(); iter++) - { - LLFace *facep = *iter; - if (facep->getDrawable() && !facep->getDrawable()->isDead() && (facep->getViewerObject()->mGLName)) - { - facep->renderForSelect(); - } - } -} - - -void LLDrawPoolBump::renderFaceSelected(LLFace *facep, - LLImageGL *image, - const LLColor4 &color, - const S32 index_offset, const S32 index_count) -{ - facep->renderSelected(image, color, index_offset, index_count); -} - - -void LLDrawPoolBump::dirtyTexture(const LLViewerImage *texturep) -{ - if (mTexturep == texturep) - { - for (std::vector<LLFace*>::iterator iter = mReferences.begin(); - iter != mReferences.end(); iter++) - { - LLFace *facep = *iter; - gPipeline.markTextured(facep->getDrawable()); - } - } -} - -LLViewerImage *LLDrawPoolBump::getTexture() -{ - return mTexturep; -} - -LLViewerImage *LLDrawPoolBump::getDebugTexture() -{ - return mTexturep; -} - -LLColor3 LLDrawPoolBump::getDebugColor() const -{ - return LLColor3(1.f, 1.f, 0.f); -} - //////////////////////////////////////////////////////////////// // List of one-component bump-maps created from other texures. @@ -1113,25 +832,93 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerImage *src_vi, LLIma } } -S32 LLDrawPoolBump::getMaterialAttribIndex() +void LLDrawPoolBump::renderBumpActive(U32 type, U32 mask) { - return gPipeline.mObjectBumpProgram.mAttribute[LLPipeline::GLSL_MATERIAL_COLOR]; +#if !LL_RELEASE_FOR_DOWNLOAD + LLGLState::checkClientArrays(mask); +#endif + + LLSpatialBridge* last_bridge = NULL; + glPushMatrix(); + + for (LLSpatialGroup::sg_vector_t::iterator i = gPipeline.mActiveGroups.begin(); i != gPipeline.mActiveGroups.end(); ++i) + { + LLSpatialGroup* group = *i; + if (!group->isDead() && + group->mSpatialPartition->mRenderByGroup && + group->mDrawMap.find(type) != group->mDrawMap.end()) + { + LLSpatialBridge* bridge = (LLSpatialBridge*) group->mSpatialPartition; + if (bridge != last_bridge) + { + glPopMatrix(); + glPushMatrix(); + glMultMatrixf((F32*) bridge->mDrawable->getRenderMatrix().mMatrix); + last_bridge = bridge; + } + + renderGroupBump(group,type,mask); + } + } + + glPopMatrix(); } -// virtual -void LLDrawPoolBump::enableShade() -{ - glDisableClientState(GL_COLOR_ARRAY); +void LLDrawPoolBump::renderBump(U32 type, U32 mask) +{ +#if !LL_RELEASE_FOR_DOWNLOAD + LLGLState::checkClientArrays(mask); +#endif + + std::vector<LLDrawInfo*>& draw_info = gPipeline.mRenderMap[type]; + + for (std::vector<LLDrawInfo*>::iterator i = draw_info.begin(); i != draw_info.end(); ++i) + { + LLDrawInfo& params = **i; + + if (LLDrawPoolBump::bindBumpMap(params)) + { + pushBatch(params, mask, FALSE); + } + } } -// virtual -void LLDrawPoolBump::disableShade() -{ - glEnableClientState(GL_COLOR_ARRAY); +void LLDrawPoolBump::renderGroupBump(LLSpatialGroup* group, U32 type, U32 mask) +{ + const std::vector<LLDrawInfo*>& draw_info = group->mDrawMap[type]; + + for (std::vector<LLDrawInfo*>::const_iterator k = draw_info.begin(); k != draw_info.end(); ++k) + { + LLDrawInfo& params = **k; + + if (LLDrawPoolBump::bindBumpMap(params)) + { + pushBatch(params, mask, FALSE); + } + } } -// virtual -void LLDrawPoolBump::setShade(F32 shade) +void LLDrawPoolBump::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture) { - glColor4f(0,0,0,shade); + if (params.mTextureMatrix) + { + glActiveTextureARB(GL_TEXTURE1_ARB); + glMatrixMode(GL_TEXTURE); + glLoadMatrixf((GLfloat*) params.mTextureMatrix->mMatrix); + glActiveTextureARB(GL_TEXTURE0_ARB); + glLoadMatrixf((GLfloat*) params.mTextureMatrix->mMatrix); + } + params.mVertexBuffer->setBuffer(mask); + U32* indices_pointer = (U32*) params.mVertexBuffer->getIndicesPointer(); + glDrawRangeElements(GL_TRIANGLES, params.mStart, params.mEnd, params.mCount, + GL_UNSIGNED_INT, indices_pointer+params.mOffset); + gPipeline.mTrianglesDrawn += params.mCount/3; + if (params.mTextureMatrix) + { + glActiveTextureARB(GL_TEXTURE1_ARB); + glLoadIdentity(); + glActiveTextureARB(GL_TEXTURE0_ARB); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + } } diff --git a/indra/newview/lldrawpoolbump.h b/indra/newview/lldrawpoolbump.h index b74acb4561..6376dd8d33 100644 --- a/indra/newview/lldrawpoolbump.h +++ b/indra/newview/lldrawpoolbump.h @@ -15,57 +15,41 @@ #include "lluuid.h" class LLImageRaw; +class LLSpatialGroup; +class LLDrawInfo; -class LLDrawPoolBump : public LLDrawPool +class LLDrawPoolBump : public LLRenderPass { -protected: - LLPointer<LLViewerImage> mTexturep; // The primary texture, not the bump texture - public: - LLDrawPoolBump(LLViewerImage *texturep); + static U32 sVertexMask; + + virtual U32 getVertexDataMask() { return sVertexMask; } - /*virtual*/ LLDrawPool *instancePool(); + LLDrawPoolBump(); /*virtual*/ void render(S32 pass = 0); /*virtual*/ void beginRenderPass( S32 pass ); /*virtual*/ void endRenderPass( S32 pass ); /*virtual*/ S32 getNumPasses(); - /*virtual*/ void renderFaceSelected(LLFace *facep, LLImageGL *image, const LLColor4 &color, - const S32 index_offset = 0, const S32 index_count = 0); /*virtual*/ void prerender(); - /*virtual*/ void renderForSelect(); - /*virtual*/ void dirtyTexture(const LLViewerImage *texturep); - /*virtual*/ LLViewerImage *getTexture(); - /*virtual*/ LLViewerImage *getDebugTexture(); - /*virtual*/ LLColor3 getDebugColor() const; // For AGP debug display - /*virtual*/ BOOL match(LLFace* last_face, LLFace* facep); + /*virtual*/ void pushBatch(LLDrawInfo& params, U32 mask, BOOL texture); + + void renderBump(U32 type, U32 mask); + void renderBumpActive(U32 type, U32 mask); + void renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture); + void renderGroupBump(LLSpatialGroup* group, U32 type, U32 mask); - virtual S32 getMaterialAttribIndex(); - static S32 numBumpPasses(); + S32 numBumpPasses(); - static void beginPass0(LLDrawPool* pool); - static S32 renderPass0(LLDrawPool* pool, face_array_t& face_list, const U32* index_array, LLViewerImage* tex); - static void endPass0(LLDrawPool* pool); - - static void beginPass1(); - static S32 renderPass1(face_array_t& face_list, const U32* index_array, LLViewerImage* tex); - static void endPass1(); - - static void beginPass2(); - static S32 renderPass2(face_array_t& face_list, const U32* index_array, LLViewerImage* tex); - static void endPass2(); - - /*virtual*/ void enableShade(); - /*virtual*/ void disableShade(); - /*virtual*/ void setShade(F32 shade); - -protected: - static LLImageGL* getBumpMap(const LLTextureEntry* te, LLViewerImage* tex); - -public: - static S32 sBumpTex; - static S32 sDiffTex; - static S32 sEnvTex; + void beginShiny(); + void renderShiny(); + void endShiny(); + void renderActive(U32 type, U32 mask, BOOL texture = TRUE); + + void beginBump(); + void renderBump(); + void endBump(); + BOOL bindBumpMap(LLDrawInfo& params); }; enum EBumpEffect diff --git a/indra/newview/lldrawpoolclouds.cpp b/indra/newview/lldrawpoolclouds.cpp index c279f085d5..d611338248 100644 --- a/indra/newview/lldrawpoolclouds.cpp +++ b/indra/newview/lldrawpoolclouds.cpp @@ -17,7 +17,7 @@ #include "pipeline.h" LLDrawPoolClouds::LLDrawPoolClouds() : - LLDrawPool(POOL_CLOUDS, DATA_SIMPLE_IL_MASK, 0) + LLDrawPool(POOL_CLOUDS) { } @@ -26,16 +26,15 @@ LLDrawPool *LLDrawPoolClouds::instancePool() return new LLDrawPoolClouds(); } +BOOL LLDrawPoolClouds::addFace(LLFace* face) +{ + llerrs << "WTF?" << llendl; + return FALSE; +} + void LLDrawPoolClouds::enqueue(LLFace *facep) { - if (facep->isState(LLFace::BACKLIST)) - { - mMoveFace.put(facep); - } - else - { - mDrawFace.push_back(facep); - } + mDrawFace.push_back(facep); facep->mDistance = (facep->mCenterAgent - gCamera->getOrigin()) * gCamera->getAtAxis(); } @@ -71,10 +70,6 @@ void LLDrawPoolClouds::render(S32 pass) gPipeline.enableLightsFullbright(LLColor4(1.f,1.f,1.f)); mDrawFace[0]->bindTexture(); - - bindGLVertexPointer(); - bindGLTexCoordPointer(); - bindGLNormalPointer(); std::sort(mDrawFace.begin(), mDrawFace.end(), LLFace::CompareDistanceGreater()); diff --git a/indra/newview/lldrawpoolclouds.h b/indra/newview/lldrawpoolclouds.h index d333444400..fd04f3b2ec 100644 --- a/indra/newview/lldrawpoolclouds.h +++ b/indra/newview/lldrawpoolclouds.h @@ -14,6 +14,16 @@ class LLDrawPoolClouds : public LLDrawPool { public: + enum + { + VERTEX_DATA_MASK = LLVertexBuffer::MAP_VERTEX | + LLVertexBuffer::MAP_NORMAL | + LLVertexBuffer::MAP_TEXCOORD + }; + + BOOL addFace(LLFace* face); + virtual U32 getVertexDataMask() { return VERTEX_DATA_MASK; } + LLDrawPoolClouds(); /*virtual*/ void prerender(); diff --git a/indra/newview/lldrawpoolground.cpp b/indra/newview/lldrawpoolground.cpp index 91e92bab6e..edbb11ad79 100644 --- a/indra/newview/lldrawpoolground.cpp +++ b/indra/newview/lldrawpoolground.cpp @@ -12,7 +12,6 @@ #include "llviewercontrol.h" -#include "llagparray.h" #include "lldrawable.h" #include "llface.h" #include "llsky.h" @@ -20,9 +19,11 @@ #include "llviewerwindow.h" #include "llworld.h" #include "pipeline.h" +#include "llagent.h" +#include "llviewerregion.h" LLDrawPoolGround::LLDrawPoolGround() : - LLDrawPool(POOL_GROUND, DATA_SIMPLE_IL_MASK, DATA_SIMPLE_NIL_MASK) + LLFacePool(POOL_GROUND) { } @@ -41,42 +42,38 @@ void LLDrawPoolGround::render(S32 pass) if (mDrawFace.empty()) { return; - } - + } + glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); - - bindGLVertexPointer(); - bindGLTexCoordPointer(); LLGLSPipelineSkyBox gls_skybox; + LLGLDisable tex(GL_TEXTURE_2D); LLGLDepthTest gls_depth(GL_FALSE, GL_FALSE); glMatrixMode( GL_PROJECTION ); - + glPushMatrix(); - gViewerWindow->setup3DRender(); + //gViewerWindow->setup3DRender(); glMatrixMode(GL_MODELVIEW); - LLGLState tex2d(GL_TEXTURE_2D, (mVertexShaderLevel > 0) ? TRUE : FALSE); - LLViewerImage::bindTexture(gSky.mVOSkyp->getScatterMap(), 0); + F32 water_height = gAgent.getRegion()->getWaterHeight(); + glPushMatrix(); + LLVector3 origin = gCamera->getOrigin(); + glTranslatef(origin.mV[0], origin.mV[1], llmax(origin.mV[2], water_height)); LLFace *facep = mDrawFace[0]; - if (!(mVertexShaderLevel > 0)) - { - gPipeline.disableLights(); - } - - glColor4fv(facep->getFaceColor().mV); + gPipeline.disableLights(); - facep->renderIndexed(getRawIndices()); + LLOverrideFaceColor col(this, gSky.mVOSkyp->getGLFogColor()); + facep->renderIndexed(); glMatrixMode( GL_PROJECTION ); glPopMatrix(); glMatrixMode( GL_MODELVIEW ); + glPopMatrix(); } void LLDrawPoolGround::renderForSelect() diff --git a/indra/newview/lldrawpoolground.h b/indra/newview/lldrawpoolground.h index 8b2dbf4353..3436b9aabd 100644 --- a/indra/newview/lldrawpoolground.h +++ b/indra/newview/lldrawpoolground.h @@ -12,9 +12,17 @@ #include "lldrawpool.h" -class LLDrawPoolGround : public LLDrawPool +class LLDrawPoolGround : public LLFacePool { public: + enum + { + VERTEX_DATA_MASK = LLVertexBuffer::MAP_VERTEX | + LLVertexBuffer::MAP_TEXCOORD + }; + + virtual U32 getVertexDataMask() { return VERTEX_DATA_MASK; } + LLDrawPoolGround(); /*virtual*/ LLDrawPool *instancePool(); diff --git a/indra/newview/lldrawpoolsimple.cpp b/indra/newview/lldrawpoolsimple.cpp index 600e4b1fc6..fcd466bfc4 100644 --- a/indra/newview/lldrawpoolsimple.cpp +++ b/indra/newview/lldrawpoolsimple.cpp @@ -11,57 +11,16 @@ #include "lldrawpoolsimple.h" #include "llagent.h" -#include "llagparray.h" #include "lldrawable.h" #include "llface.h" #include "llsky.h" #include "pipeline.h" -S32 LLDrawPoolSimple::sDiffTex = 0; - -LLDrawPoolSimple::LLDrawPoolSimple(LLViewerImage *texturep) : - LLDrawPool(POOL_SIMPLE, - DATA_SIMPLE_IL_MASK | DATA_COLORS_MASK, - DATA_SIMPLE_NIL_MASK), // ady temp - mTexturep(texturep) +LLDrawPoolSimple::LLDrawPoolSimple() : + LLRenderPass(POOL_SIMPLE) { } -LLDrawPool *LLDrawPoolSimple::instancePool() -{ - return new LLDrawPoolSimple(mTexturep); -} - -BOOL LLDrawPoolSimple::match(LLFace* last_face, LLFace* facep) -{ - if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_CHAIN_FACES) && - !last_face->isState(LLFace::LIGHT | LLFace::FULLBRIGHT) && - !facep->isState(LLFace::LIGHT | LLFace::FULLBRIGHT) && - facep->getIndicesStart() == last_face->getIndicesStart()+last_face->getIndicesCount() && - facep->getRenderColor() == last_face->getRenderColor()) - { - if (facep->isState(LLFace::GLOBAL)) - { - if (last_face->isState(LLFace::GLOBAL)) - { - return TRUE; - } - } - else - { - if (!last_face->isState(LLFace::GLOBAL)) - { - if (last_face->getRenderMatrix() == facep->getRenderMatrix()) - { - return TRUE; - } - } - } - } - - return FALSE; -} - void LLDrawPoolSimple::prerender() { mVertexShaderLevel = gPipeline.getVertexShaderLevel(LLPipeline::SHADER_OBJECT); @@ -72,156 +31,50 @@ void LLDrawPoolSimple::beginRenderPass(S32 pass) glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); - if (gPipeline.getLightingDetail() >= 2) - { - glEnableClientState(GL_COLOR_ARRAY); - } - - if (mVertexShaderLevel > 0) - { - S32 scatterTex = gPipeline.mObjectSimpleProgram.enableTexture(LLPipeline::GLSL_SCATTER_MAP); - LLViewerImage::bindTexture(gSky.mVOSkyp->getScatterMap(), scatterTex); - sDiffTex = gPipeline.mObjectSimpleProgram.enableTexture(LLPipeline::GLSL_DIFFUSE_MAP); - } + glEnableClientState(GL_COLOR_ARRAY); } - void LLDrawPoolSimple::render(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_SIMPLE); - if (mDrawFace.empty()) - { - return; - } - - bindGLVertexPointer(); - bindGLTexCoordPointer(); - bindGLNormalPointer(); - if (gPipeline.getLightingDetail() >= 2) - { - bindGLColorPointer(); - } - - LLViewerImage* tex = getTexture(); - LLGLState alpha_test(GL_ALPHA_TEST, FALSE); - LLGLState blend(GL_BLEND, FALSE); - - if (tex) - { - LLViewerImage::bindTexture(tex,sDiffTex); - if (tex->getPrimaryFormat() == GL_ALPHA) - { - // Enable Invisibility Hack - alpha_test.enable(); - blend.enable(); - } - } - else - { - LLImageGL::unbindTexture(sDiffTex, GL_TEXTURE_2D); - } - - drawLoop(); -} - -void LLDrawPoolSimple::endRenderPass(S32 pass) -{ - if (mVertexShaderLevel > 0) - { - gPipeline.mObjectSimpleProgram.disableTexture(LLPipeline::GLSL_SCATTER_MAP); - gPipeline.mObjectSimpleProgram.disableTexture(LLPipeline::GLSL_DIFFUSE_MAP); - glActiveTextureARB(GL_TEXTURE0_ARB); - glEnable(GL_TEXTURE_2D); - } + LLGLDisable blend(GL_BLEND); + LLGLDisable alpha_test(GL_ALPHA_TEST); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); - if (gPipeline.getLightingDetail() >= 2) { - glDisableClientState(GL_COLOR_ARRAY); + LLFastTimer t(LLFastTimer::FTM_RENDER_SIMPLE); + gPipeline.enableLightsDynamic(1.f); + renderTexture(LLRenderPass::PASS_SIMPLE, getVertexDataMask()); + renderActive(LLRenderPass::PASS_SIMPLE, getVertexDataMask()); } -} -void LLDrawPoolSimple::renderForSelect() -{ - if (mDrawFace.empty() || !mMemory.count()) { - return; + LLFastTimer t(LLFastTimer::FTM_RENDER_GRASS); + LLGLEnable blend(GL_BLEND); + LLGLEnable alpha_test(GL_ALPHA_TEST); + glAlphaFunc(GL_GREATER, 0.5f); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + //render grass + LLRenderPass::renderTexture(LLRenderPass::PASS_GRASS, getVertexDataMask()); + glAlphaFunc(GL_GREATER, 0.01f); } - - glEnableClientState ( GL_VERTEX_ARRAY ); - - bindGLVertexPointer(); - - for (std::vector<LLFace*>::iterator iter = mDrawFace.begin(); - iter != mDrawFace.end(); iter++) + { - LLFace *facep = *iter; - LLDrawable *drawable = facep->getDrawable(); - if (drawable && !drawable->isDead() && (facep->getViewerObject()->mGLName)) - { - facep->renderForSelect(); - } + LLFastTimer t(LLFastTimer::FTM_RENDER_FULLBRIGHT); + U32 fullbright_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD | LLVertexBuffer::MAP_COLOR; + gPipeline.enableLightsFullbright(LLColor4(1,1,1,1)); + glDisableClientState(GL_NORMAL_ARRAY); + renderTexture(LLRenderPass::PASS_FULLBRIGHT, fullbright_mask); + renderActive(LLRenderPass::PASS_FULLBRIGHT, fullbright_mask); } -} - - -void LLDrawPoolSimple::renderFaceSelected(LLFace *facep, - LLImageGL *image, - const LLColor4 &color, - const S32 index_offset, const S32 index_count) -{ - facep->renderSelected(image, color, index_offset, index_count); -} - -void LLDrawPoolSimple::dirtyTexture(const LLViewerImage *texturep) -{ - if (mTexturep == texturep) { - for (std::vector<LLFace*>::iterator iter = mReferences.begin(); - iter != mReferences.end(); iter++) - { - LLFace *facep = *iter; - gPipeline.markTextured(facep->getDrawable()); - } + LLFastTimer t(LLFastTimer::FTM_RENDER_INVISIBLE); + U32 invisi_mask = LLVertexBuffer::MAP_VERTEX; + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + renderInvisible(invisi_mask); + renderActive(LLRenderPass::PASS_INVISIBLE, invisi_mask); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); } } -LLViewerImage *LLDrawPoolSimple::getTexture() -{ - return mTexturep; -} - -LLViewerImage *LLDrawPoolSimple::getDebugTexture() -{ - return mTexturep; -} - -LLColor3 LLDrawPoolSimple::getDebugColor() const -{ - return LLColor3(1.f, 1.f, 1.f); -} - -S32 LLDrawPoolSimple::getMaterialAttribIndex() -{ - return gPipeline.mObjectSimpleProgram.mAttribute[LLPipeline::GLSL_MATERIAL_COLOR]; -} - -// virtual -void LLDrawPoolSimple::enableShade() -{ - glDisableClientState(GL_COLOR_ARRAY); -} - -// virtual -void LLDrawPoolSimple::disableShade() -{ - glEnableClientState(GL_COLOR_ARRAY); -} - -// virtual -void LLDrawPoolSimple::setShade(F32 shade) -{ - glColor4f(0,0,0,shade); -} diff --git a/indra/newview/lldrawpoolsimple.h b/indra/newview/lldrawpoolsimple.h index 41c4580cea..f89230d866 100644 --- a/indra/newview/lldrawpoolsimple.h +++ b/indra/newview/lldrawpoolsimple.h @@ -11,64 +11,24 @@ #include "lldrawpool.h" -class LLFRInfo +class LLDrawPoolSimple : public LLRenderPass { public: - U32 mPrimType; - U32 mGeomIndex; - U32 mGeomIndexEnd; - U32 mNumIndices; - U32 mIndicesStart; - - LLFRInfo() - { - } - - LLFRInfo(const U32 pt, const U32 gi, const U32 gc, const U32 ni, const U32 is) : - mPrimType(pt), - mGeomIndex(gi), - mGeomIndexEnd(gi+gc), - mNumIndices(ni), - mIndicesStart(is) - { - } -}; - -class LLDrawPoolSimple : public LLDrawPool -{ - LLPointer<LLViewerImage> mTexturep; -public: enum { - SHADER_LEVEL_LOCAL_LIGHTS = 2 + VERTEX_DATA_MASK = LLVertexBuffer::MAP_VERTEX | + LLVertexBuffer::MAP_NORMAL | + LLVertexBuffer::MAP_TEXCOORD | + LLVertexBuffer::MAP_COLOR }; - - LLDrawPoolSimple(LLViewerImage *texturep); - - /*virtual*/ LLDrawPool *instancePool(); + virtual U32 getVertexDataMask() { return VERTEX_DATA_MASK; } + LLDrawPoolSimple(); + /*virtual*/ void beginRenderPass(S32 pass); - /*virtual*/ void endRenderPass(S32 pass); /*virtual*/ void render(S32 pass = 0); - /*virtual*/ void renderFaceSelected(LLFace *facep, - LLImageGL *image, - const LLColor4 &color, - const S32 index_offset = 0, const S32 index_count = 0); /*virtual*/ void prerender(); - /*virtual*/ void renderForSelect(); - /*virtual*/ void dirtyTexture(const LLViewerImage *texturep); - /*virtual*/ LLViewerImage *getTexture(); - /*virtual*/ LLViewerImage *getDebugTexture(); - /*virtual*/ LLColor3 getDebugColor() const; // For AGP debug display - /*virtual*/ BOOL match(LLFace* last_face, LLFace* facep); - - /*virtual*/ void enableShade(); - /*virtual*/ void disableShade(); - /*virtual*/ void setShade(F32 shade); - - virtual S32 getMaterialAttribIndex(); - static S32 sDiffTex; }; #endif // LL_LLDRAWPOOLSIMPLE_H diff --git a/indra/newview/lldrawpoolsky.cpp b/indra/newview/lldrawpoolsky.cpp index 96eb8ea721..80340f63b9 100644 --- a/indra/newview/lldrawpoolsky.cpp +++ b/indra/newview/lldrawpoolsky.cpp @@ -12,7 +12,6 @@ #include "imageids.h" -#include "llagparray.h" #include "llagent.h" #include "lldrawable.h" #include "llface.h" @@ -26,7 +25,7 @@ #include "pipeline.h" LLDrawPoolSky::LLDrawPoolSky() : - LLDrawPool(POOL_SKY, DATA_SIMPLE_IL_MASK, DATA_SIMPLE_NIL_MASK) + LLFacePool(POOL_SKY) { } @@ -62,15 +61,17 @@ void LLDrawPoolSky::render(S32 pass) glMatrixMode( GL_PROJECTION ); glPushMatrix(); - gViewerWindow->setup3DRender(); + //gViewerWindow->setup3DRender(); + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + LLVector3 origin = gCamera->getOrigin(); + glTranslatef(origin.mV[0], origin.mV[1], origin.mV[2]); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); - bindGLVertexPointer(); - bindGLTexCoordPointer(); - S32 face_count = (S32)mDrawFace.size(); for (S32 i = 0; i < llmin(6, face_count); ++i) @@ -78,13 +79,13 @@ void LLDrawPoolSky::render(S32 pass) renderSkyCubeFace(i); } - const LLFace *hbfaces[3]; + LLFace *hbfaces[3]; hbfaces[0] = NULL; hbfaces[1] = NULL; hbfaces[2] = NULL; for (S32 curr_face = 0; curr_face < face_count; curr_face++) { - const LLFace* facep = mDrawFace[curr_face]; + LLFace* facep = mDrawFace[curr_face]; if (voskyp->isSameFace(LLVOSky::FACE_SUN, facep)) { hbfaces[0] = facep; @@ -118,11 +119,12 @@ void LLDrawPoolSky::render(S32 pass) glMatrixMode( GL_PROJECTION ); glPopMatrix(); glMatrixMode( GL_MODELVIEW ); + glPopMatrix(); } void LLDrawPoolSky::renderSkyCubeFace(U8 side) { - const LLFace &face = *mDrawFace[LLVOSky::FACE_SIDE0 + side]; + LLFace &face = *mDrawFace[LLVOSky::FACE_SIDE0 + side]; if (!face.getGeomCount()) { return; @@ -130,20 +132,20 @@ void LLDrawPoolSky::renderSkyCubeFace(U8 side) mSkyTex[side].bindTexture(TRUE); - face.renderIndexed(getRawIndices()); + face.renderIndexed(); if (LLSkyTex::doInterpolate()) { LLGLEnable blend(GL_BLEND); mSkyTex[side].bindTexture(FALSE); glColor4f(1, 1, 1, LLSkyTex::getInterpVal()); // lighting is disabled - face.renderIndexed(getRawIndices()); + face.renderIndexed(); } mIndicesDrawn += face.getIndicesCount(); } -void LLDrawPoolSky::renderHeavenlyBody(U8 hb, const LLFace* face) +void LLDrawPoolSky::renderHeavenlyBody(U8 hb, LLFace* face) { if ( !mHB[hb]->getDraw() ) return; if (! face->getGeomCount()) return; @@ -152,13 +154,13 @@ void LLDrawPoolSky::renderHeavenlyBody(U8 hb, const LLFace* face) tex->bind(); LLColor4 color(mHB[hb]->getInterpColor()); LLOverrideFaceColor override(this, color); - face->renderIndexed(getRawIndices()); + face->renderIndexed(); mIndicesDrawn += face->getIndicesCount(); } -void LLDrawPoolSky::renderSunHalo(const LLFace* face) +void LLDrawPoolSky::renderSunHalo(LLFace* face) { if (! mHB[0]->getDraw()) return; if (! face->getGeomCount()) return; @@ -169,7 +171,7 @@ void LLDrawPoolSky::renderSunHalo(const LLFace* face) color.mV[3] = llclamp(mHB[0]->getHaloBrighness(), 0.f, 1.f); LLOverrideFaceColor override(this, color); - face->renderIndexed(getRawIndices()); + face->renderIndexed(); mIndicesDrawn += face->getIndicesCount(); } diff --git a/indra/newview/lldrawpoolsky.h b/indra/newview/lldrawpoolsky.h index 881ce6d542..88d1ce03d0 100644 --- a/indra/newview/lldrawpoolsky.h +++ b/indra/newview/lldrawpoolsky.h @@ -14,13 +14,21 @@ class LLSkyTex; class LLHeavenBody; -class LLDrawPoolSky : public LLDrawPool +class LLDrawPoolSky : public LLFacePool { private: LLSkyTex *mSkyTex; LLHeavenBody *mHB[2]; // Sun and Moon public: + enum + { + VERTEX_DATA_MASK = LLVertexBuffer::MAP_VERTEX | + LLVertexBuffer::MAP_TEXCOORD + }; + + virtual U32 getVertexDataMask() { return VERTEX_DATA_MASK; } + LLDrawPoolSky(); /*virtual*/ LLDrawPool *instancePool(); @@ -33,8 +41,8 @@ public: void setMoon(LLHeavenBody* moon) { mHB[1] = moon; } void renderSkyCubeFace(U8 side); - void renderHeavenlyBody(U8 hb, const LLFace* face); - void renderSunHalo(const LLFace* face); + void renderHeavenlyBody(U8 hb, LLFace* face); + void renderSunHalo(LLFace* face); virtual S32 getMaterialAttribIndex() { return 0; } }; diff --git a/indra/newview/lldrawpoolterrain.cpp b/indra/newview/lldrawpoolterrain.cpp index 3e6ae7bf85..8c5c2e177a 100644 --- a/indra/newview/lldrawpoolterrain.cpp +++ b/indra/newview/lldrawpoolterrain.cpp @@ -13,7 +13,6 @@ #include "llfasttimer.h" #include "llagent.h" -#include "llagparray.h" #include "llviewercontrol.h" #include "lldrawable.h" #include "llface.h" @@ -37,7 +36,7 @@ S32 LLDrawPoolTerrain::sDetailMode = 1; F32 LLDrawPoolTerrain::sDetailScale = DETAIL_SCALE; LLDrawPoolTerrain::LLDrawPoolTerrain(LLViewerImage *texturep) : - LLDrawPool(POOL_TERRAIN, DATA_SIMPLE_IL_MASK | DATA_COLORS_MASK | DATA_TEX_COORDS1_MASK, DATA_SIMPLE_NIL_MASK), + LLFacePool(POOL_TERRAIN), mTexturep(texturep) { // Hack! @@ -75,6 +74,13 @@ void LLDrawPoolTerrain::prerender() #if 0 // 1.9.2 mVertexShaderLevel = gPipeline.getVertexShaderLevel(LLPipeline::SHADER_ENVIRONMENT); #endif + sDetailMode = gSavedSettings.getS32("RenderTerrainDetail"); +} + +//static +S32 LLDrawPoolTerrain::getDetailMode() +{ + return sDetailMode; } void LLDrawPoolTerrain::render(S32 pass) @@ -86,6 +92,15 @@ void LLDrawPoolTerrain::render(S32 pass) return; } + // Hack! Get the region that this draw pool is rendering from! + LLViewerRegion *regionp = mDrawFace[0]->getDrawable()->getVObj()->getRegion(); + LLVLComposition *compp = regionp->getComposition(); + for (S32 i = 0; i < 4; i++) + { + compp->mDetailTextures[i]->setBoostLevel(LLViewerImage::BOOST_TERRAIN); + compp->mDetailTextures[i]->addTextureStats(1024.f*1024.f); // assume large pixel area + } + if (!gGLManager.mHasMultitexture) { // No mulititexture, render simple land. @@ -152,25 +167,16 @@ void LLDrawPoolTerrain::renderFull4TUShader() glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); - bindGLVertexPointer(); - bindGLNormalPointer(); if (gPipeline.getLightingDetail() >= 2) { glEnableClientState(GL_COLOR_ARRAY); - bindGLColorPointer(); } - + glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA); // Hack! Get the region that this draw pool is rendering from! LLViewerRegion *regionp = mDrawFace[0]->getDrawable()->getVObj()->getRegion(); LLVLComposition *compp = regionp->getComposition(); - for (S32 i = 0; i < 4; i++) - { - compp->mDetailTextures[i]->setBoostLevel(LLViewerImage::BOOST_TERRAIN); - compp->mDetailTextures[i]->addTextureStats(1024.f*1024.f); // assume large pixel area - } - LLViewerImage *detail_texture0p = compp->mDetailTextures[0]; LLViewerImage *detail_texture1p = compp->mDetailTextures[1]; LLViewerImage *detail_texture2p = compp->mDetailTextures[2]; @@ -200,8 +206,7 @@ void LLDrawPoolTerrain::renderFull4TUShader() S32 detailTex0 = gPipeline.mTerrainProgram.enableTexture(LLPipeline::GLSL_TERRAIN_DETAIL0); S32 detailTex1 = gPipeline.mTerrainProgram.enableTexture(LLPipeline::GLSL_TERRAIN_DETAIL1); S32 rampTex = gPipeline.mTerrainProgram.enableTexture(LLPipeline::GLSL_TERRAIN_ALPHARAMP); - S32 scatterTex = gPipeline.mTerrainProgram.enableTexture(LLPipeline::GLSL_SCATTER_MAP); - + LLViewerImage::bindTexture(detail_texture0p,detailTex0); glClientActiveTextureARB(GL_TEXTURE0_ARB); @@ -222,7 +227,6 @@ void LLDrawPoolTerrain::renderFull4TUShader() glClientActiveTextureARB(GL_TEXTURE1_ARB); glEnableClientState(GL_TEXTURE_COORD_ARRAY); - bindGLTexCoordPointer(1); // // Stage 2: Interpolate detail1 with existing based on ramp @@ -239,9 +243,6 @@ void LLDrawPoolTerrain::renderFull4TUShader() glTexGenfv(GL_S, GL_OBJECT_PLANE, tp0.mV); glTexGenfv(GL_T, GL_OBJECT_PLANE, tp1.mV); - // Stage 4: Haze - LLViewerImage::bindTexture(gSky.mVOSkyp->getScatterMap(), scatterTex); - // // Stage 3: Modulate with primary color for lighting // @@ -278,7 +279,6 @@ void LLDrawPoolTerrain::renderFull4TUShader() glClientActiveTextureARB(GL_TEXTURE1_ARB); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glActiveTextureARB(GL_TEXTURE1_ARB); - bindGLTexCoordPointer(1); // Set the texture matrix glMatrixMode(GL_TEXTURE); @@ -310,7 +310,6 @@ void LLDrawPoolTerrain::renderFull4TUShader() glClientActiveTextureARB(GL_TEXTURE3_ARB); glActiveTextureARB(GL_TEXTURE3_ARB); glEnableClientState(GL_TEXTURE_COORD_ARRAY); - bindGLTexCoordPointer(1); // Set the texture matrix glMatrixMode(GL_TEXTURE); @@ -323,7 +322,6 @@ void LLDrawPoolTerrain::renderFull4TUShader() } // Disable multitexture - gPipeline.mTerrainProgram.disableTexture(LLPipeline::GLSL_SCATTER_MAP); gPipeline.mTerrainProgram.disableTexture(LLPipeline::GLSL_TERRAIN_ALPHARAMP); gPipeline.mTerrainProgram.disableTexture(LLPipeline::GLSL_TERRAIN_DETAIL0); gPipeline.mTerrainProgram.disableTexture(LLPipeline::GLSL_TERRAIN_DETAIL1); @@ -377,18 +375,9 @@ void LLDrawPoolTerrain::renderFull4TU() glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); - bindGLVertexPointer(); - bindGLNormalPointer(); - // Hack! Get the region that this draw pool is rendering from! LLViewerRegion *regionp = mDrawFace[0]->getDrawable()->getVObj()->getRegion(); LLVLComposition *compp = regionp->getComposition(); - for (S32 i = 0; i < 4; i++) - { - compp->mDetailTextures[i]->setBoostLevel(LLViewerImage::BOOST_TERRAIN); - compp->mDetailTextures[i]->addTextureStats(1024.f*1024.f); // assume large pixel area - } - LLViewerImage *detail_texture0p = compp->mDetailTextures[0]; LLViewerImage *detail_texture1p = compp->mDetailTextures[1]; LLViewerImage *detail_texture2p = compp->mDetailTextures[2]; @@ -411,6 +400,7 @@ void LLDrawPoolTerrain::renderFull4TU() // // Stage 0: detail texture 0 // + glActiveTextureARB(GL_TEXTURE0_ARB); LLViewerImage::bindTexture(detail_texture0p,0); glClientActiveTextureARB(GL_TEXTURE0_ARB); @@ -432,12 +422,12 @@ void LLDrawPoolTerrain::renderFull4TU() // // Stage 1: Generate alpha ramp for detail0/detail1 transition // + glActiveTextureARB(GL_TEXTURE1_ARB); LLViewerImage::bindTexture(m2DAlphaRampImagep,1); glEnable(GL_TEXTURE_2D); // Texture unit 1 glClientActiveTextureARB(GL_TEXTURE1_ARB); glEnableClientState(GL_TEXTURE_COORD_ARRAY); - bindGLTexCoordPointer(1); // Care about alpha only glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); @@ -452,6 +442,7 @@ void LLDrawPoolTerrain::renderFull4TU() // // Stage 2: Interpolate detail1 with existing based on ramp // + glActiveTextureARB(GL_TEXTURE2_ARB); LLViewerImage::bindTexture(detail_texture1p,2); glEnable(GL_TEXTURE_2D); // Texture unit 2 glClientActiveTextureARB(GL_TEXTURE2_ARB); @@ -477,6 +468,7 @@ void LLDrawPoolTerrain::renderFull4TU() // // Stage 3: Modulate with primary (vertex) color for lighting // + glActiveTextureARB(GL_TEXTURE3_ARB); LLViewerImage::bindTexture(detail_texture1p,3); // bind any texture glEnable(GL_TEXTURE_2D); // Texture unit 3 glClientActiveTextureARB(GL_TEXTURE3_ARB); @@ -498,6 +490,7 @@ void LLDrawPoolTerrain::renderFull4TU() // Stage 0: Write detail3 into base // + glActiveTextureARB(GL_TEXTURE0_ARB); LLViewerImage::bindTexture(detail_texture3p,0); glClientActiveTextureARB(GL_TEXTURE0_ARB); @@ -519,14 +512,13 @@ void LLDrawPoolTerrain::renderFull4TU() // // Stage 1: Generate alpha ramp for detail2/detail3 transition // + glActiveTextureARB(GL_TEXTURE1_ARB); LLViewerImage::bindTexture(m2DAlphaRampImagep,1); glEnable(GL_TEXTURE_2D); // Texture unit 1 glClientActiveTextureARB(GL_TEXTURE1_ARB); glEnableClientState(GL_TEXTURE_COORD_ARRAY); - bindGLTexCoordPointer(1); - // Set the texture matrix glMatrixMode(GL_TEXTURE); @@ -547,6 +539,7 @@ void LLDrawPoolTerrain::renderFull4TU() // // Stage 2: Interpolate detail2 with existing based on ramp // + glActiveTextureARB(GL_TEXTURE2_ARB); LLViewerImage::bindTexture(detail_texture2p,2); glEnable(GL_TEXTURE_2D); // Texture unit 2 glClientActiveTextureARB(GL_TEXTURE2_ARB); @@ -573,19 +566,19 @@ void LLDrawPoolTerrain::renderFull4TU() // // Stage 3: Generate alpha ramp for detail1/detail2 transition // + glActiveTextureARB(GL_TEXTURE3_ARB); LLViewerImage::bindTexture(m2DAlphaRampImagep,3); glEnable(GL_TEXTURE_2D); // Texture unit 3 glClientActiveTextureARB(GL_TEXTURE3_ARB); glEnableClientState(GL_TEXTURE_COORD_ARRAY); - bindGLTexCoordPointer(1); // Set the texture matrix glMatrixMode(GL_TEXTURE); glLoadIdentity(); glTranslatef(-1.f, 0.f, 0.f); - + // Set alpha texture and do lighting modulation glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE); @@ -656,18 +649,9 @@ void LLDrawPoolTerrain::renderFull2TU() glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); - bindGLVertexPointer(); - bindGLNormalPointer(); - // Hack! Get the region that this draw pool is rendering from! LLViewerRegion *regionp = mDrawFace[0]->getDrawable()->getVObj()->getRegion(); LLVLComposition *compp = regionp->getComposition(); - for (S32 i = 0; i < 4; i++) - { - compp->mDetailTextures[i]->setBoostLevel(LLViewerImage::BOOST_TERRAIN); - compp->mDetailTextures[i]->addTextureStats(1024.f*1024.f); // assume large pixel area - } - LLViewerImage *detail_texture0p = compp->mDetailTextures[0]; LLViewerImage *detail_texture1p = compp->mDetailTextures[1]; LLViewerImage *detail_texture2p = compp->mDetailTextures[2]; @@ -724,7 +708,6 @@ void LLDrawPoolTerrain::renderFull2TU() glDisable(GL_TEXTURE_GEN_S); glDisable(GL_TEXTURE_GEN_T); glEnableClientState(GL_TEXTURE_COORD_ARRAY); - bindGLTexCoordPointer(1); // Care about alpha only glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); @@ -781,7 +764,6 @@ void LLDrawPoolTerrain::renderFull2TU() glTranslatef(-1.f, 0.f, 0.f); glEnableClientState(GL_TEXTURE_COORD_ARRAY); - bindGLTexCoordPointer(1); // Care about alpha only glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); @@ -839,7 +821,6 @@ void LLDrawPoolTerrain::renderFull2TU() glTranslatef(-2.f, 0.f, 0.f); glEnableClientState(GL_TEXTURE_COORD_ARRAY); - bindGLTexCoordPointer(1); // Care about alpha only glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); @@ -919,9 +900,6 @@ void LLDrawPoolTerrain::renderSimple() glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); - bindGLVertexPointer(); - bindGLNormalPointer(); - LLVector4 tp0, tp1; //---------------------------------------------------------------------------- @@ -999,9 +977,6 @@ void LLDrawPoolTerrain::renderOwnership() glEnableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); - bindGLVertexPointer(); - bindGLTexCoordPointer(0); - LLViewerImage::bindTexture(texturep); glClientActiveTextureARB(GL_TEXTURE0_ARB); @@ -1017,12 +992,12 @@ void LLDrawPoolTerrain::renderOwnership() const F32 TEXTURE_FUDGE = 257.f / 256.f; glScalef( TEXTURE_FUDGE, TEXTURE_FUDGE, 1.f ); - const U32* index_array = getRawIndices(); for (std::vector<LLFace*>::iterator iter = mDrawFace.begin(); iter != mDrawFace.end(); iter++) { LLFace *facep = *iter; - facep->renderIndexed(index_array); + facep->renderIndexed(LLVertexBuffer::MAP_VERTEX | + LLVertexBuffer::MAP_TEXCOORD); } glMatrixMode(GL_TEXTURE); @@ -1036,14 +1011,13 @@ void LLDrawPoolTerrain::renderOwnership() void LLDrawPoolTerrain::renderForSelect() { - if (mDrawFace.empty() || !mMemory.count()) + if (mDrawFace.empty()) { return; } - glEnableClientState ( GL_VERTEX_ARRAY ); - - bindGLVertexPointer(); + + LLImageGL::unbindTexture(0); for (std::vector<LLFace*>::iterator iter = mDrawFace.begin(); iter != mDrawFace.end(); iter++) @@ -1051,14 +1025,14 @@ void LLDrawPoolTerrain::renderForSelect() LLFace *facep = *iter; if (!facep->getDrawable()->isDead() && (facep->getDrawable()->getVObj()->mGLName)) { - facep->renderForSelect(); + facep->renderForSelect(LLVertexBuffer::MAP_VERTEX); } } } -void LLDrawPoolTerrain::dirtyTexture(const LLViewerImage *texturep) +void LLDrawPoolTerrain::dirtyTextures(const std::set<LLViewerImage*>& textures) { - if (mTexturep == texturep) + if (textures.find(mTexturep) != textures.end()) { for (std::vector<LLFace*>::iterator iter = mReferences.begin(); iter != mReferences.end(); iter++) diff --git a/indra/newview/lldrawpoolterrain.h b/indra/newview/lldrawpoolterrain.h index b5fe0a30fd..4882532e8a 100644 --- a/indra/newview/lldrawpoolterrain.h +++ b/indra/newview/lldrawpoolterrain.h @@ -11,10 +11,22 @@ #include "lldrawpool.h" -class LLDrawPoolTerrain : public LLDrawPool +class LLDrawPoolTerrain : public LLFacePool { LLPointer<LLViewerImage> mTexturep; public: + enum + { + VERTEX_DATA_MASK = LLVertexBuffer::MAP_VERTEX | + LLVertexBuffer::MAP_NORMAL | + LLVertexBuffer::MAP_TEXCOORD | + LLVertexBuffer::MAP_TEXCOORD2 | + LLVertexBuffer::MAP_COLOR + }; + + virtual U32 getVertexDataMask() { return VERTEX_DATA_MASK; } + static S32 getDetailMode(); + LLDrawPoolTerrain(LLViewerImage *texturep); virtual ~LLDrawPoolTerrain(); @@ -24,7 +36,7 @@ public: /*virtual*/ void render(S32 pass = 0); /*virtual*/ void prerender(); /*virtual*/ void renderForSelect(); - /*virtual*/ void dirtyTexture(const LLViewerImage *texturep); + /*virtual*/ void dirtyTextures(const std::set<LLViewerImage*>& textures); /*virtual*/ LLViewerImage *getTexture(); /*virtual*/ LLViewerImage *getDebugTexture(); /*virtual*/ LLColor3 getDebugColor() const; // For AGP debug display diff --git a/indra/newview/lldrawpooltree.cpp b/indra/newview/lldrawpooltree.cpp index c41ceedac7..170669955c 100644 --- a/indra/newview/lldrawpooltree.cpp +++ b/indra/newview/lldrawpooltree.cpp @@ -10,7 +10,6 @@ #include "lldrawpooltree.h" -#include "llagparray.h" #include "lldrawable.h" #include "llface.h" #include "llsky.h" @@ -22,7 +21,7 @@ S32 LLDrawPoolTree::sDiffTex = 0; LLDrawPoolTree::LLDrawPoolTree(LLViewerImage *texturep) : - LLDrawPool(POOL_TREE, DATA_SIMPLE_IL_MASK, 0), + LLFacePool(POOL_TREE), mTexturep(texturep) { mTexturep->bind(0); @@ -36,7 +35,7 @@ LLDrawPool *LLDrawPoolTree::instancePool() void LLDrawPoolTree::prerender() { - mVertexShaderLevel = gPipeline.getVertexShaderLevel(LLPipeline::SHADER_OBJECT); + mVertexShaderLevel = 0; } void LLDrawPoolTree::beginRenderPass(S32 pass) @@ -44,13 +43,7 @@ void LLDrawPoolTree::beginRenderPass(S32 pass) glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); - - if ((mVertexShaderLevel > 0)) - { - S32 scatterTex = gPipeline.mObjectSimpleProgram.enableTexture(LLPipeline::GLSL_SCATTER_MAP); - LLViewerImage::bindTexture(gSky.mVOSkyp->getScatterMap(), scatterTex); - sDiffTex = gPipeline.mObjectSimpleProgram.enableTexture(LLPipeline::GLSL_DIFFUSE_MAP); - } + glAlphaFunc(GL_GREATER, 0.5f); } void LLDrawPoolTree::render(S32 pass) @@ -64,34 +57,21 @@ void LLDrawPoolTree::render(S32 pass) gPipeline.enableLightsDynamic(1.f); LLGLSPipelineAlpha gls_pipeline_alpha; - - bindGLVertexPointer(); - bindGLTexCoordPointer(); - bindGLNormalPointer(); - LLOverrideFaceColor color(this, 1.f, 1.f, 1.f, 1.f); renderTree(); - } void LLDrawPoolTree::endRenderPass(S32 pass) { - if ((mVertexShaderLevel > 0)) - { - gPipeline.mObjectSimpleProgram.disableTexture(LLPipeline::GLSL_SCATTER_MAP); - gPipeline.mObjectSimpleProgram.disableTexture(LLPipeline::GLSL_DIFFUSE_MAP); - glActiveTextureARB(GL_TEXTURE0_ARB); - glEnable(GL_TEXTURE_2D); - } - + glAlphaFunc(GL_GREATER, 0.01f); glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); } void LLDrawPoolTree::renderForSelect() { - if (mDrawFace.empty() || !mMemory.count()) + if (mDrawFace.empty()) { return; } @@ -104,10 +84,7 @@ void LLDrawPoolTree::renderForSelect() LLGLSObjectSelectAlpha gls_alpha; glBlendFunc(GL_ONE, GL_ZERO); - glAlphaFunc(gPickTransparent ? GL_GEQUAL : GL_GREATER, 0.f); - - bindGLVertexPointer(); - bindGLTexCoordPointer(); + glAlphaFunc(GL_GREATER, 0.5f); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE); @@ -147,6 +124,8 @@ void LLDrawPoolTree::renderTree(BOOL selecting) } } + U32 indices_drawn = 0; + glMatrixMode(GL_MODELVIEW); for (std::vector<LLFace*>::iterator iter = mDrawFace.begin(); @@ -155,11 +134,14 @@ void LLDrawPoolTree::renderTree(BOOL selecting) LLFace *face = *iter; LLDrawable *drawablep = face->getDrawable(); - if (drawablep->isDead()) + if (drawablep->isDead() || face->mVertexBuffer.isNull()) { continue; } + face->mVertexBuffer->setBuffer(LLDrawPoolTree::VERTEX_DATA_MASK); + U32* indicesp = (U32*) face->mVertexBuffer->getIndicesPointer(); + // Render each of the trees LLVOTree *treep = (LLVOTree *)drawablep->getVObj(); @@ -217,55 +199,26 @@ void LLDrawPoolTree::renderTree(BOOL selecting) } } - if (app_angle > (THRESH_ANGLE_FOR_BILLBOARD + BLEND_RANGE_FOR_BILLBOARD)) - { - // - // Draw only the full geometry tree - // - //stop_depth = (app_angle < THRESH_ANGLE_FOR_RECURSION_REDUCTION); - glAlphaFunc(GL_GREATER, 0.5f); - LLDrawPool::LLOverrideFaceColor clr(this, color); - treep->drawBranchPipeline(this, trunk_LOD, stop_depth, treep->mDepth, treep->mTrunkDepth, 1.0, treep->mTwist, droop, treep->mBranches, alpha); - } - else if (app_angle < (THRESH_ANGLE_FOR_BILLBOARD - BLEND_RANGE_FOR_BILLBOARD)) + if (app_angle < (THRESH_ANGLE_FOR_BILLBOARD - BLEND_RANGE_FOR_BILLBOARD)) { // // Draw only the billboard // // Only the billboard, can use closer to normal alpha func. stop_depth = -1; - glAlphaFunc(GL_GREATER, 0.4f); - LLDrawPool::LLOverrideFaceColor clr(this, color); - treep->drawBranchPipeline(this, trunk_LOD, stop_depth, treep->mDepth, treep->mTrunkDepth, 1.0, treep->mTwist, droop, treep->mBranches, alpha); + LLFacePool::LLOverrideFaceColor clr(this, color); + indices_drawn += treep->drawBranchPipeline(indicesp, trunk_LOD, stop_depth, treep->mDepth, treep->mTrunkDepth, 1.0, treep->mTwist, droop, treep->mBranches, alpha); } - else + else // if (app_angle > (THRESH_ANGLE_FOR_BILLBOARD + BLEND_RANGE_FOR_BILLBOARD)) { // - // Draw a blended version including both billboard and full tree - // - alpha = (app_angle - THRESH_ANGLE_FOR_BILLBOARD)/BLEND_RANGE_FOR_BILLBOARD; - BOOL billboard_depth = TRUE; // billboard gets alpha - if (alpha > 0.5f) - { - billboard_depth = FALSE; - } - alpha = alpha/2.f + 0.5f; - - glAlphaFunc(GL_GREATER, alpha*0.5f); - { - LLGLDepthTest gls_depth(GL_TRUE, billboard_depth ? GL_FALSE : GL_TRUE); - color.mV[3] = (U8) (llclamp(alpha, 0.0f, 1.0f) * 255); - LLDrawPool::LLOverrideFaceColor clr(this, color); - treep->drawBranchPipeline(this, trunk_LOD, 0, treep->mDepth, treep->mTrunkDepth, 1.0, treep->mTwist, droop, treep->mBranches, alpha); - } - { - LLGLDepthTest gls_depth(GL_TRUE, billboard_depth ? GL_TRUE : GL_FALSE); - glAlphaFunc(GL_GREATER, (1.f - alpha)*0.1f); - color.mV[3] = (U8) (llclamp(1.f-alpha, 0.0f, 1.0f) * 255); - LLDrawPool::LLOverrideFaceColor clr(this, color); - treep->drawBranchPipeline(this, trunk_LOD, -1, treep->mDepth, treep->mTrunkDepth, 1.0, treep->mTwist, droop, treep->mBranches, 1.f - alpha); - } + // Draw only the full geometry tree + // + //stop_depth = (app_angle < THRESH_ANGLE_FOR_RECURSION_REDUCTION); + LLFacePool::LLOverrideFaceColor clr(this, color); + indices_drawn += treep->drawBranchPipeline(indicesp, trunk_LOD, stop_depth, treep->mDepth, treep->mTrunkDepth, 1.0, treep->mTwist, droop, treep->mBranches, alpha); } + glPopMatrix(); } } @@ -279,45 +232,21 @@ void LLDrawPoolTree::renderTree(BOOL selecting) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } } - glAlphaFunc(GL_GREATER, 0.01f); -} - - -S32 LLDrawPoolTree::rebuild() -{ - mRebuildTime++; - if (mRebuildTime > mRebuildFreq) - { - // Flush AGP to force an AGP realloc and reduce AGP fragmentation - flushAGP(); - mRebuildTime = 0; - } - return 0; + addIndicesDrawn(indices_drawn); } BOOL LLDrawPoolTree::verify() const { - BOOL ok = TRUE; - - // shared geometry. Just verify that it's there and correct. +/* BOOL ok = TRUE; - // Verify all indices in the pool are in the right range - const U32 *indicesp = getRawIndices(); - for (U32 i = 0; i < getIndexCount(); i++) - { - if (indicesp[i] > getVertexCount()) - { - ok = FALSE; - llinfos << "Bad index in tree pool!" << llendl; - } - } - if (!ok) { printDebugInfo(); } - return ok; + return ok;*/ + + return TRUE; } LLViewerImage *LLDrawPoolTree::getTexture() diff --git a/indra/newview/lldrawpooltree.h b/indra/newview/lldrawpooltree.h index 228b11a981..5b937cf688 100644 --- a/indra/newview/lldrawpooltree.h +++ b/indra/newview/lldrawpooltree.h @@ -11,10 +11,19 @@ #include "lldrawpool.h" -class LLDrawPoolTree : public LLDrawPool +class LLDrawPoolTree : public LLFacePool { LLPointer<LLViewerImage> mTexturep; public: + enum + { + VERTEX_DATA_MASK = LLVertexBuffer::MAP_VERTEX | + LLVertexBuffer::MAP_NORMAL | + LLVertexBuffer::MAP_TEXCOORD + }; + + virtual U32 getVertexDataMask() { return VERTEX_DATA_MASK; } + LLDrawPoolTree(LLViewerImage *texturep); /*virtual*/ LLDrawPool *instancePool(); @@ -24,7 +33,6 @@ public: /*virtual*/ void render(S32 pass = 0); /*virtual*/ void endRenderPass( S32 pass ); /*virtual*/ void renderForSelect(); - /*virtual*/ S32 rebuild(); /*virtual*/ BOOL verify() const; /*virtual*/ LLViewerImage *getTexture(); /*virtual*/ LLViewerImage *getDebugTexture(); diff --git a/indra/newview/lldrawpoolwater.cpp b/indra/newview/lldrawpoolwater.cpp index 108048efbc..db5debc079 100644 --- a/indra/newview/lldrawpoolwater.cpp +++ b/indra/newview/lldrawpoolwater.cpp @@ -16,7 +16,6 @@ #include "m3math.h" #include "llagent.h" // for gAgent for getRegion for getWaterHeight -#include "llagparray.h" #include "llcubemap.h" #include "lldrawable.h" #include "llface.h" @@ -44,11 +43,11 @@ int nhpo2(int v) } static GLuint sScreenTex = 0; +BOOL LLDrawPoolWater::sSkipScreenCopy = FALSE; LLDrawPoolWater::LLDrawPoolWater() : - LLDrawPool(POOL_WATER, DATA_SIMPLE_IL_MASK, DATA_SIMPLE_NIL_MASK) + LLFacePool(POOL_WATER) { - mCleanupUnused = TRUE; mHBTex[0] = gImageList.getImage(gSunTextureID, TRUE, TRUE); mHBTex[0]->bind(); mHBTex[0]->setClamp(TRUE, TRUE); @@ -116,11 +115,21 @@ extern LLColor4U MAX_WATER_COLOR; void LLDrawPoolWater::render(S32 pass) { LLFastTimer ftm(LLFastTimer::FTM_RENDER_WATER); - if (mDrawFace.empty()) + if (mDrawFace.empty() || LLDrawable::getCurrentFrame() <= 1) { return; } + //do a quick 'n dirty depth sort + for (std::vector<LLFace*>::iterator iter = mDrawFace.begin(); + iter != mDrawFace.end(); iter++) + { + LLFace* facep = *iter; + facep->mDistance = -facep->mCenterLocal.mV[2]; + } + + std::sort(mDrawFace.begin(), mDrawFace.end(), LLFace::CompareDistanceGreater()); + LLGLSPipelineAlpha alphaState; if ((mVertexShaderLevel >= SHADER_LEVEL_RIPPLE)) @@ -145,7 +154,7 @@ void LLDrawPoolWater::render(S32 pass) return; } - const LLFace* refl_face = voskyp->getReflFace(); + LLFace* refl_face = voskyp->getReflFace(); gPipeline.disableLights(); @@ -157,10 +166,6 @@ void LLDrawPoolWater::render(S32 pass) glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); - bindGLVertexPointer(); - bindGLNormalPointer(); - bindGLTexCoordPointer(); - // Set up second pass first glActiveTextureARB(GL_TEXTURE1_ARB); mWaterImagep->addTextureStats(1024.f*1024.f); @@ -227,7 +232,7 @@ void LLDrawPoolWater::render(S32 pass) continue; } face->bindTexture(); - face->renderIndexed(getRawIndices()); + face->renderIndexed(); mIndicesDrawn += face->getIndicesCount(); } @@ -288,7 +293,7 @@ void LLDrawPoolWater::render(S32 pass) if (face->getGeomCount() > 0) { - face->renderIndexed(getRawIndices()); + face->renderIndexed(); mIndicesDrawn += face->getIndicesCount(); } } @@ -335,7 +340,7 @@ void LLDrawPoolWater::renderShaderSimple() return; } - const LLFace* refl_face = voskyp->getReflFace(); + LLFace* refl_face = voskyp->getReflFace(); LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE); @@ -345,10 +350,6 @@ void LLDrawPoolWater::renderShaderSimple() glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); - bindGLVertexPointer(); - bindGLNormalPointer(); - bindGLTexCoordPointer(); - // Set up second pass first S32 bumpTex = gPipeline.mWaterProgram.enableTexture(LLPipeline::GLSL_BUMP_MAP); mWaterImagep->addTextureStats(1024.f*1024.f); @@ -413,9 +414,6 @@ void LLDrawPoolWater::renderShaderSimple() glMatrixMode(GL_MODELVIEW); } - S32 scatterTex = gPipeline.mWaterProgram.enableTexture(LLPipeline::GLSL_SCATTER_MAP); - LLViewerImage::bindTexture(gSky.mVOSkyp->getScatterMap(), scatterTex); - S32 diffTex = gPipeline.mWaterProgram.enableTexture(LLPipeline::GLSL_DIFFUSE_MAP); gPipeline.mWaterProgram.bind(); @@ -429,7 +427,7 @@ void LLDrawPoolWater::renderShaderSimple() continue; } face->bindTexture(diffTex); - face->renderIndexed(getRawIndices()); + face->renderIndexed(); mIndicesDrawn += face->getIndicesCount(); } @@ -450,8 +448,7 @@ void LLDrawPoolWater::renderShaderSimple() glDisable(GL_TEXTURE_GEN_T); //texture unit 1 gPipeline.mWaterProgram.disableTexture(LLPipeline::GLSL_DIFFUSE_MAP); - gPipeline.mWaterProgram.disableTexture(LLPipeline::GLSL_SCATTER_MAP); - + // Disable texture coordinate and color arrays LLImageGL::unbindTexture(diffTex, GL_TEXTURE_2D); @@ -477,7 +474,7 @@ void LLDrawPoolWater::renderShaderSimple() glDisableClientState(GL_NORMAL_ARRAY); } -void LLDrawPoolWater::renderReflection(const LLFace* face) +void LLDrawPoolWater::renderReflection(LLFace* face) { LLVOSky *voskyp = gSky.mVOSkyp; @@ -505,7 +502,7 @@ void LLDrawPoolWater::renderReflection(const LLFace* face) LLViewerImage::bindTexture(mHBTex[dr]); LLOverrideFaceColor override(this, face->getFaceColor().mV); - face->renderIndexed(getRawIndices()); + face->renderIndexed(); mIndicesDrawn += face->getIndicesCount(); glDisableClientState(GL_TEXTURE_COORD_ARRAY); @@ -513,36 +510,44 @@ void LLDrawPoolWater::renderReflection(const LLFace* face) void bindScreenToTexture() { - GLint viewport[4]; - glGetIntegerv(GL_VIEWPORT, viewport); - GLuint resX = nhpo2(viewport[2]); - GLuint resY = nhpo2(viewport[3]); - - glBindTexture(GL_TEXTURE_2D, sScreenTex); - GLint cResX; - GLint cResY; - glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &cResX); - glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &cResY); - - if (cResX != (GLint)resX || cResY != (GLint)resY) + if (LLDrawPoolWater::sSkipScreenCopy) { - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, resX, resY, 0, GL_RGB, GL_FLOAT, NULL); - gImageList.updateMaxResidentTexMem(-1, resX*resY*3); + glBindTexture(GL_TEXTURE_2D, 0); } + else + { - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, viewport[0], viewport[1], 0, 0, viewport[2], viewport[3]); + GLint viewport[4]; + glGetIntegerv(GL_VIEWPORT, viewport); + GLuint resX = nhpo2(viewport[2]); + GLuint resY = nhpo2(viewport[3]); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glBindTexture(GL_TEXTURE_2D, sScreenTex); + GLint cResX; + GLint cResY; + glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &cResX); + glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &cResY); + + if (cResX != (GLint)resX || cResY != (GLint)resY) + { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, resX, resY, 0, GL_RGB, GL_FLOAT, NULL); + gImageList.updateMaxResidentTexMem(-1, resX*resY*3); + } - float scale[2]; - scale[0] = (float) viewport[2]/resX; - scale[1] = (float) viewport[3]/resY; - glUniform2fvARB(gPipeline.mWaterProgram.mUniform[LLPipeline::GLSL_WATER_FBSCALE], 1, scale); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, viewport[0], viewport[1], 0, 0, viewport[2], viewport[3]); - LLImageGL::sBoundTextureMemory += resX * resY * 3; + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + float scale[2]; + scale[0] = (float) viewport[2]/resX; + scale[1] = (float) viewport[3]/resY; + glUniform2fvARB(gPipeline.mWaterProgram.mUniform[LLPipeline::GLSL_WATER_FBSCALE], 1, scale); + + LLImageGL::sBoundTextureMemory += resX * resY * 3; + } } void LLDrawPoolWater::shade() @@ -577,9 +582,6 @@ void LLDrawPoolWater::shade() glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); LLGLDisable blend(GL_BLEND); - bindGLVertexPointer(); - bindGLNormalPointer(); - bindGLTexCoordPointer(); LLColor3 light_diffuse(0,0,0); F32 light_exp = 0.0f; @@ -630,9 +632,6 @@ void LLDrawPoolWater::shade() bindScreenToTexture(); - S32 scatterTex = gPipeline.mWaterProgram.enableTexture(LLPipeline::GLSL_SCATTER_MAP); - LLViewerImage::bindTexture(gSky.mVOSkyp->getScatterMap(), scatterTex); - S32 diffTex = gPipeline.mWaterProgram.enableTexture(LLPipeline::GLSL_DIFFUSE_MAP); LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE); @@ -678,7 +677,7 @@ void LLDrawPoolWater::shade() } face->bindTexture(diffTex); - face->renderIndexed(getRawIndices()); + face->renderIndexed(); mIndicesDrawn += face->getIndicesCount(); } } @@ -686,7 +685,6 @@ void LLDrawPoolWater::shade() gPipeline.mWaterProgram.disableTexture(LLPipeline::GLSL_ENVIRONMENT_MAP, GL_TEXTURE_CUBE_MAP_ARB); gPipeline.mWaterProgram.disableTexture(LLPipeline::GLSL_WATER_SCREENTEX); gPipeline.mWaterProgram.disableTexture(LLPipeline::GLSL_BUMP_MAP); - gPipeline.mWaterProgram.disableTexture(LLPipeline::GLSL_SCATTER_MAP); gPipeline.mWaterProgram.disableTexture(LLPipeline::GLSL_DIFFUSE_MAP); glActiveTextureARB(GL_TEXTURE0_ARB); @@ -695,10 +693,6 @@ void LLDrawPoolWater::shade() glClientActiveTextureARB(GL_TEXTURE0_ARB); glDisableClientState(GL_TEXTURE_COORD_ARRAY); - - /*glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY);*/ } void LLDrawPoolWater::renderForSelect() diff --git a/indra/newview/lldrawpoolwater.h b/indra/newview/lldrawpoolwater.h index 7e661b3718..fafacf4d34 100644 --- a/indra/newview/lldrawpoolwater.h +++ b/indra/newview/lldrawpoolwater.h @@ -16,7 +16,7 @@ class LLFace; class LLHeavenBody; class LLWaterSurface; -class LLDrawPoolWater: public LLDrawPool +class LLDrawPoolWater: public LLFacePool { protected: LLPointer<LLViewerImage> mHBTex[2]; @@ -25,6 +25,16 @@ protected: const LLWaterSurface *mWaterSurface; public: + static BOOL sSkipScreenCopy; + enum + { + VERTEX_DATA_MASK = LLVertexBuffer::MAP_VERTEX | + LLVertexBuffer::MAP_NORMAL | + LLVertexBuffer::MAP_TEXCOORD + }; + + virtual U32 getVertexDataMask() { return VERTEX_DATA_MASK; } + enum { SHADER_LEVEL_RIPPLE = 2, @@ -45,7 +55,7 @@ public: /*virtual*/ LLViewerImage *getDebugTexture(); /*virtual*/ LLColor3 getDebugColor() const; // For AGP debug display - void renderReflection(const LLFace* face); + void renderReflection(LLFace* face); void shade(); void renderShaderSimple(); diff --git a/indra/newview/lldynamictexture.cpp b/indra/newview/lldynamictexture.cpp index 0f0a9d9bda..f2981625f7 100644 --- a/indra/newview/lldynamictexture.cpp +++ b/indra/newview/lldynamictexture.cpp @@ -16,6 +16,8 @@ #include "llviewercamera.h" #include "llviewercontrol.h" #include "llviewerimage.h" +#include "llvertexbuffer.h" + // static LLLinkedList<LLDynamicTexture> LLDynamicTexture::sInstances[ LLDynamicTexture::ORDER_COUNT ]; @@ -174,6 +176,8 @@ BOOL LLDynamicTexture::updateAllInstances() return TRUE; } + BOOL started = FALSE; + BOOL result = FALSE; for( S32 order = 0; order < ORDER_COUNT; order++ ) { @@ -183,6 +187,12 @@ BOOL LLDynamicTexture::updateAllInstances() { if (dynamicTexture->needsRender()) { + if (!started) + { + started = TRUE; + LLVertexBuffer::startRender(); + } + dynamicTexture->preRender(); if (dynamicTexture->render()) { @@ -194,6 +204,11 @@ BOOL LLDynamicTexture::updateAllInstances() } } + if (started) + { + LLVertexBuffer::stopRender(); + } + return result; } diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index cd24454caf..64edcecdc6 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -10,13 +10,13 @@ #include "lldrawable.h" // lldrawable needs to be included before llface #include "llface.h" +#include "llviewertextureanim.h" #include "llviewercontrol.h" #include "llvolume.h" #include "m3math.h" #include "v3color.h" -#include "llagparray.h" #include "lldrawpoolsimple.h" #include "lldrawpoolbump.h" #include "llgl.h" @@ -28,8 +28,6 @@ #include "llvovolume.h" #include "pipeline.h" -#include "llagparray.inl" - #define LL_MAX_INDICES_COUNT 1000000 extern BOOL gPickFaces; @@ -118,25 +116,23 @@ void cylindricalProjection(LLVector2 &tc, const LLVolumeFace::VertexData &vd, co void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp) { - mGeneration = DIRTY; + mLastUpdateTime = gFrameTimeSeconds; + mVSize = 0.f; + mPixelArea = 1024.f; mState = GLOBAL; mDrawPoolp = NULL; + mPoolType = 0; mGeomIndex = -1; - mSkipRender = FALSE; - mNextFace = NULL; // mCenterLocal // mCenterAgent mDistance = 0.f; - mPrimType = LLTriangles; mGeomCount = 0; mIndicesCount = 0; mIndicesIndex = -1; mTexture = NULL; mTEOffset = -1; - mBackupMem = NULL; - setDrawable(drawablep); mVObjp = objp; @@ -144,6 +140,12 @@ void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp) mAlphaFade = 0.f; mFaceColor = LLColor4(1,0,0,1); + + mLastVertexBuffer = mVertexBuffer; + mLastGeomCount = mGeomCount; + mLastGeomIndex = mGeomIndex; + mLastIndicesCount = mIndicesCount; + mLastIndicesIndex = mIndicesIndex; } @@ -157,11 +159,6 @@ void LLFace::destroy() mDrawPoolp->removeFace(this); mDrawPoolp = NULL; } - - // Remove light and blocker list references - - delete[] mBackupMem; - mBackupMem = NULL; } @@ -175,13 +172,7 @@ void LLFace::setWorldMatrix(const LLMatrix4 &mat) llerrs << "Faces on this drawable are not independently modifiable\n" << llendl; } - -void LLFace::setDirty() -{ - mGeneration = DIRTY; -} - -void LLFace::setPool(LLDrawPool* new_pool, LLViewerImage *texturep) +void LLFace::setPool(LLFacePool* new_pool, LLViewerImage *texturep) { LLMemType mt1(LLMemType::MTYPE_DRAWABLE); @@ -196,22 +187,12 @@ void LLFace::setPool(LLDrawPool* new_pool, LLViewerImage *texturep) if (mDrawPoolp) { mDrawPoolp->removeFace(this); - mSkipRender = FALSE; - mNextFace = NULL; - // Invalidate geometry (will get rebuilt next frame) - setDirty(); if (mDrawablep) { gPipeline.markRebuild(mDrawablep, LLDrawable::REBUILD_ALL, TRUE); } } - if (isState(BACKLIST)) - { - delete[] mBackupMem; - mBackupMem = NULL; - clearState(BACKLIST); - } mGeomIndex = -1; // Add to new pool @@ -220,7 +201,6 @@ void LLFace::setPool(LLDrawPool* new_pool, LLViewerImage *texturep) new_pool->addFace(this); } mDrawPoolp = new_pool; - } mTexture = texturep; } @@ -249,91 +229,12 @@ void LLFace::setDrawable(LLDrawable *drawable) mXform = &drawable->mXform; } -S32 LLFace::allocBackupMem() -{ - LLMemType mt1(LLMemType::MTYPE_DRAWABLE); - - S32 size = 0; - size += mIndicesCount * 4; - size += mGeomCount * mDrawPoolp->getStride(); - - if (mDrawPoolp->mDataMaskNIL & LLDrawPool::DATA_VERTEX_WEIGHTS_MASK) - { - size += mGeomCount * mDrawPoolp->sDataSizes[LLDrawPool::DATA_VERTEX_WEIGHTS]; - } - - if (mDrawPoolp->mDataMaskNIL & LLDrawPool::DATA_CLOTHING_WEIGHTS_MASK) - { - size += mGeomCount * mDrawPoolp->sDataSizes[LLDrawPool::DATA_CLOTHING_WEIGHTS]; - } - - delete[] mBackupMem; - mBackupMem = new U8[size]; - return size; -} - - void LLFace::setSize(const S32 num_vertices, const S32 num_indices) { LLMemType mt1(LLMemType::MTYPE_DRAWABLE); - if (getState() & SHARED_GEOM) - { - mGeomCount = num_vertices; - mIndicesCount = num_indices; - return; // Shared, don't allocate or do anything with memory - } - if (num_vertices != (S32)mGeomCount || num_indices != (S32)mIndicesCount) - { - setDirty(); - - delete[] mBackupMem; - mBackupMem = NULL; - clearState(BACKLIST); - - mGeomCount = num_vertices; - mIndicesCount = num_indices; - } - -} - -BOOL LLFace::reserveIfNeeded() -{ - LLMemType mt1(LLMemType::MTYPE_DRAWABLE); - - if (getDirty()) - { - if (isState(BACKLIST)) - { - llwarns << "Reserve on backlisted object!" << llendl; - } - - if (0 == mGeomCount) - { - //llwarns << "Reserving zero bytes for face!" << llendl; - mGeomCount = 0; - mIndicesCount = 0; - return FALSE; - } - - mGeomIndex = mDrawPoolp->reserveGeom(mGeomCount); - // (reserveGeom() always returns a valid index) - mIndicesIndex = mDrawPoolp->reserveInd (mIndicesCount); - mGeneration = mDrawPoolp->mGeneration; - } - - return TRUE; -} - -void LLFace::unReserve() -{ - LLMemType mt1(LLMemType::MTYPE_DRAWABLE); - - if (!(isState(SHARED_GEOM))) - { - mGeomIndex = mDrawPoolp->unReserveGeom(mGeomIndex, mGeomCount); - mIndicesIndex = mDrawPoolp->unReserveInd(mIndicesIndex, mIndicesCount); - } + mGeomCount = num_vertices; + mIndicesCount = num_indices; } //============================================================================ @@ -347,55 +248,22 @@ S32 LLFace::getGeometryAvatar( LLStrider<LLVector4> &clothing_weights) { LLMemType mt1(LLMemType::MTYPE_DRAWABLE); - - if (mGeomCount <= 0) - { - return -1; - } - - if (isState(BACKLIST)) - { - if (!mBackupMem) - { - llerrs << "No backup memory for backlist" << llendl; - } - - vertices = (LLVector3*)(mBackupMem + (4 * mIndicesCount) + mDrawPoolp->mDataOffsets[LLDrawPool::DATA_VERTICES]); - normals = (LLVector3*)(mBackupMem + (4 * mIndicesCount) + mDrawPoolp->mDataOffsets[LLDrawPool::DATA_NORMALS]); - binormals = (LLVector3*)(mBackupMem + (4 * mIndicesCount) + mDrawPoolp->mDataOffsets[LLDrawPool::DATA_BINORMALS]); - tex_coords = (LLVector2*)(mBackupMem + (4 * mIndicesCount) + mDrawPoolp->mDataOffsets[LLDrawPool::DATA_TEX_COORDS0]); - clothing_weights = (LLVector4*)(mBackupMem + (4 * mIndicesCount) + mDrawPoolp->mDataOffsets[LLDrawPool::DATA_CLOTHING_WEIGHTS]); - vertex_weights = (F32*)(mBackupMem + (4 * mIndicesCount) + (mGeomCount * mDrawPoolp->getStride())); - tex_coords.setStride( mDrawPoolp->getStride()); - vertices.setStride( mDrawPoolp->getStride()); - normals.setStride( mDrawPoolp->getStride()); - binormals.setStride( mDrawPoolp->getStride()); - clothing_weights.setStride( mDrawPoolp->getStride()); - return 0; + if (mVertexBuffer.notNull()) + { + mVertexBuffer->getVertexStrider (vertices, mGeomIndex); + mVertexBuffer->getNormalStrider (normals, mGeomIndex); + mVertexBuffer->getBinormalStrider (binormals, mGeomIndex); + mVertexBuffer->getTexCoordStrider (tex_coords, mGeomIndex); + mVertexBuffer->getWeightStrider(vertex_weights, mGeomIndex); + mVertexBuffer->getClothWeightStrider(clothing_weights, mGeomIndex); } else { - if (!reserveIfNeeded()) - { - return -1; - } - - llassert(mGeomIndex >= 0); - llassert(mIndicesIndex >= 0); - - mDrawPoolp->getVertexStrider (vertices, mGeomIndex); - mDrawPoolp->getNormalStrider (normals, mGeomIndex); - mDrawPoolp->getBinormalStrider (binormals, mGeomIndex); - mDrawPoolp->getTexCoordStrider (tex_coords, mGeomIndex); - mDrawPoolp->getVertexWeightStrider(vertex_weights, mGeomIndex); - mDrawPoolp->getClothingWeightStrider(clothing_weights, mGeomIndex); - - mDrawPoolp->setDirty(); - - llassert(mGeomIndex >= 0); - return mGeomIndex; + mGeomIndex = -1; } + + return mGeomIndex; } S32 LLFace::getGeometryTerrain( @@ -404,64 +272,29 @@ S32 LLFace::getGeometryTerrain( LLStrider<LLColor4U> &colors, LLStrider<LLVector2> &texcoords0, LLStrider<LLVector2> &texcoords1, - U32 *&indicesp) + LLStrider<U32> &indicesp) { LLMemType mt1(LLMemType::MTYPE_DRAWABLE); - if (mGeomCount <= 0) + if (mVertexBuffer.notNull()) { - return -1; - } - - if (isState(BACKLIST)) - { - if (!mBackupMem) - { - printDebugInfo(); - llerrs << "No backup memory for face" << llendl; - } - vertices = (LLVector3*)(mBackupMem + (4 * mIndicesCount) + mDrawPoolp->mDataOffsets[LLDrawPool::DATA_VERTICES]); - normals = (LLVector3*)(mBackupMem + (4 * mIndicesCount) + mDrawPoolp->mDataOffsets[LLDrawPool::DATA_NORMALS]); - colors = (LLColor4U*)(mBackupMem + (4 * mIndicesCount) + mDrawPoolp->mDataOffsets[LLDrawPool::DATA_COLORS]); - texcoords0= (LLVector2*)(mBackupMem + (4 * mIndicesCount) + mDrawPoolp->mDataOffsets[LLDrawPool::DATA_TEX_COORDS0]); - texcoords1= (LLVector2*)(mBackupMem + (4 * mIndicesCount) + mDrawPoolp->mDataOffsets[LLDrawPool::DATA_TEX_COORDS1]); - texcoords0.setStride(mDrawPoolp->getStride()); - texcoords1.setStride(mDrawPoolp->getStride()); - vertices.setStride( mDrawPoolp->getStride()); - normals.setStride( mDrawPoolp->getStride()); - colors.setStride( mDrawPoolp->getStride()); - indicesp = (U32*)mBackupMem; - - return 0; + mVertexBuffer->getVertexStrider(vertices, mGeomIndex); + mVertexBuffer->getNormalStrider(normals, mGeomIndex); + mVertexBuffer->getColorStrider(colors, mGeomIndex); + mVertexBuffer->getTexCoordStrider(texcoords0, mGeomIndex); + mVertexBuffer->getTexCoord2Strider(texcoords1, mGeomIndex); + mVertexBuffer->getIndexStrider(indicesp, mIndicesIndex); } else { - if (!reserveIfNeeded()) - { - llinfos << "Get geometry failed!" << llendl; - return -1; - } - - llassert(mGeomIndex >= 0); - llassert(mIndicesIndex >= 0); - - mDrawPoolp->getVertexStrider(vertices, mGeomIndex); - mDrawPoolp->getNormalStrider(normals, mGeomIndex); - mDrawPoolp->getColorStrider(colors, mGeomIndex); - mDrawPoolp->getTexCoordStrider(texcoords0, mGeomIndex, 0); - mDrawPoolp->getTexCoordStrider(texcoords1, mGeomIndex, 1); - - indicesp = mDrawPoolp->getIndices(mIndicesIndex); - - mDrawPoolp->setDirty(); - - llassert(mGeomIndex >= 0); - return mGeomIndex; + mGeomIndex = -1; } + + return mGeomIndex; } S32 LLFace::getGeometry(LLStrider<LLVector3> &vertices, LLStrider<LLVector3> &normals, - LLStrider<LLVector2> &tex_coords, U32 *&indicesp) + LLStrider<LLVector2> &tex_coords, LLStrider<U32> &indicesp) { LLMemType mt1(LLMemType::MTYPE_DRAWABLE); @@ -470,55 +303,31 @@ S32 LLFace::getGeometry(LLStrider<LLVector3> &vertices, LLStrider<LLVector3> &no return -1; } - if (isState(BACKLIST)) + if (mVertexBuffer.notNull()) { - if (!mBackupMem) + mVertexBuffer->getVertexStrider(vertices, mGeomIndex); + if (mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_NORMAL)) + { + mVertexBuffer->getNormalStrider(normals, mGeomIndex); + } + if (mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD)) { - printDebugInfo(); - llerrs << "No backup memory for face" << llendl; + mVertexBuffer->getTexCoordStrider(tex_coords, mGeomIndex); } - vertices = (LLVector3*)(mBackupMem + (4 * mIndicesCount) + mDrawPoolp->mDataOffsets[LLDrawPool::DATA_VERTICES]); - normals = (LLVector3*)(mBackupMem + (4 * mIndicesCount) + mDrawPoolp->mDataOffsets[LLDrawPool::DATA_NORMALS]); - tex_coords= (LLVector2*)(mBackupMem + (4 * mIndicesCount) + mDrawPoolp->mDataOffsets[LLDrawPool::DATA_TEX_COORDS0]); - tex_coords.setStride(mDrawPoolp->getStride()); - vertices.setStride( mDrawPoolp->getStride()); - normals.setStride( mDrawPoolp->getStride()); - indicesp = (U32*)mBackupMem; - return 0; + mVertexBuffer->getIndexStrider(indicesp, mIndicesIndex); } else { - if (!reserveIfNeeded()) - { - return -1; - } - - llassert(mGeomIndex >= 0); - llassert(mIndicesIndex >= 0); - - mDrawPoolp->getVertexStrider(vertices, mGeomIndex); - if (mDrawPoolp->mDataMaskIL & LLDrawPool::DATA_NORMALS_MASK) - { - mDrawPoolp->getNormalStrider(normals, mGeomIndex); - } - if (mDrawPoolp->mDataMaskIL & LLDrawPool::DATA_TEX_COORDS0_MASK) - { - mDrawPoolp->getTexCoordStrider(tex_coords, mGeomIndex); - } - - indicesp =mDrawPoolp->getIndices (mIndicesIndex); - - mDrawPoolp->setDirty(); - - llassert(mGeomIndex >= 0); - return mGeomIndex; + mGeomIndex = -1; } + + return mGeomIndex; } S32 LLFace::getGeometryColors(LLStrider<LLVector3> &vertices, LLStrider<LLVector3> &normals, LLStrider<LLVector2> &tex_coords, LLStrider<LLColor4U> &colors, - U32 *&indicesp) + LLStrider<U32> &indicesp) { S32 res = getGeometry(vertices, normals, tex_coords, indicesp); if (res >= 0) @@ -528,95 +337,25 @@ S32 LLFace::getGeometryColors(LLStrider<LLVector3> &vertices, LLStrider<LLVector return res; } -S32 LLFace::getGeometryMultiTexture( - LLStrider<LLVector3> &vertices, - LLStrider<LLVector3> &normals, - LLStrider<LLVector3> &binormals, - LLStrider<LLVector2> &tex_coords0, - LLStrider<LLVector2> &tex_coords1, - U32 *&indicesp) +void LLFace::updateCenterAgent() { - LLMemType mt1(LLMemType::MTYPE_DRAWABLE); - - if (mGeomCount <= 0) - { - return -1; - } - - if (isState(BACKLIST)) + if (mDrawablep->isActive()) { - if (!mBackupMem) - { - printDebugInfo(); - llerrs << "No backup memory for face" << llendl; - } - vertices = (LLVector3*)(mBackupMem + (4 * mIndicesCount) + mDrawPoolp->mDataOffsets[LLDrawPool::DATA_VERTICES]); - normals = (LLVector3*)(mBackupMem + (4 * mIndicesCount) + mDrawPoolp->mDataOffsets[LLDrawPool::DATA_NORMALS]); - tex_coords0 = (LLVector2*)(mBackupMem + (4 * mIndicesCount) + mDrawPoolp->mDataOffsets[LLDrawPool::DATA_TEX_COORDS0]); - tex_coords0.setStride( mDrawPoolp->getStride() ); - vertices.setStride( mDrawPoolp->getStride() ); - normals.setStride( mDrawPoolp->getStride() ); - if (mDrawPoolp->mDataMaskIL & LLDrawPool::DATA_BINORMALS_MASK) - { - binormals = (LLVector3*)(mBackupMem + (4 * mIndicesCount) + mDrawPoolp->mDataOffsets[LLDrawPool::DATA_BINORMALS]); - binormals.setStride( mDrawPoolp->getStride() ); - } - if (mDrawPoolp->mDataMaskIL & LLDrawPool::DATA_TEX_COORDS1_MASK) - { - tex_coords1 = (LLVector2*)(mBackupMem + (4 * mIndicesCount) + mDrawPoolp->mDataOffsets[LLDrawPool::DATA_TEX_COORDS1]); - tex_coords1.setStride( mDrawPoolp->getStride() ); - } - indicesp = (U32*)mBackupMem; - - return 0; + mCenterAgent = mCenterLocal * getRenderMatrix(); } else { - if (!reserveIfNeeded()) - { - return -1; - } - - llassert(mGeomIndex >= 0); - llassert(mIndicesIndex >= 0); - - mDrawPoolp->getVertexStrider(vertices, mGeomIndex); - if (mDrawPoolp->mDataMaskIL & LLDrawPool::DATA_NORMALS_MASK) - { - mDrawPoolp->getNormalStrider(normals, mGeomIndex); - } - if (mDrawPoolp->mDataMaskIL & LLDrawPool::DATA_TEX_COORDS0_MASK) - { - mDrawPoolp->getTexCoordStrider(tex_coords0, mGeomIndex); - } - if (mDrawPoolp->mDataMaskIL & LLDrawPool::DATA_BINORMALS_MASK) - { - mDrawPoolp->getBinormalStrider(binormals, mGeomIndex); - } - if (mDrawPoolp->mDataMaskIL & LLDrawPool::DATA_TEX_COORDS1_MASK) - { - mDrawPoolp->getTexCoordStrider(tex_coords1, mGeomIndex, 1); - } - indicesp = mDrawPoolp->getIndices(mIndicesIndex); - - mDrawPoolp->setDirty(); - - llassert(mGeomIndex >= 0); - return mGeomIndex; + mCenterAgent = mCenterLocal; } } -void LLFace::updateCenterAgent() +void LLFace::renderForSelect(U32 data_mask) { - mCenterAgent = mCenterLocal * getRenderMatrix(); -} - -void LLFace::renderForSelect() const -{ - if(mGeomIndex < 0 || mDrawablep.isNull()) + if(mGeomIndex < 0 || mDrawablep.isNull() || mVertexBuffer.isNull()) { return; } + if (mVObjp->mGLName) { S32 name = mVObjp->mGLName; @@ -630,47 +369,25 @@ void LLFace::renderForSelect() const #endif glColor4ubv(color.mV); - if (mVObjp->getPCode() == LL_PCODE_VOLUME) + if (!getPool()) { - LLVOVolume *volp; - volp = (LLVOVolume *)(LLViewerObject*)mVObjp; - if (volp->getNumFaces() == 1 && !volp->getVolumeChanged()) + switch (getPoolType()) { - // We need to special case the coalesced face model. - S32 num_vfs = volp->getVolume()->getNumFaces(); - S32 offset = 0; - S32 i; - - for (i = 0; i < num_vfs; i++) - { - if (gPickFaces) - { - // mask off high 4 bits (16 total possible faces) - color.mV[0] &= 0x0f; - color.mV[0] |= (i & 0x0f) << 4; - glColor4ubv(color.mV); - } - S32 count = volp->getVolume()->getVolumeFace(i).mIndices.size(); - if (isState(GLOBAL)) - { - glDrawElements(mPrimType, count, GL_UNSIGNED_INT, getRawIndices() + offset); - } - else - { - glPushMatrix(); - glMultMatrixf((float*)getRenderMatrix().mMatrix); - glDrawElements(mPrimType, count, GL_UNSIGNED_INT, getRawIndices() + offset); - glPopMatrix(); - } - offset += count; - } - // We're done, return. - return; + case LLDrawPool::POOL_ALPHA: + getTexture()->bind(); + break; + default: + LLImageGL::unbindTexture(0); + break; } - - // We don't have coalesced faces, do this the normal way. } + mVertexBuffer->setBuffer(data_mask); +#if !LL_RELEASE_FOR_DOWNLOAD + LLGLState::checkClientArrays(data_mask); +#endif + U32* indicesp = (U32*) mVertexBuffer->getIndicesPointer() + mIndicesIndex; + if (gPickFaces && mTEOffset != -1) { // mask off high 4 bits (16 total possible faces) @@ -683,13 +400,13 @@ void LLFace::renderForSelect() const { if (isState(GLOBAL)) { - glDrawElements(mPrimType, mIndicesCount, GL_UNSIGNED_INT, getRawIndices()); + glDrawElements(GL_TRIANGLES, mIndicesCount, GL_UNSIGNED_INT, indicesp); } else { glPushMatrix(); glMultMatrixf((float*)getRenderMatrix().mMatrix); - glDrawElements(mPrimType, mIndicesCount, GL_UNSIGNED_INT, getRawIndices()); + glDrawElements(GL_TRIANGLES, mIndicesCount, GL_UNSIGNED_INT, indicesp); glPopMatrix(); } } @@ -697,13 +414,13 @@ void LLFace::renderForSelect() const { if (isState(GLOBAL)) { - glDrawArrays(mPrimType, mGeomIndex, mGeomCount); + glDrawArrays(GL_TRIANGLES, mGeomIndex, mGeomCount); } else { glPushMatrix(); glMultMatrixf((float*)getRenderMatrix().mMatrix); - glDrawArrays(mPrimType, mGeomIndex, mGeomCount); + glDrawArrays(GL_TRIANGLES, mGeomIndex, mGeomCount); glPopMatrix(); } } @@ -712,11 +429,12 @@ void LLFace::renderForSelect() const void LLFace::renderSelected(LLImageGL *imagep, const LLColor4& color, const S32 offset, const S32 count) { - if(mGeomIndex < 0 || mDrawablep.isNull()) + if(mGeomIndex < 0 || mDrawablep.isNull() || mVertexBuffer.isNull()) { return; } - if (mGeomCount > 0) + + if (mGeomCount > 0 && mIndicesCount > 0) { LLGLSPipelineAlpha gls_pipeline_alpha; glColor4fv(color.mV); @@ -729,110 +447,27 @@ void LLFace::renderSelected(LLImageGL *imagep, const LLColor4& color, const S32 glMultMatrixf((float*)getRenderMatrix().mMatrix); } - if (sSafeRenderSelect) - { - glBegin(mPrimType); - if (count) - { - for (S32 i = offset; i < offset + count; i++) - { - LLVector2 tc = mDrawPoolp->getTexCoord(mDrawPoolp->getIndex(getIndicesStart() + i), 0); - glTexCoord2fv(tc.mV); - LLVector3 normal = mDrawPoolp->getNormal(mDrawPoolp->getIndex(getIndicesStart() + i)); - glNormal3fv(normal.mV); - LLVector3 vertex = mDrawPoolp->getVertex(mDrawPoolp->getIndex(getIndicesStart() + i)); - glVertex3fv(vertex.mV); - } - } - else - { - for (U32 i = 0; i < getIndicesCount(); i++) - { - LLVector2 tc = mDrawPoolp->getTexCoord(mDrawPoolp->getIndex(getIndicesStart() + i), 0); - glTexCoord2fv(tc.mV); - LLVector3 normal = mDrawPoolp->getNormal(mDrawPoolp->getIndex(getIndicesStart() + i)); - glNormal3fv(normal.mV); - LLVector3 vertex = mDrawPoolp->getVertex(mDrawPoolp->getIndex(getIndicesStart() + i)); - glVertex3fv(vertex.mV); - } - } - glEnd(); - - if( gSavedSettings.getBOOL("ShowTangentBasis") ) - { - S32 start; - S32 end; - if (count) - { - start = offset; - end = offset + count; - } - else - { - start = 0; - end = getIndicesCount(); - } + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_NORMAL_ARRAY); - LLGLSNoTexture gls_no_texture; - glColor4f(1, 1, 1, 1); - glBegin(GL_LINES); - for (S32 i = start; i < end; i++) - { - LLVector3 vertex = mDrawPoolp->getVertex(mDrawPoolp->getIndex(getIndicesStart() + i)); - glVertex3fv(vertex.mV); - LLVector3 normal = mDrawPoolp->getNormal(mDrawPoolp->getIndex(getIndicesStart() + i)); - glVertex3fv( (vertex + normal * 0.1f).mV ); - } - glEnd(); + mVertexBuffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD); +#if !LL_RELEASE_FOR_DOWNLOAD + LLGLState::checkClientArrays(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD); +#endif + U32* indicesp = ((U32*) mVertexBuffer->getIndicesPointer()) + mIndicesIndex; - if (mDrawPoolp->mDataMaskIL & LLDrawPool::DATA_BINORMALS_MASK) - { - glColor4f(0, 1, 0, 1); - glBegin(GL_LINES); - for (S32 i = start; i < end; i++) - { - LLVector3 vertex = mDrawPoolp->getVertex(mDrawPoolp->getIndex(getIndicesStart() + i)); - glVertex3fv(vertex.mV); - LLVector3 binormal = mDrawPoolp->getBinormal(mDrawPoolp->getIndex(getIndicesStart() + i)); - glVertex3fv( (vertex + binormal * 0.1f).mV ); - } - glEnd(); - } - } + if (count) + { + glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, indicesp + offset); } else { - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_NORMAL_ARRAY); - if (count) - { - if (mIndicesCount > 0) - { - glDrawElements(mPrimType, count, GL_UNSIGNED_INT, getRawIndices() + offset); - } - else - { - llerrs << "Rendering non-indexed volume face!" << llendl; - glDrawArrays(mPrimType, mGeomIndex, mGeomCount); - } - } - else - { - if (mIndicesCount > 0) - { - glDrawElements(mPrimType, mIndicesCount, GL_UNSIGNED_INT, getRawIndices()); - } - else - { - glDrawArrays(mPrimType, mGeomIndex, mGeomCount); - } - } - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); + glDrawElements(GL_TRIANGLES, mIndicesCount, GL_UNSIGNED_INT, indicesp); } - + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); + if (!isState(GLOBAL)) { // Restore the tranform for non-global objects @@ -843,6 +478,7 @@ void LLFace::renderSelected(LLImageGL *imagep, const LLColor4& color, const S32 void LLFace::renderSelectedUV(const S32 offset, const S32 count) { +#if 0 LLUUID uv_img_red_blue_id(gViewerArt.getString("uv_test1.tga")); LLUUID uv_img_green_id(gViewerArt.getString("uv_test2.tga")); LLViewerImage* red_blue_imagep = gImageList.getImage(uv_img_red_blue_id, TRUE, TRUE); @@ -892,7 +528,7 @@ void LLFace::renderSelectedUV(const S32 offset, const S32 count) glPolygonOffset(factor, bias); if (sSafeRenderSelect) { - glBegin(mPrimType); + glBegin(GL_TRIANGLES); if (count) { for (S32 i = offset; i < offset + count; i++) @@ -924,7 +560,7 @@ void LLFace::renderSelectedUV(const S32 offset, const S32 count) { if (mIndicesCount > 0) { - glDrawElements(mPrimType, count, GL_UNSIGNED_INT, getRawIndices() + offset); + glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, getRawIndices() + offset); } else { @@ -936,15 +572,14 @@ void LLFace::renderSelectedUV(const S32 offset, const S32 count) { if (mIndicesCount > 0) { - glDrawElements(mPrimType, mIndicesCount, GL_UNSIGNED_INT, getRawIndices()); + glDrawElements(GL_TRIANGLES, mIndicesCount, GL_UNSIGNED_INT, getRawIndices()); } else { - glDrawArrays(mPrimType, mGeomIndex, mGeomCount); + glDrawArrays(GL_TRIANGLES, mGeomIndex, mGeomCount); } } glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); } glDisable(GL_POLYGON_OFFSET_FILL); @@ -965,12 +600,13 @@ void LLFace::renderSelectedUV(const S32 offset, const S32 count) //restore blend func glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +#endif } void LLFace::printDebugInfo() const { - LLDrawPool *poolp = getPool(); + LLFacePool *poolp = getPool(); llinfos << "Object: " << getViewerObject()->mID << llendl; if (getDrawable()) { @@ -986,10 +622,6 @@ void LLFace::printDebugInfo() const } llinfos << "Face: " << this << llendl; - if (isState(BACKLIST)) - { - llinfos << "Backlisted!" << llendl; - } llinfos << "State: " << getState() << llendl; llinfos << "Geom Index Data:" << llendl; llinfos << "--------------------" << llendl; @@ -1018,7 +650,7 @@ void LLFace::printDebugInfo() const llinfos << "Incorrect number of pool references!" << llendl; } - +#if 0 llinfos << "Indices:" << llendl; llinfos << "--------------------" << llendl; @@ -1039,149 +671,7 @@ void LLFace::printDebugInfo() const llinfos << mGeomIndex + i << ":" << poolp->getVertex(mGeomIndex + i) << llendl; } llinfos << llendl; -} - -S32 LLFace::backup() -{ - LLMemType mt1(LLMemType::MTYPE_DRAWABLE); - - if (isState(BACKLIST)) - { - llwarns << "Face is already backed up in LLFace::backup!" << llendl; - return mGeomCount; - } - if (mGeomIndex < 0) - { - // flexible objects can cause this - //llwarns << "No geometry to back-up" << llendl; - return 0; - } - - S32 size = 0; - if (!mBackupMem) - { - size = allocBackupMem(); - } - else - { - llerrs << "Memory already backed up!" << llendl; - } - - // Need to flag this, because we can allocate a non-zero backup mem if we have indices and no geometry. - - if (mGeomCount || mIndicesCount) - { - setState(BACKLIST); -#if !RELEASE_FOR_DOWNLOAD - if (mGeomIndex < 0 || mIndicesIndex < 0) - { - llerrs << "LLFace::backup" << llendl; - } #endif - - U32 *backup = (U32*)mBackupMem; - S32 stride = mDrawPoolp->getStride(); - - U32 *index = mDrawPoolp->getIndices(mIndicesIndex); - for (U32 i=0;i<mIndicesCount;i++) - { - *backup++ = index[i] - mGeomIndex; - index[i] = 0; - } - - if (!mGeomCount) - { - return mGeomCount; - } - // - // Don't change the order of these unles you change the corresponding getGeometry calls that read out of - // backup memory, and also the other of the backup/restore pair! - // - memcpy(backup, (mDrawPoolp->mMemory.getMem() + mGeomIndex * stride), mGeomCount * stride); /*Flawfinder: ignore*/ - backup += mGeomCount * stride / 4; - - if (mDrawPoolp->mDataMaskNIL & LLDrawPool::DATA_CLOTHING_WEIGHTS_MASK) - { - memcpy(backup, &mDrawPoolp->getClothingWeight(mGeomIndex), mGeomCount * sizeof(LLVector4)); /*Flawfinder: ignore*/ - backup += mGeomCount*4; - } - - if (mDrawPoolp->mDataMaskNIL & LLDrawPool::DATA_VERTEX_WEIGHTS_MASK) - { - memcpy(backup, &mDrawPoolp->getVertexWeight(mGeomIndex), mGeomCount * sizeof(F32)); /*Flawfinder: ignore*/ - backup += mGeomCount; - } - - llassert((U8*)backup - mBackupMem == size); - - unReserve(); - } - return mGeomCount; -} - -void LLFace::restore() -{ - LLMemType mt1(LLMemType::MTYPE_DRAWABLE); - - if (!isState(BACKLIST)) - { - // flexible objects can cause this -// printDebugInfo(); -// llwarns << "not backlisted for restore" << llendl; - return; - } - if (!mGeomCount || !mBackupMem) - { - if (!mBackupMem) - { - printDebugInfo(); - llwarns << "no backmem for restore" << llendl; - } - - clearState(BACKLIST); - return; - } - - S32 stride = mDrawPoolp->getStride(); - mGeomIndex = mDrawPoolp->reserveGeom(mGeomCount); - mIndicesIndex = mDrawPoolp->reserveInd (mIndicesCount); - mGeneration = mDrawPoolp->mGeneration; - - llassert(mGeomIndex >= 0); - llassert(mIndicesIndex >= 0); - - U32 *backup = (U32*)mBackupMem; - U32 *index = mDrawPoolp->getIndices(mIndicesIndex); - - for (U32 i=0;i<mIndicesCount;i++) - { - S32 ind = mGeomIndex + *backup; - index[i] = ind; - backup++; - } - - mDrawPoolp->mMemory.copyToMem(mGeomIndex * stride, (U8 *)backup, mGeomCount * stride); - backup += mGeomCount * stride / 4; - - // - // Don't change the order of these unles you change the corresponding getGeometry calls that read out of - // backup memory, and also the other of the backup/restore pair! - // - if (mDrawPoolp->mDataMaskNIL & LLDrawPool::DATA_CLOTHING_WEIGHTS_MASK) - { - mDrawPoolp->mClothingWeights.copyToMem(mGeomIndex, (U8 *)backup, mGeomCount); - backup += mGeomCount*4; - } - - if (mDrawPoolp->mDataMaskNIL & LLDrawPool::DATA_VERTEX_WEIGHTS_MASK) - { - mDrawPoolp->mWeights.copyToMem(mGeomIndex, (U8 *)backup, mGeomCount); - backup += mGeomCount; - } - - delete[] mBackupMem; - mBackupMem = NULL; - clearState(BACKLIST); } // Transform the texture coordinates for this face. @@ -1213,48 +703,197 @@ static void xform(LLVector2 &tex_coord, F32 cosAng, F32 sinAng, F32 offS, F32 of } -BOOL LLFace::genVolumeTriangles(const LLVolume &volume, S32 f, - const LLMatrix4& mat, const LLMatrix3& inv_trans_mat, BOOL global_volume) +BOOL LLFace::genVolumeBBoxes(const LLVolume &volume, S32 f, + const LLMatrix4& mat_vert, const LLMatrix3& mat_normal, BOOL global_volume) +{ + LLMemType mt1(LLMemType::MTYPE_DRAWABLE); + + const LLVolumeFace &face = volume.getVolumeFace(f); + + //get bounding box + if (mDrawablep->isState(LLDrawable::REBUILD_ALL)) + { + //vertex buffer no longer valid + mVertexBuffer = NULL; + mLastVertexBuffer = NULL; + + LLVector3 min,max; + + min = face.mExtents[0]; + max = face.mExtents[1]; + + //min, max are in volume space, convert to drawable render space + LLVector3 center = ((min + max) * 0.5f)*mat_vert; + LLVector3 size = ((max-min) * 0.5f); + if (!global_volume) + { + size.scaleVec(mDrawablep->getVObj()->getScale()); + } + LLQuaternion rotation = LLQuaternion(mat_normal); + + LLVector3 v[4]; + //get 4 corners of bounding box + v[0] = (size * rotation); + v[1] = (LLVector3(-size.mV[0], -size.mV[1], size.mV[2]) * rotation); + v[2] = (LLVector3(size.mV[0], -size.mV[1], -size.mV[2]) * rotation); + v[3] = (LLVector3(-size.mV[0], size.mV[1], -size.mV[2]) * rotation); + + LLVector3& newMin = mExtents[0]; + LLVector3& newMax = mExtents[1]; + + newMin = newMax = center; + + for (U32 i = 0; i < 4; i++) + { + for (U32 j = 0; j < 3; j++) + { + F32 delta = fabsf(v[i].mV[j]); + F32 min = center.mV[j] - delta; + F32 max = center.mV[j] + delta; + + if (min < newMin.mV[j]) + { + newMin.mV[j] = min; + } + + if (max > newMax.mV[j]) + { + newMax.mV[j] = max; + } + } + } + + mCenterLocal = (newMin+newMax)*0.5f; + updateCenterAgent(); + } + + return TRUE; +} + + +BOOL LLFace::getGeometryVolume(const LLVolume& volume, + S32 f, + LLStrider<LLVector3>& vertices, + LLStrider<LLVector3>& normals, + LLStrider<LLVector2>& tex_coords, + LLStrider<LLVector2>& tex_coords2, + LLStrider<LLColor4U>& colors, + LLStrider<U32>& indicesp, + const LLMatrix4& mat_vert, const LLMatrix3& mat_normal, + U32& index_offset) { const LLVolumeFace &vf = volume.getVolumeFace(f); S32 num_vertices = (S32)vf.mVertices.size(); S32 num_indices = (S32)vf.mIndices.size(); - setSize(num_vertices, num_indices); - return genVolumeTriangles(volume, f, f, mat, inv_trans_mat, global_volume); -} + LLStrider<LLVector3> old_verts; + LLStrider<LLVector2> old_texcoords; + LLStrider<LLVector2> old_texcoords2; + LLStrider<LLVector3> old_normals; + LLStrider<LLColor4U> old_colors; -BOOL LLFace::genVolumeTriangles(const LLVolume &volume, S32 fstart, S32 fend, - const LLMatrix4& mat_vert, const LLMatrix3& mat_normal, const BOOL global_volume) -{ - LLMemType mt1(LLMemType::MTYPE_DRAWABLE); + BOOL full_rebuild = mDrawablep->isState(LLDrawable::REBUILD_VOLUME); + BOOL moved = TRUE; - if (!mDrawablep) + BOOL global_volume = mDrawablep->getVOVolume()->isVolumeGlobal(); + LLVector3 scale; + if (global_volume) { - return TRUE; + scale.setVec(1,1,1); + } + else + { + scale = mVObjp->getScale(); } - S32 index_offset; - F32 r, os, ot, ms, mt, cos_ang, sin_ang; - LLStrider<LLVector3> vertices; - LLStrider<LLVector3> normals; - LLStrider<LLVector3> binormals; - LLStrider<LLVector2> tex_coords; - LLStrider<LLVector2> tex_coords2; - U32 *indicesp = NULL; + if (!full_rebuild) + { + if (mLastVertexBuffer == mVertexBuffer && + !mVertexBuffer->isEmpty()) + { //this face really doesn't need to be regenerated, try real hard not to do so + if (mLastGeomCount == mGeomCount && + mLastGeomIndex == mGeomIndex && + mLastIndicesCount == mIndicesCount && + mLastIndicesIndex == mIndicesIndex) + { //data is in same location in vertex buffer + moved = FALSE; + } - BOOL bump = mDrawPoolp && (mDrawPoolp->mDataMaskIL & LLDrawPool::DATA_BINORMALS_MASK); - BOOL is_static = mDrawablep->isStatic(); - BOOL is_global = is_static; - - if (bump) - { - index_offset = getGeometryMultiTexture(vertices, normals, binormals, tex_coords, tex_coords2, indicesp); + if (!moved && !mDrawablep->isState(LLDrawable::REBUILD_ALL)) + { //nothing needs to be done + vertices += mGeomCount; + normals += mGeomCount; + tex_coords += mGeomCount; + colors += mGeomCount; + tex_coords2 += mGeomCount; + index_offset += mGeomCount; + indicesp += mIndicesCount; + return FALSE; + } + + if (mLastGeomCount == mGeomCount) + { + if (mLastGeomIndex >= mGeomIndex && + mLastGeomIndex + mGeomCount+1 < mVertexBuffer->getNumVerts()) + { + //copy from further down the buffer + mVertexBuffer->getVertexStrider(old_verts, mLastGeomIndex); + mVertexBuffer->getTexCoordStrider(old_texcoords, mLastGeomIndex); + mVertexBuffer->getTexCoord2Strider(old_texcoords2, mLastGeomIndex); + mVertexBuffer->getNormalStrider(old_normals, mLastGeomIndex); + mVertexBuffer->getColorStrider(old_colors, mLastGeomIndex); + + if (!mDrawablep->isState(LLDrawable::REBUILD_ALL)) + { + //quick copy + for (S32 i = 0; i < mGeomCount; i++) + { + *vertices++ = *old_verts++; + *tex_coords++ = *old_texcoords++; + *tex_coords2++ = *old_texcoords2++; + *colors++ = *old_colors++; + *normals++ = *old_normals++; + } + + for (U32 i = 0; i < mIndicesCount; i++) + { + *indicesp++ = vf.mIndices[i] + index_offset; + } + + index_offset += mGeomCount; + mLastGeomIndex = mGeomIndex; + mLastIndicesCount = mIndicesCount; + mLastIndicesIndex = mIndicesIndex; + + return TRUE; + } + } + else + { + full_rebuild = TRUE; + } + } + } + else + { + full_rebuild = TRUE; + } } else { - index_offset = getGeometry(vertices, normals, tex_coords, indicesp); + mLastUpdateTime = gFrameTimeSeconds; } + + + BOOL rebuild_pos = full_rebuild || mDrawablep->isState(LLDrawable::REBUILD_POSITION); + BOOL rebuild_color = full_rebuild || mDrawablep->isState(LLDrawable::REBUILD_COLOR); + BOOL rebuild_tcoord = full_rebuild || mDrawablep->isState(LLDrawable::REBUILD_TCOORD); + + F32 r = 0, os = 0, ot = 0, ms = 0, mt = 0, cos_ang = 0, sin_ang = 0; + + BOOL is_static = mDrawablep->isStatic(); + BOOL is_global = is_static; + if (-1 == index_offset) { return TRUE; @@ -1262,16 +901,6 @@ BOOL LLFace::genVolumeTriangles(const LLVolume &volume, S32 fstart, S32 fend, LLVector3 center_sum(0.f, 0.f, 0.f); - LLVector3 render_pos; - - if (mDrawablep->isState(LLDrawable::REBUILD_TCOORD) && - global_volume) - { - render_pos = mVObjp->getRenderPosition(); - } - - setPrimType(LLTriangles); - if (is_global) { setState(GLOBAL); @@ -1280,26 +909,16 @@ BOOL LLFace::genVolumeTriangles(const LLVolume &volume, S32 fstart, S32 fend, { clearState(GLOBAL); } - - LLVector3 min, max; + LLVector2 tmin, tmax; - BOOL grab_first_vert = TRUE; - BOOL grab_first_tcoord = TRUE; - - for (S32 vol_face = fstart; vol_face <= fend; vol_face++) + const LLTextureEntry *tep = mVObjp->getTE(f); + U8 bump_code = tep ? bump_code = tep->getBumpmap() : 0; + + if (rebuild_tcoord) { - const LLVolumeFace &vf = volume.getVolumeFace(vol_face); - S32 num_vertices = (S32)vf.mVertices.size(); - S32 num_indices = (S32)vf.mIndices.size(); - llassert(num_indices > 0); - - U8 bump_code; - const LLTextureEntry *tep = mVObjp->getTE(vol_face); - if (tep) { - bump_code = tep->getBumpmap(); r = tep->getRotation(); os = tep->mOffsetS; ot = tep->mOffsetT; @@ -1310,7 +929,6 @@ BOOL LLFace::genVolumeTriangles(const LLVolume &volume, S32 fstart, S32 fend, } else { - bump_code = 0; cos_ang = 1.0f; sin_ang = 0.0f; os = 0.0f; @@ -1318,209 +936,228 @@ BOOL LLFace::genVolumeTriangles(const LLVolume &volume, S32 fstart, S32 fend, ms = 1.0f; mt = 1.0f; } + } - if (mDrawablep->isState(LLDrawable::REBUILD_VOLUME)) + if (isState(TEXTURE_ANIM)) + { + LLVOVolume* vobj = (LLVOVolume*) (LLViewerObject*) mVObjp; + U8 mode = vobj->mTexAnimMode; + if (mode & LLViewerTextureAnim::TRANSLATE) { - // VERTICES & NORMALS - for (S32 i = 0; i < num_vertices; i++) - { - LLVector3 v; - v = vf.mVertices[i].mPosition * mat_vert; + os = ot = 0.f; + } + if (mode & LLViewerTextureAnim::ROTATE) + { + r = 0.f; + cos_ang = 1.f; + sin_ang = 0.f; + } + if (mode & LLViewerTextureAnim::SCALE) + { + ms = mt = 1.f; + } + } - LLVector3 normal = vf.mVertices[i].mNormal * mat_normal; - normal.normVec(); - *normals++ = normal; - - *vertices++ = v; - - if (grab_first_vert) - { - grab_first_vert = FALSE; - min = max = v; - } - else - { - for (U32 j = 0; j < 3; j++) - { - if (v.mV[j] < min.mV[j]) - { - min.mV[j] = v.mV[j]; - } - if (v.mV[j] > max.mV[j]) - { - max.mV[j] = v.mV[j]; - } - } - } + LLColor4U color = tep->getColor(); + + if (rebuild_color) + { + GLfloat alpha[4] = + { + 0.00f, + 0.25f, + 0.5f, + 0.75f + }; + + if (gPipeline.getPoolTypeFromTE(tep, getTexture()) == LLDrawPool::POOL_BUMP) + { + color.mV[3] = U8 (alpha[tep->getShiny()] * 255); + } + } + + // INDICES + if (full_rebuild || moved) + { + for (S32 i = 0; i < num_indices; i++) + { + *indicesp++ = vf.mIndices[i] + index_offset; + } + } + else + { + indicesp += num_indices; + } + + //bump setup + LLVector3 binormal_dir( -sin_ang, cos_ang, 0 ); + LLVector3 bump_s_primary_light_ray; + LLVector3 bump_t_primary_light_ray; + + if (bump_code) + { + F32 offset_multiple; + switch( bump_code ) + { + case BE_NO_BUMP: + offset_multiple = 0.f; + break; + case BE_BRIGHTNESS: + case BE_DARKNESS: + if( mTexture.notNull() && mTexture->getHasGLTexture()) + { + // Offset by approximately one texel + S32 cur_discard = mTexture->getDiscardLevel(); + S32 max_size = llmax( mTexture->getWidth(), mTexture->getHeight() ); + max_size <<= cur_discard; + const F32 ARTIFICIAL_OFFSET = 2.f; + offset_multiple = ARTIFICIAL_OFFSET / (F32)max_size; } - for (S32 i = 0; i < num_indices; i++) + else { - S32 index = vf.mIndices[i] + index_offset; - llassert(index >= 0 && (i != 1 || *(indicesp-1)!=(U32)index)); - *indicesp++ = index; + offset_multiple = 1.f/256; } + break; + + default: // Standard bumpmap textures. Assumed to be 256x256 + offset_multiple = 1.f / 256; + break; } - if ((mDrawablep->isState(LLDrawable::REBUILD_TCOORD)) || - ((bump || getTextureEntry()->getTexGen() != 0) && mDrawablep->isState(LLDrawable::REBUILD_VOLUME))) + F32 s_scale = 1.f; + F32 t_scale = 1.f; + if( tep ) { - // TEX COORDS AND BINORMALS - LLVector3 binormal_dir( -sin_ang, cos_ang, 0 ); - LLVector3 bump_s_primary_light_ray; - LLVector3 bump_t_primary_light_ray; - if (bump) - { - F32 offset_multiple; - switch( bump_code ) - { - case BE_NO_BUMP: - offset_multiple = 0.f; - break; - case BE_BRIGHTNESS: - case BE_DARKNESS: - if( mTexture.notNull() && mTexture->getHasGLTexture()) - { - // Offset by approximately one texel - S32 cur_discard = mTexture->getDiscardLevel(); - S32 max_size = llmax( mTexture->getWidth(), mTexture->getHeight() ); - max_size <<= cur_discard; - const F32 ARTIFICIAL_OFFSET = 2.f; - offset_multiple = ARTIFICIAL_OFFSET / (F32)max_size; - } - else - { - offset_multiple = 1.f/256; - } - break; - - default: // Standard bumpmap textures. Assumed to be 256x256 - offset_multiple = 1.f / 256; - break; - } + tep->getScale( &s_scale, &t_scale ); + } + LLVector3 sun_ray = gSky.getSunDirection(); + LLVector3 moon_ray = gSky.getMoonDirection(); + LLVector3& primary_light_ray = (sun_ray.mV[VZ] > 0) ? sun_ray : moon_ray; + bump_s_primary_light_ray = offset_multiple * s_scale * primary_light_ray; + bump_t_primary_light_ray = offset_multiple * t_scale * primary_light_ray; + } + + U8 texgen = getTextureEntry()->getTexGen(); - F32 s_scale = 1.f; - F32 t_scale = 1.f; - if( tep ) - { - tep->getScale( &s_scale, &t_scale ); - } - LLVector3 sun_ray = gSky.getSunDirection(); - LLVector3 moon_ray = gSky.getMoonDirection(); - LLVector3& primary_light_ray = (sun_ray.mV[VZ] > 0) ? sun_ray : moon_ray; - bump_s_primary_light_ray = offset_multiple * s_scale * primary_light_ray; - bump_t_primary_light_ray = offset_multiple * t_scale * primary_light_ray; - } - - for (S32 i = 0; i < num_vertices; i++) + for (S32 i = 0; i < num_vertices; i++) + { + if (rebuild_tcoord) + { + LLVector2 tc = vf.mVertices[i].mTexCoord; + + if (texgen != LLTextureEntry::TEX_GEN_DEFAULT) { - LLVector2 tc = vf.mVertices[i].mTexCoord; + LLVector3 vec = vf.mVertices[i].mPosition; + + vec.scaleVec(scale); - U8 texgen = getTextureEntry()->getTexGen(); - if (texgen != LLTextureEntry::TEX_GEN_DEFAULT) + switch (texgen) { + case LLTextureEntry::TEX_GEN_PLANAR: + planarProjection(tc, vf.mVertices[i], vf.mCenter, vec); + break; + case LLTextureEntry::TEX_GEN_SPHERICAL: + sphericalProjection(tc, vf.mVertices[i], vf.mCenter, vec); + break; + case LLTextureEntry::TEX_GEN_CYLINDRICAL: + cylindricalProjection(tc, vf.mVertices[i], vf.mCenter, vec); + break; + default: + break; + } + } - LLVector3 vec = vf.mVertices[i].mPosition; //-vf.mCenter; - - if (global_volume) - { - vec -= render_pos; - } - else - { - vec.scaleVec(mVObjp->getScale()); - } - - switch (texgen) - { - case LLTextureEntry::TEX_GEN_PLANAR: - planarProjection(tc, vf.mVertices[i], vf.mCenter, vec); - break; - case LLTextureEntry::TEX_GEN_SPHERICAL: - sphericalProjection(tc, vf.mVertices[i], vf.mCenter, vec); - break; - case LLTextureEntry::TEX_GEN_CYLINDRICAL: - cylindricalProjection(tc, vf.mVertices[i], vf.mCenter, vec); - break; - default: - break; - } - } - xform(tc, cos_ang, sin_ang, os, ot, ms, mt); - *tex_coords++ = tc; - if (grab_first_tcoord) - { - grab_first_tcoord = FALSE; - tmin = tmax = tc; - } - else - { - for (U32 j = 0; j < 2; j++) - { - if (tmin.mV[j] > tc.mV[j]) - { - tmin.mV[j] = tc.mV[j]; - } - else if (tmax.mV[j] < tc.mV[j]) - { - tmax.mV[j] = tc.mV[j]; - } - } - } - if (bump) - { - LLVector3 tangent = vf.mVertices[i].mBinormal % vf.mVertices[i].mNormal; - LLMatrix3 tangent_to_object; - tangent_to_object.setRows(tangent, vf.mVertices[i].mBinormal, vf.mVertices[i].mNormal); - LLVector3 binormal = binormal_dir * tangent_to_object; + xform(tc, cos_ang, sin_ang, os, ot, ms, mt); + *tex_coords++ = tc; + + if (bump_code) + { + LLVector3 tangent = vf.mVertices[i].mBinormal % vf.mVertices[i].mNormal; + LLMatrix3 tangent_to_object; + tangent_to_object.setRows(tangent, vf.mVertices[i].mBinormal, vf.mVertices[i].mNormal); + LLVector3 binormal = binormal_dir * tangent_to_object; - if (!global_volume) - { - binormal = binormal * mat_normal; - } - binormal.normVec(); - tangent.normVec(); - - tc += LLVector2( bump_s_primary_light_ray * tangent, bump_t_primary_light_ray * binormal ); - *tex_coords2++ = tc; + binormal = binormal * mat_normal; + binormal.normVec(); - *binormals++ = binormal; - } + tc += LLVector2( bump_s_primary_light_ray * tangent, bump_t_primary_light_ray * binormal ); + *tex_coords2++ = tc; + } + } + else if (moved) + { + *tex_coords++ = *old_texcoords++; + if (bump_code) + { + *tex_coords2++ = *old_texcoords2++; } } + + if (rebuild_pos) + { + *vertices++ = vf.mVertices[i].mPosition * mat_vert; - index_offset += num_vertices; + LLVector3 normal = vf.mVertices[i].mNormal * mat_normal; + normal.normVec(); + + *normals++ = normal; + } + else if (moved) + { + *normals++ = *old_normals++; + *vertices++ = *old_verts++; + } - center_sum += vf.mCenter * mat_vert; + if (rebuild_color) + { + *colors++ = color; + } + else if (moved) + { + *colors++ = *old_colors++; + } } - - center_sum /= (F32)(fend-fstart+1); - - if (is_static) + + if (!rebuild_pos && !moved) { - mCenterAgent = center_sum; - mCenterLocal = mCenterAgent - mDrawablep->getPositionAgent(); + vertices += num_vertices; } - else + + if (!rebuild_tcoord && !moved) { - mCenterLocal = center_sum; - updateCenterAgent(); + tex_coords2 += num_vertices; + tex_coords += num_vertices; } - - if (!grab_first_vert && mDrawablep->isState(LLDrawable::REBUILD_VOLUME)) + else if (!bump_code) { - mExtents[0] = min; - mExtents[1] = max; + tex_coords2 += num_vertices; } - - if (!grab_first_tcoord && mDrawablep->isState(LLDrawable::REBUILD_TCOORD)) + + if (!rebuild_color && !moved) { - mTexExtents[0] = tmin; - mTexExtents[1] = tmax; + colors += num_vertices; } - + + if (rebuild_tcoord) + { + mTexExtents[0].setVec(0,0); + mTexExtents[1].setVec(1,1); + xform(mTexExtents[0], cos_ang, sin_ang, os, ot, ms, mt); + xform(mTexExtents[1], cos_ang, sin_ang, os, ot, ms, mt); + } + + index_offset += num_vertices; + + mLastVertexBuffer = mVertexBuffer; + mLastGeomCount = mGeomCount; + mLastGeomIndex = mGeomIndex; + mLastIndicesCount = mIndicesCount; + mLastIndicesIndex = mIndicesIndex; + return TRUE; } +#if 0 BOOL LLFace::genLighting(const LLVolume* volume, const LLDrawable* drawablep, S32 fstart, S32 fend, const LLMatrix4& mat_vert, const LLMatrix3& mat_normal, BOOL do_lighting) { @@ -1643,21 +1280,20 @@ BOOL LLFace::genShadows(const LLVolume* volume, const LLDrawable* drawablep, S32 } return TRUE; } +#endif BOOL LLFace::verify(const U32* indices_array) const { BOOL ok = TRUE; // First, check whether the face data fits within the pool's range. - if ((mGeomIndex < 0) || (mGeomIndex + mGeomCount) > (S32)getPool()->getVertexCount()) + if ((mGeomIndex < 0) || (mGeomIndex + mGeomCount) > mVertexBuffer->getNumVerts()) { ok = FALSE; llinfos << "Face not within pool range!" << llendl; } S32 indices_count = (S32)getIndicesCount(); - S32 geom_start = getGeomStart(); - S32 geom_count = mGeomCount; - + if (!indices_count) { return TRUE; @@ -1669,6 +1305,10 @@ BOOL LLFace::verify(const U32* indices_array) const llinfos << "Face has bogus indices count" << llendl; } +#if 0 + S32 geom_start = getGeomStart(); + S32 geom_count = mGeomCount; + const U32 *indicesp = indices_array ? indices_array + mIndicesIndex : getRawIndices(); for (S32 i = 0; i < indices_count; i++) @@ -1687,6 +1327,7 @@ BOOL LLFace::verify(const U32* indices_array) const ok = FALSE; } } +#endif if (!ok) { @@ -1737,7 +1378,7 @@ const LLColor4& LLFace::getRenderColor() const void LLFace::renderSetColor() const { - if (!LLDrawPool::LLOverrideFaceColor::sOverrideFaceColor) + if (!LLFacePool::LLOverrideFaceColor::sOverrideFaceColor) { const LLColor4* color = &(getRenderColor()); @@ -1754,61 +1395,21 @@ void LLFace::renderSetColor() const S32 LLFace::pushVertices(const U32* index_array) const { - U32 indices_count = mIndicesCount; - S32 ret = 0; -#if ENABLE_FACE_LINKING - LLFace* next = mNextFace; -#endif - - if (mGeomCount < gGLManager.mGLMaxVertexRange && (S32) indices_count < gGLManager.mGLMaxIndexRange) + if (mIndicesCount) { - LLFace* current = (LLFace*) this; - S32 geom_count = mGeomCount; -#if ENABLE_FACE_LINKING - while (current) + if (mGeomCount <= gGLManager.mGLMaxVertexRange && + mIndicesCount <= (U32) gGLManager.mGLMaxIndexRange) { - //chop up batch into implementation recommended sizes - while (next && - (current == next || - ((S32) (indices_count + next->mIndicesCount) < gGLManager.mGLMaxIndexRange && - geom_count + next->mGeomCount < gGLManager.mGLMaxVertexRange))) - { - indices_count += next->mIndicesCount; - geom_count += next->mGeomCount; - next = next->mNextFace; - } -#endif - if (indices_count) - { - glDrawRangeElements(mPrimType, current->mGeomIndex, current->mGeomIndex + geom_count, indices_count, - GL_UNSIGNED_INT, index_array + current->mIndicesIndex); - } - ret += (S32) indices_count; - indices_count = 0; - geom_count = 0; -#if ENABLE_FACE_LINKING - current = next; + glDrawRangeElements(GL_TRIANGLES, mGeomIndex, mGeomIndex + mGeomCount-1, mIndicesCount, + GL_UNSIGNED_INT, index_array + mIndicesIndex); } -#endif - } - else - { -#if ENABLE_FACE_LINKING - while (next) - { - indices_count += next->mIndicesCount; - next = next->mNextFace; - } -#endif - if (indices_count) + else { - glDrawElements(mPrimType, indices_count, GL_UNSIGNED_INT, index_array + mIndicesIndex); + glDrawElements(GL_TRIANGLES, mIndicesCount, GL_UNSIGNED_INT, index_array+mIndicesIndex); } - ret += (S32) indices_count; } - return ret; - + return mIndicesCount; } const LLMatrix4& LLFace::getRenderMatrix() const @@ -1835,19 +1436,25 @@ S32 LLFace::renderElements(const U32 *index_array) const return ret; } -S32 LLFace::renderIndexed(const U32 *index_array) const +S32 LLFace::renderIndexed() { - if (mSkipRender) + if(mGeomIndex < 0 || mDrawablep.isNull() || mDrawPoolp == NULL) { return 0; } + + return renderIndexed(mDrawPoolp->getVertexDataMask()); +} - if(mGeomIndex < 0 || mDrawablep.isNull()) +S32 LLFace::renderIndexed(U32 mask) +{ + if (mVertexBuffer.isNull()) { return 0; } - - renderSetColor(); + + mVertexBuffer->setBuffer(mask); + U32* index_array = (U32*) mVertexBuffer->getIndicesPointer(); return renderElements(index_array); } @@ -1860,26 +1467,13 @@ S32 LLFace::getVertices(LLStrider<LLVector3> &vertices) { return -1; } - if (isState(BACKLIST)) - { - if (!mBackupMem) - { - printDebugInfo(); - llerrs << "No backup memory for face" << llendl; - } - vertices = (LLVector3*)(mBackupMem + (4 * mIndicesCount) + mDrawPoolp->mDataOffsets[LLDrawPool::DATA_VERTICES]); - vertices.setStride( mDrawPoolp->getStride()); - return 0; - } - else + + if (mGeomIndex >= 0) // flexible objects may not have geometry { - if (mGeomIndex >= 0) // flexible objects may not have geometry - { - mDrawPoolp->getVertexStrider(vertices, mGeomIndex); - mDrawPoolp->setDirty(); - } - return mGeomIndex; + mVertexBuffer->getVertexStrider(vertices, mGeomIndex); + } + return mGeomIndex; } S32 LLFace::getColors(LLStrider<LLColor4U> &colors) @@ -1888,42 +1482,17 @@ S32 LLFace::getColors(LLStrider<LLColor4U> &colors) { return -1; } - if (isState(BACKLIST)) - { - llassert(mBackupMem); - colors = (LLColor4U*)(mBackupMem + (4 * mIndicesCount) + mDrawPoolp->mDataOffsets[LLDrawPool::DATA_COLORS]); - colors.setStride( mDrawPoolp->getStride()); - return 0; - } - else - { - llassert(mGeomIndex >= 0); - mDrawPoolp->getColorStrider(colors, mGeomIndex); - return mGeomIndex; - } -} - -S32 LLFace::getIndices(U32* &indicesp) -{ - if (isState(BACKLIST)) - { - indicesp = (U32*)mBackupMem; - return 0; - } - else - { - indicesp = mDrawPoolp->getIndices(mIndicesIndex); - llassert(mGeomIndex >= 0 && indicesp[0] != indicesp[1]); - return mGeomIndex; - } + + llassert(mGeomIndex >= 0); + mVertexBuffer->getColorStrider(colors, mGeomIndex); + return mGeomIndex; } -void LLFace::link(LLFace* facep) +S32 LLFace::getIndices(LLStrider<U32> &indicesp) { -#if ENABLE_FACE_LINKING - mNextFace = facep; - facep->mSkipRender = TRUE; -#endif + mVertexBuffer->getIndexStrider(indicesp, mIndicesIndex); + llassert(mGeomIndex >= 0 && indicesp[0] != indicesp[1]); + return mIndicesIndex; } LLVector3 LLFace::getPositionAgent() const diff --git a/indra/newview/llface.h b/indra/newview/llface.h index 0d017d6efe..18db645305 100644 --- a/indra/newview/llface.h +++ b/indra/newview/llface.h @@ -19,18 +19,19 @@ #include "llquaternion.h" #include "xform.h" #include "lldarrayptr.h" +#include "llvertexbuffer.h" +#include "llviewerimage.h" #include "llpagemem.h" #include "llstat.h" #include "lldrawable.h" -#define ENABLE_FACE_LINKING 1 // Causes problems with snapshot rendering - -class LLDrawPool; +class LLFacePool; class LLVolume; class LLViewerImage; class LLTextureEntry; class LLVertexProgram; class LLViewerImage; +class LLGeometryManager; class LLFace { @@ -38,26 +39,12 @@ public: enum EMasks { - SHARED_GEOM = 0x0001, - LIGHT = 0x0002, - REBUILD = 0x0004, - GLOBAL = 0x0008, - VISIBLE = 0x0010, - BACKLIST = 0x0020, - INTERP = 0x0040, - FULLBRIGHT = 0x0080, - HUD_RENDER = 0x0100, - USE_FACE_COLOR = 0x0200, - - POINT_SPRITE = 0x10000, - BOARD_SPRITE = 0x20000, - FIXED_SPRITE = 0x40000, - DEPTH_SPRITE = 0x80000 - }; - - enum EDirty - { - DIRTY = -2 + LIGHT = 0x0001, + GLOBAL = 0x0002, + FULLBRIGHT = 0x0004, + HUD_RENDER = 0x0008, + USE_FACE_COLOR = 0x0010, + TEXTURE_ANIM = 0x0020, }; static void initClass(); @@ -74,54 +61,64 @@ public: const S32 getGeomIndex() const { return mGeomIndex; } // index into draw pool const U32 getGeomStart() const { return mGeomIndex; } // index into draw pool LLViewerImage* getTexture() const { return mTexture; } + void setTexture(LLViewerImage* tex) { mTexture = tex; } LLXformMatrix* getXform() const { return mXform; } BOOL hasGeometry() const { return mGeomCount > 0; } LLVector3 getPositionAgent() const; - void setPrimType(U32 primType) { mPrimType = primType; } - const U32 getPrimType() const { return mPrimType; } - + U32 getState() const { return mState; } void setState(U32 state) { mState |= state; } void clearState(U32 state) { mState &= ~state; } - BOOL isState(U32 state) const { return ((mState & state) != 0); } - + BOOL isState(U32 state) const { return ((mState & state) != 0) ? TRUE : FALSE; } + void setVirtualSize(F32 size) { mVSize = size; } + void setPixelArea(F32 area) { mPixelArea = area; } + F32 getVirtualSize() const { return mVSize; } + F32 getPixelArea() const { return mPixelArea; } void bindTexture(S32 stage = 0) const { LLViewerImage::bindTexture(mTexture, stage); } void enableLights() const; void renderSetColor() const; S32 renderElements(const U32 *index_array) const; - S32 renderIndexed (const U32 *index_array) const; + S32 renderIndexed (); + S32 renderIndexed (U32 mask); S32 pushVertices(const U32* index_array) const; void setWorldMatrix(const LLMatrix4& mat); const LLTextureEntry* getTextureEntry() const { return mVObjp->getTE(mTEOffset); } - LLDrawPool* getPool() const { return mDrawPoolp; } - S32 getStride() const { return mDrawPoolp->getStride(); } - const U32* getRawIndices() const { return &mDrawPoolp->mIndices[mIndicesIndex]; } + LLFacePool* getPool() const { return mDrawPoolp; } + U32 getPoolType() const { return mPoolType; } LLDrawable* getDrawable() const { return mDrawablep; } LLViewerObject* getViewerObject() const { return mVObjp; } - - void clearDirty() { mGeneration = mDrawPoolp->mGeneration; }; - - S32 backup(); - void restore(); + S32 getLOD() const { return mVObjp.notNull() ? mVObjp->getLOD() : 0; } + LLVertexBuffer* getVertexBuffer() const { return mVertexBuffer; } + void setPoolType(U32 type) { mPoolType = type; } + S32 getTEOffset() { return mTEOffset; } void setViewerObject(LLViewerObject* object); - void setPool(LLDrawPool *pool, LLViewerImage *texturep); + void setPool(LLFacePool *pool, LLViewerImage *texturep); + void setDrawable(LLDrawable *drawable); void setTEOffset(const S32 te_offset); - S32 getTEOffset() { return mTEOffset; } + void setFaceColor(const LLColor4& color); // override material color void unsetFaceColor(); // switch back to material color const LLColor4& getFaceColor() const { return mFaceColor; } const LLColor4& getRenderColor() const; - void unReserve(); // Set Removed from pool - - BOOL reserveIfNeeded(); // Reserves data if dirty. - + //for volumes + S32 getGeometryVolume(const LLVolume& volume, + S32 f, + LLStrider<LLVector3>& vertices, + LLStrider<LLVector3>& normals, + LLStrider<LLVector2>& texcoords, + LLStrider<LLVector2>& texcoords2, + LLStrider<LLColor4U>& colors, + LLStrider<U32>& indices, + const LLMatrix4& mat_vert, const LLMatrix3& mat_normal, + U32& index_offset); + // For avatar S32 getGeometryAvatar( LLStrider<LLVector3> &vertices, @@ -137,69 +134,51 @@ public: LLStrider<LLColor4U> &colors, LLStrider<LLVector2> &texCoords0, LLStrider<LLVector2> &texCoords1, - U32* &indices); + LLStrider<U32> &indices); // For volumes, etc. S32 getGeometry(LLStrider<LLVector3> &vertices, LLStrider<LLVector3> &normals, LLStrider<LLVector2> &texCoords, - U32* &indices); + LLStrider<U32> &indices); S32 getGeometryColors(LLStrider<LLVector3> &vertices, LLStrider<LLVector3> &normals, LLStrider<LLVector2> &texCoords, LLStrider<LLColor4U> &colors, - U32* &indices); + LLStrider<U32> &indices); - S32 getGeometryMultiTexture(LLStrider<LLVector3> &vertices, - LLStrider<LLVector3> &normals, - LLStrider<LLVector3> &binormals, - LLStrider<LLVector2> &texCoords0, - LLStrider<LLVector2> &texCoords1, - U32* &indices); - - - S32 getVertices (LLStrider<LLVector3> &vertices); - S32 getColors (LLStrider<LLColor4U> &colors); - S32 getIndices (U32* &indices); + S32 getVertices(LLStrider<LLVector3> &vertices); + S32 getColors(LLStrider<LLColor4U> &colors); + S32 getIndices(LLStrider<U32> &indices); void setSize(const S32 numVertices, const S32 num_indices = 0); - BOOL getDirty() const { return (mGeneration != mDrawPoolp->mGeneration); } - - BOOL genVolumeTriangles(const LLVolume &volume, S32 f, - const LLMatrix4& mat, const LLMatrix3& inv_trans_mat, BOOL global_volume = FALSE); - BOOL genVolumeTriangles(const LLVolume &volume, S32 fstart, S32 fend, + + BOOL genVolumeBBoxes(const LLVolume &volume, S32 f, const LLMatrix4& mat, const LLMatrix3& inv_trans_mat, BOOL global_volume = FALSE); - BOOL genLighting(const LLVolume* volume, const LLDrawable* drawablep, S32 fstart, S32 fend, - const LLMatrix4& mat_vert, const LLMatrix3& mat_normal, BOOL do_lighting); - - BOOL genShadows(const LLVolume* volume, const LLDrawable* drawablep, S32 fstart, S32 fend, - const LLMatrix4& mat_vert, const LLMatrix3& mat_normal, BOOL use_shadow_factor); - + void init(LLDrawable* drawablep, LLViewerObject* objp); void destroy(); void update(); void updateCenterAgent(); // Update center when xform has changed. - void renderSelectedUV(const S32 offset = 0, const S32 count = 0); + void renderSelectedUV(const S32 offset = 0, const S32 count = 0); - void renderForSelect() const; + void renderForSelect(U32 data_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD); void renderSelected(LLImageGL *image, const LLColor4 &color, const S32 offset = 0, const S32 count = 0); F32 getKey() const { return mDistance; } - S32 getGeneration() const { return mGeneration; } S32 getReferenceIndex() const { return mReferenceIndex; } void setReferenceIndex(const S32 index) { mReferenceIndex = index; } BOOL verify(const U32* indices_array = NULL) const; void printDebugInfo() const; - void link(LLFace* facep); + void setGeomIndex(S32 idx) { mGeomIndex = idx; } + void setIndicesIndex(S32 idx) { mIndicesIndex = idx; } protected: - S32 allocBackupMem(); // Allocate backup memory based on the draw pool information. - void setDirty(); public: LLVector3 mCenterLocal; @@ -208,30 +187,39 @@ public: LLVector2 mTexExtents[2]; F32 mDistance; F32 mAlphaFade; - LLFace* mNextFace; - BOOL mSkipRender; - + LLPointer<LLVertexBuffer> mVertexBuffer; + LLPointer<LLVertexBuffer> mLastVertexBuffer; + F32 mLastUpdateTime; + protected: - S32 mGeneration; + friend class LLGeometryManager; + friend class LLVolumeGeometryManager; + U32 mState; - LLDrawPool* mDrawPoolp; - S32 mGeomIndex; // index into draw pool + LLFacePool* mDrawPoolp; + U32 mPoolType; LLColor4 mFaceColor; // overrides material color if state |= USE_FACE_COLOR - U32 mPrimType; S32 mGeomCount; // vertex count for this face + S32 mGeomIndex; // index into draw pool U32 mIndicesCount; S32 mIndicesIndex; // index into draw pool for indices (yeah, I know!) - LLXformMatrix* mXform; - LLPointer<LLViewerImage> mTexture; - U8 *mBackupMem; + //previous rebuild's geometry info + S32 mLastGeomCount; + S32 mLastGeomIndex; + U32 mLastIndicesCount; + S32 mLastIndicesIndex; + LLXformMatrix* mXform; + LLPointer<LLViewerImage> mTexture; LLPointer<LLDrawable> mDrawablep; LLPointer<LLViewerObject> mVObjp; S32 mTEOffset; S32 mReferenceIndex; + F32 mVSize; + F32 mPixelArea; protected: static BOOL sSafeRenderSelect; @@ -245,6 +233,43 @@ public: } }; + struct CompareTexture + { + bool operator()(const LLFace* const& lhs, const LLFace* const& rhs) + { + return lhs->getTexture() < rhs->getTexture(); + } + }; + + struct CompareTextureAndGeomCount + { + bool operator()(const LLFace* const& lhs, const LLFace* const& rhs) + { + return lhs->getTexture() == rhs->getTexture() ? + lhs->getGeomCount() < rhs->getGeomCount() : + lhs->getTexture() > rhs->getTexture(); + } + }; + + struct CompareTextureAndLOD + { + bool operator()(const LLFace* const& lhs, const LLFace* const& rhs) + { + return lhs->getTexture() == rhs->getTexture() ? + lhs->getLOD() < rhs->getLOD() : + lhs->getTexture() < rhs->getTexture(); + } + }; + + struct CompareTextureAndTime + { + bool operator()(const LLFace* const& lhs, const LLFace* const& rhs) + { + return lhs->getTexture() == rhs->getTexture() ? + lhs->mLastUpdateTime < rhs->mLastUpdateTime : + lhs->getTexture() < rhs->getTexture(); + } + }; }; #endif // LL_LLFACE_H diff --git a/indra/newview/llfasttimerview.cpp b/indra/newview/llfasttimerview.cpp index 57f786053a..09610b01a3 100644 --- a/indra/newview/llfasttimerview.cpp +++ b/indra/newview/llfasttimerview.cpp @@ -67,31 +67,41 @@ static struct ft_display_info ft_display_table[] = { LLFastTimer::FTM_RESET_DRAWORDER, " ResetDrawOrder", &LLColor4::pink1, 0 }, { LLFastTimer::FTM_WORLD_UPDATE, " World Update", &LLColor4::blue1, 1 }, { LLFastTimer::FTM_UPDATE_MOVE, " Move Objects", &LLColor4::pink2, 0 }, - { LLFastTimer::FTM_OCTREE_BALANCE, " Octree Balance", &LLColor4::red3, 0 }, - { LLFastTimer::FTM_CULL, " Object Cull", &LLColor4::blue2, 0 }, - { LLFastTimer::FTM_CULL_REBOUND, " Rebound", &LLColor4::blue3, 0 }, + { LLFastTimer::FTM_OCTREE_BALANCE, " Octree Balance", &LLColor4::red3, 0 }, + { LLFastTimer::FTM_TEMP1, " Blur", &LLColor4::red1, 0 }, + { LLFastTimer::FTM_CULL, " Object Cull", &LLColor4::blue2, 1 }, + { LLFastTimer::FTM_CULL_REBOUND, " Rebound", &LLColor4::blue3, 0 }, + { LLFastTimer::FTM_FRUSTUM_CULL, " Frustum Cull", &LLColor4::blue4, 0 }, + { LLFastTimer::FTM_OCCLUSION, " Object Occlude", &LLColor4::pink1, 0 }, + { LLFastTimer::FTM_OCCLUSION_READBACK, " Occlusion Read", &LLColor4::red2, 0 }, { LLFastTimer::FTM_HUD_EFFECTS, " HUD Effects", &LLColor4::orange1, 0 }, { LLFastTimer::FTM_HUD_UPDATE, " HUD Update", &LLColor4::orange2, 0 }, - { LLFastTimer::FTM_OCCLUSION, " Object Occlude",&LLColor4::pink1, 0 }, - { LLFastTimer::FTM_OCCLUSION_READBACK, " Occlusion Read",&LLColor4::red2, 0 }, { LLFastTimer::FTM_GEO_UPDATE, " Geo Update", &LLColor4::blue3, 0 }, { LLFastTimer::FTM_UPDATE_PRIMITIVES, " Volumes", &LLColor4::blue4, 0 }, { LLFastTimer::FTM_GEN_VOLUME, " Gen Volume", &LLColor4::yellow3, 0 }, { LLFastTimer::FTM_GEN_FLEX, " Flexible", &LLColor4::yellow4, 0 }, { LLFastTimer::FTM_GEN_TRIANGLES, " Triangles", &LLColor4::yellow5, 0 }, + { LLFastTimer::FTM_UPDATE_AVATAR, " Avatar", &LLColor4::yellow1, 0 }, + { LLFastTimer::FTM_UPDATE_TREE, " Tree", &LLColor4::yellow2, 0 }, + { LLFastTimer::FTM_UPDATE_TERRAIN, " Terrain", &LLColor4::yellow6, 0 }, + { LLFastTimer::FTM_UPDATE_CLOUDS, " Clouds", &LLColor4::yellow7, 0 }, + { LLFastTimer::FTM_UPDATE_GRASS, " Grass", &LLColor4::yellow8, 0 }, + { LLFastTimer::FTM_UPDATE_WATER, " Water", &LLColor4::yellow9, 0 }, { LLFastTimer::FTM_GEO_LIGHT, " Lighting", &LLColor4::yellow1, 0 }, { LLFastTimer::FTM_GEO_SHADOW, " Shadow", &LLColor4::black, 0 }, { LLFastTimer::FTM_UPDATE_PARTICLES, " Particles", &LLColor4::blue5, 0 }, + { LLFastTimer::FTM_SIMULATE_PARTICLES, " Particle Sim", &LLColor4::blue4, 0 }, { LLFastTimer::FTM_GEO_RESERVE, " Reserve", &LLColor4::blue6, 0 }, { LLFastTimer::FTM_UPDATE_LIGHTS, " Lights", &LLColor4::yellow2, 0 }, { LLFastTimer::FTM_UPDATE_SKY, " Sky Update", &LLColor4::cyan1, 0 }, - { LLFastTimer::FTM_OBJECTLIST_UPDATE, " Object Update", &LLColor4::purple1, 1 }, + { LLFastTimer::FTM_OBJECTLIST_UPDATE, " Object Update", &LLColor4::purple1, 0 }, { LLFastTimer::FTM_AVATAR_UPDATE, " Avatars", &LLColor4::purple2, 0 }, { LLFastTimer::FTM_JOINT_UPDATE, " Joints", &LLColor4::purple3, 0 }, { LLFastTimer::FTM_ATTACHMENT_UPDATE, " Attachments", &LLColor4::purple4, 0 }, { LLFastTimer::FTM_UPDATE_ANIMATION, " Animation", &LLColor4::purple5, 0 }, { LLFastTimer::FTM_FLEXIBLE_UPDATE, " Flex Update", &LLColor4::pink2, 0 }, { LLFastTimer::FTM_LOD_UPDATE, " LOD Update", &LLColor4::magenta1, 0 }, + { LLFastTimer::FTM_TEMP5, " Check", &LLColor4::red1, 1}, { LLFastTimer::FTM_REGION_UPDATE, " Region Update", &LLColor4::cyan2, 0 }, { LLFastTimer::FTM_NETWORK, " Network", &LLColor4::orange1, 1 }, { LLFastTimer::FTM_IDLE_NETWORK, " Decode Msgs", &LLColor4::orange2, 0 }, @@ -106,17 +116,35 @@ static struct ft_display_info ft_display_table[] = { LLFastTimer::FTM_IMAGE_UPDATE, " Image Update", &LLColor4::yellow4, 1 }, { LLFastTimer::FTM_IMAGE_CREATE, " Image CreateGL",&LLColor4::yellow5, 0 }, { LLFastTimer::FTM_IMAGE_DECODE, " Image Decode", &LLColor4::yellow6, 0 }, + { LLFastTimer::FTM_IMAGE_MARK_DIRTY, " Dirty Textures",&LLColor4::red1, 0 }, { LLFastTimer::FTM_VFILE_WAIT, " VFile Wait", &LLColor4::cyan6, 0 }, // { LLFastTimer::FTM_IDLE_CB, " Callbacks", &LLColor4::pink1, 0 }, - { LLFastTimer::FTM_RENDER, " Render", &green0, 0 }, + { LLFastTimer::FTM_RENDER, " Render", &green0, 1 }, { LLFastTimer::FTM_REBUILD, " Rebuild", &LLColor4::green1, 1 }, { LLFastTimer::FTM_STATESORT, " State Sort", &LLColor4::orange1, 1 }, + { LLFastTimer::FTM_STATESORT_DRAWABLE, " Drawable", &LLColor4::orange2, 0 }, + { LLFastTimer::FTM_STATESORT_POSTSORT, " Post Sort", &LLColor4::orange3, 0 }, + { LLFastTimer::FTM_REBUILD_OCCLUSION_VB," Occlusion", &LLColor4::cyan5, 0 }, + { LLFastTimer::FTM_REBUILD_VBO, " VBO Rebuild", &LLColor4::red4, 0 }, + { LLFastTimer::FTM_REBUILD_VOLUME_VB, " Volume", &LLColor4::blue1, 0 }, + { LLFastTimer::FTM_REBUILD_NONE_VB, " Unknown", &LLColor4::cyan5, 0 }, + { LLFastTimer::FTM_REBUILD_BRIDGE_VB, " Bridge", &LLColor4::blue2, 0 }, + { LLFastTimer::FTM_REBUILD_HUD_VB, " HUD", &LLColor4::blue3, 0 }, + { LLFastTimer::FTM_REBUILD_TERRAIN_VB, " Terrain", &LLColor4::blue4, 0 }, + { LLFastTimer::FTM_REBUILD_WATER_VB, " Water", &LLColor4::blue5, 0 }, + { LLFastTimer::FTM_REBUILD_TREE_VB, " Tree", &LLColor4::cyan1, 0 }, + { LLFastTimer::FTM_REBUILD_PARTICLE_VB, " Particle", &LLColor4::cyan2, 0 }, + { LLFastTimer::FTM_REBUILD_CLOUD_VB, " Cloud", &LLColor4::cyan3, 0 }, + { LLFastTimer::FTM_REBUILD_GRASS_VB, " Grass", &LLColor4::cyan4, 0 }, { LLFastTimer::FTM_RENDER_GEOMETRY, " Geometry", &LLColor4::green2, 1 }, - { LLFastTimer::FTM_POOLS, " Pools", &LLColor4::green3, 0 }, - { LLFastTimer::FTM_POOLRENDER, " RenderPool", &LLColor4::green4, 0 }, + { LLFastTimer::FTM_POOLS, " Pools", &LLColor4::green3, 1 }, + { LLFastTimer::FTM_POOLRENDER, " RenderPool", &LLColor4::green4, 1 }, { LLFastTimer::FTM_RENDER_TERRAIN, " Terrain", &LLColor4::green6, 0 }, { LLFastTimer::FTM_RENDER_CHARACTERS, " Avatars", &LLColor4::yellow1, 0 }, { LLFastTimer::FTM_RENDER_SIMPLE, " Simple", &LLColor4::yellow2, 0 }, + { LLFastTimer::FTM_RENDER_FULLBRIGHT, " Fullbright", &LLColor4::yellow5, 0 }, + { LLFastTimer::FTM_RENDER_GRASS, " Grass", &LLColor4::yellow6, 0 }, + { LLFastTimer::FTM_RENDER_INVISIBLE, " Invisible", &LLColor4::red2, 0 }, { LLFastTimer::FTM_RENDER_SHINY, " Shiny", &LLColor4::yellow3, 0 }, { LLFastTimer::FTM_RENDER_BUMP, " Bump", &LLColor4::yellow4, 0 }, { LLFastTimer::FTM_RENDER_TREES, " Trees", &LLColor4::yellow8, 0 }, @@ -130,15 +158,16 @@ static struct ft_display_info ft_display_table[] = // { LLFastTimer::FTM_RENDER_FONTS, " Fonts", &LLColor4::pink1, 0 }, // { LLFastTimer::FTM_UPDATE_TEXTURES, " Textures", &LLColor4::pink2, 0 }, { LLFastTimer::FTM_SWAP, " Swap", &LLColor4::pink1, 0 }, + { LLFastTimer::FTM_TEMP6, " Client Copy", &LLColor4::red1, 1}, -// { LLFastTimer::FTM_TEMP1, " Temp1", &LLColor4::red1, 0 }, -// { LLFastTimer::FTM_TEMP2, " Temp2", &LLColor4::magenta1, 0 }, -// { LLFastTimer::FTM_TEMP3, " Temp3", &LLColor4::red2, 0 }, -// { LLFastTimer::FTM_TEMP4, " Temp4", &LLColor4::magenta2, 0 }, -// { LLFastTimer::FTM_TEMP5, " Temp5", &LLColor4::red3, 0 }, -// { LLFastTimer::FTM_TEMP6, " Temp6", &LLColor4::magenta3, 0 }, -// { LLFastTimer::FTM_TEMP7, " Temp7", &LLColor4::red4, 0 }, -// { LLFastTimer::FTM_TEMP8, " Temp8", &LLColor4::magenta4, 0 }, +// { LLFastTimer::FTM_TEMP1, " Temp1", &LLColor4::red1, 0 }, +// { LLFastTimer::FTM_TEMP2, " Temp2", &LLColor4::magenta1, 0 }, +// { LLFastTimer::FTM_TEMP3, " Temp3", &LLColor4::red2, 0 }, +// { LLFastTimer::FTM_TEMP4, " Temp4", &LLColor4::magenta2, 0 }, +// { LLFastTimer::FTM_TEMP5, " Temp5", &LLColor4::red3, 0 }, +// { LLFastTimer::FTM_TEMP6, " Temp6", &LLColor4::magenta3, 0 }, +// { LLFastTimer::FTM_TEMP7, " Temp7", &LLColor4::red4, 0 }, +// { LLFastTimer::FTM_TEMP8, " Temp8", &LLColor4::magenta4, 0 }, { LLFastTimer::FTM_OTHER, " Other", &red0 } }; @@ -148,7 +177,7 @@ static const int FTV_DISPLAY_NUM = (sizeof(ft_display_table)/sizeof(ft_display_ S32 ft_display_idx[FTV_DISPLAY_NUM]; // line of table entry for display purposes (for collapse) LLFastTimerView::LLFastTimerView(const std::string& name, const LLRect& rect) -: LLView(name, rect, TRUE) + : LLFloater(name, rect, "Fast Timers") { setVisible(FALSE); mDisplayMode = 0; @@ -891,7 +920,10 @@ void LLFastTimerView::draw() F32 ms = (F32)((F64)max_ticks * iclock_freq); //display y-axis range - LLString tdesc = llformat("%4.2f ms", ms); + LLString tdesc = mDisplayCalls ? + llformat("%d calls", max_ticks) : + llformat("%4.2f ms", ms); + x = graph_rect.mRight - LLFontGL::sMonospace->getWidth(tdesc)-5; y = graph_rect.mTop - ((S32)LLFontGL::sMonospace->getLineHeight()); @@ -957,6 +989,13 @@ void LLFastTimerView::draw() for (U32 j = 0; j < LLFastTimer::FTM_HISTORY_NUM; j++) { U64 ticks = ticks_sum[j+1][idx]; + if (mDisplayCalls) + { + S32 tidx = ft_display_table[idx].timer; + S32 hidx = (LLFastTimer::sLastFrameIndex + j) % LLFastTimer::FTM_HISTORY_NUM; + ticks = (S32)LLFastTimer::sCallHistory[hidx][tidx]; + } + if (alpha == 1.f) { //normalize to highlighted timer cur_max = llmax(cur_max, ticks); diff --git a/indra/newview/llfasttimerview.h b/indra/newview/llfasttimerview.h index eb30f60f3d..be66a8481a 100644 --- a/indra/newview/llfasttimerview.h +++ b/indra/newview/llfasttimerview.h @@ -9,10 +9,10 @@ #ifndef LL_LLFASTTIMERVIEW_H #define LL_LLFASTTIMERVIEW_H -#include "llview.h" +#include "llfloater.h" #include "llframetimer.h" -class LLFastTimerView : public LLView +class LLFastTimerView : public LLFloater { public: LLFastTimerView(const std::string& name, const LLRect& rect); diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp index bee2f879ac..e3b5a2bb68 100644 --- a/indra/newview/llfeaturemanager.cpp +++ b/indra/newview/llfeaturemanager.cpp @@ -137,7 +137,7 @@ BOOL LLFeatureList::maskList(LLFeatureList &mask) } #if 0 && !LL_RELEASE_FOR_DOWNLOAD - llinfos << "After appling mask " << mask.mName << llendl; + llinfos << "After applying mask " << mask.mName << llendl; dump(); #endif return TRUE; @@ -276,7 +276,6 @@ BOOL LLFeatureManager::loadFeatureTables() } } file.close(); - //flp->dump(); return TRUE; } @@ -361,10 +360,11 @@ void LLFeatureManager::loadGPUClass() llinfos << "GPU is " << label << llendl; mGPUString = label; mGPUClass = (S32) strtol(cls, NULL, 10); + file.close(); + return; } } file.close(); - //flp->dump(); llwarns << "Couldn't match GPU to a class: " << gGLManager.getRawGLString() << llendl; } @@ -382,11 +382,7 @@ void LLFeatureManager::initCPUFeatureMasks() { maskFeatures("RAM256MB"); } - else if (gSysMemory.getPhysicalMemory() <= 512*1024*1024) - { - //maskFeatures("RAM512MB"); - } - + if (gSysCPU.getMhz() < 1100) { maskFeatures("CPUSlow"); @@ -449,7 +445,11 @@ void LLFeatureManager::initGraphicsFeatureMasks() } if (gGLManager.mIsIntel) { - maskFeatures("Brookdale"); + maskFeatures("Intel"); + } + if (gGLManager.mGLVersion < 1.5f) + { + maskFeatures("OpenGLPre15"); } if (gGLManager.mIsMobilityRadeon9000) @@ -464,303 +464,6 @@ void LLFeatureManager::initGraphicsFeatureMasks() extern LLOSInfo gSysOS; - -BOOL bad_hardware_dialog(const LLString &info_str, const LLString &url) -{ - if (!gSavedSettings.getWarning("AboutBadPCI")) - { - return FALSE; - } - - // XUI:translate - std::string msg = llformat( - "[SECOND_LIFE] has detected that there may be a problem with.\n" - "hardware or drivers on your computer. Often resolving these\n" - "issues can result in enhanced stability and performance.\n" - " \n" - "%s\n" - " \n" - "Would you like to view a web page with more detailed\n" - "information on this problem?\n", info_str.c_str()); - - // Warn them that runnin without DirectX 9 will - // not allow us to tell them about driver issues - S32 button = OSMessageBox(msg.c_str(), - "Warning", - OSMB_YESNO); - if (OSBTN_YES== button) - { - llinfos << "User quitting after detecting bad drivers" << llendl; - spawn_web_browser(url.c_str()); - return TRUE; - } - else - { - // Don't warn about bad PCI stuff again, they've clicked past it. - gSavedSettings.setWarning("AboutBadPCI", FALSE); - } - return FALSE; -} - -BOOL LLFeatureManager::initPCIFeatureMasks() -{ -#if LL_WINDOWS - BOOL exit_after_bad = FALSE; - - BOOL is_2000 = FALSE; - BOOL is_xp = FALSE; - - if (gSysOS.mMajorVer != 5) - { - // Unknown windows version number, exit!" - llwarns << "Unknown Windows major version " << gSysOS.mMajorVer << ", aborting detection!" << llendl; - return FALSE; - } - if (gSysOS.mMinorVer == 0) - { - is_2000 = TRUE; - } - else if (gSysOS.mMinorVer == 1) - { - is_xp = TRUE; - } - else - { - llwarns << "Unknown Windows minor version " << gSysOS.mMinorVer << ", aborting detection!" << llendl; - return FALSE; - } - - // This only works on Win32, as it relies on DX9 hardware detection - // The PCI masks are actually the inverse of the normal masks - // We actually look through the masks,and see if any hardware matches it. - // This is because the masks encode logic about - - // Check for the broken AMD AGP controllers (751, 761, 762) - - // Horrible cruddy fixed lookup table. - // Figure out what OS we're on, the version numbers are different. Sigh... - - LLDXDriverFile *dfilep = NULL; - LLDXDevice *devp = NULL; - - // AMD(1022) AGP controllers - // 7007 AMD-751 AGP Controller - // 700F AMD-761 AGP Controller - // 700D AMD-762 AGP Controller - devp = gDXHardware.findDevice("VEN_1022", "DEV_7007|DEV_700F|DEV_700D"); - if (devp) - { - // We're just pretty much screwed here, there are big problems with this hardware - // We've got trouble with the most recent nVidia drivers. Check for this and warn. - - // Note: Need to detect that we're running with older nVidia hardware, probably - exit_after_bad |= bad_hardware_dialog("AMD AGP Controller", - AMD_AGP_URL); - } - - // VIA(1106) AGP Controllers - // These need upgrading on both Win2K and WinXP - // - // 8305 VT8363/8365 CPU to AGP - Apollo KT133/KM133 - // 8598 VT82C598MVP/694X CPU to AGP - Apollo MVP3/Pro133A - // 8605 VT8605 CPU to AGP - Apollo PM133 - // B091 VT8633 CPU to AGP - Apollo Pro 266 - // B099 VT8366/A/T CPU to AGP - Apollo KT266/A/333 - // B168 VT8235 CPU to AGP (AGP 2.0/3.0) - ProSavageDDR P4X333 chipset - // B188 VT8237 CPU to AGP (AGP 2.0/3.0) - K8T800 - // B198 VT8237 CPU to AGP (AGP 2.0/3.0) - ProSavageDDR P4X600 chipset - - devp = gDXHardware.findDevice("VEN_1106", - "DEV_8305|DEV_8598|DEV_8605|DEV_B091|" - "DEV_B099|DEV_B168|DEV_B188|DEV_B198"); - if (devp) - { - BOOL out_of_date = FALSE; - // Wanted driver: VIAAGP1.SYS - // Version Format: M.mm.0000.vvvv - // M.mm - Major/minor OS version (5.0 for Win2000, 5.1 for WinXP) - // vvvv - driver version number - // - // Notes: - // 3442 is most recent as of 2/25/04, probably want at least 3430 (seems to be a common version) - - // These are DELIBERATE assignments inside if statements, blech. - if (dfilep = devp->findDriver("pci.sys")) - { - // Old driver: pci.sys - // Version: 5.01.2600.xxxx - // - // Notes: - // Default WinXP driver for B168, B198? - - // Old driver: pci.sys - // Version: 5.01.2195.xxxx - // - // Notes: - // Default Win2K driver for 8305? - - llwarns << "Detected pci.sys" << llendl; - write_debug("Old driver (pci.sys) for VIA detected!"); - out_of_date = TRUE; - } - else if (dfilep = devp->findDriver("VIAAGP.SYS")) - { - // Old driver: VIAAGP.SYS - // Version: 5.01.2600.xxxx - // - // Notes: - // Default WinXP driver for B09x? - - llwarns << "Detected VIAAGP.SYS" << llendl; - write_debug("Old driver (VIAAGP.SYS) for VIA detected!"); - out_of_date = TRUE; - } - else if (dfilep = devp->findDriver("VIAAGP1.SYS")) - { - if (dfilep->mVersion.getField(3) < 3430) - { - // They're using a pretty old version of the VIA AGP drivers - // Maybe they want to upgrade? - llwarns << "Detected VIAAGP1.SYS" << llendl; - write_debug("Old driver (VIAAGP1.SYS) for VIA detected!"); - out_of_date = TRUE; - } - } - if (out_of_date) - { - exit_after_bad |= bad_hardware_dialog("Out of date VIA AGP chipset driver", - VIA_URL); - } - } - - // Intel(8086) AGP controllers (Win2K) - // These particular controllers only may need drivers on Win2K - // - // 1A31 82845[MP|MZ] Processor to AGP Controller - // 2532 82850/860 Processor to AGP Controller - if (is_2000) - { - devp = gDXHardware.findDevice("VEN_8086", - "DEV_1A31"); - if (devp) - { - if (dfilep = devp->findDriver("pci.sys")) - { - // Old driver: pci.sys - // Version 5.01.21[9|6]5.xxxx - // - // Notes: - // Default driver for Win2K? Not sure what the "correct" driver is - - // maybe some variant of AGP440.SYS? - llwarns << "Detected pci.sys" << llendl; - write_debug("Old driver (pci.sys) for Intel 82845/850 on Win2K detected!"); - exit_after_bad |= bad_hardware_dialog("Out of date Intel chipset driver", - INTEL_CHIPSET_URL); - } - } - } - - /* Removed 4/3/2006 by JC - After talking with Doug, we don't know what the proper driver - and/or version number should be for Intel 865. Regardless, this - code would _always_ complain if you had that chipset. - - // Intel(8086) AGP controllers (All) - // These particular controllers may need drivers on both Win2K and WinXP - // - // 2561 82845G/GL/GE/PE/GV Processor to AGP Controller - // 2571 82865G/PE/P/GV/28248P Processor to AGP Controller - devp = gDXHardware.findDevice("VEN_8086", - "DEV_2571"); - if (devp) - { - // Wanted driver: AGP440.SYS(?) - // - // Notes: - // Not sure, need to verify with an actual 82865/75 (Dell 8300?) - - // Old driver: pci.sys - // Version 5.01.21[9|6]5.xxxx - // - // Notes: - // Default driver for Win2K? Not sure what the "correct" driver is - - // maybe some variant of AGP440.SYS? - exit_after_bad |= bad_hardware_dialog("Out of date Intel chipset driver", - INTEL_CHIPSET_URL); - } - */ - - - // SiS(1039) AGP controllers (All) - // These particular controllers may need drivers on both Win2K and WinXP - // - // 0001 SiS 530 - // 0002 SiS SG86C202(???) - // 0003 SiS 648FX - devp = gDXHardware.findDevice("VEN_1039", - "DEV_0001|DEV_0002|DEV_0003"); - if (devp) - { - BOOL out_of_date = FALSE; - // Wanted driver: SISAGPX.SYS - // - // Notes: - // Not sure, need to verify with an actual 82865/75 (Dell 8300?) - - // Old driver: pci.sys - // Version 5.01.21[9|6]5.xxxx - // - // Notes: - // Default driver for Win2K? Not sure what the "correct" driver is - - // maybe some variant of AGP440.SYS? - if (dfilep = devp->findDriver("pci.sys")) - { - // Old driver: pci.sys - // Version 5.01.21[9|6]5.xxxx - // - llwarns << "Detected pci.sys" << llendl; - write_debug("Old driver (pci.sys) for SiS detected!"); - out_of_date = TRUE; - } - - if (dfilep = devp->findDriver("sisagp.sys")) - { - // Old driver: pci.sys - // Version 5.01.21[9|6]5.xxxx - // - llwarns << "Detected sisagp.sys" << llendl; - write_debug("Old driver (sisagp.sys) for SiS detected!"); - out_of_date = TRUE; - } - - if (dfilep = devp->findDriver("sisagpx.sys")) - { - // Old driver: pci.sys - // Version 7.02.0000.xxxx - // - // Notes: - // Default driver for Win2K? Not sure what the "correct" driver is - - // maybe some variant of AGP440.SYS? - if (dfilep->mVersion.getField(3) < 1160) - { - out_of_date = TRUE; - llwarns << "Detected sisagpx.sys" << llendl; - write_debug("Old driver (sisagpx.sys) for SiS detected!"); - } - } - if (out_of_date) - { - exit_after_bad |= bad_hardware_dialog("Out of date SiS chipset driver", - SIS_CHIPSET_URL); - } - } - - return exit_after_bad; -#else - return TRUE; -#endif -} - void LLFeatureManager::applyRecommendedFeatures() { // see featuretable.txt @@ -770,14 +473,14 @@ void LLFeatureManager::applyRecommendedFeatures() dump(); #endif - // Enabling AGP - if (getRecommendedLevel("RenderAGP")) + // Enabling VBO + if (getRecommendedLevel("RenderVBO")) { - gSavedSettings.setBOOL("RenderUseAGP", TRUE); + gSavedSettings.setBOOL("RenderVBOEnable", TRUE); } else { - gSavedSettings.setBOOL("RenderUseAGP", FALSE); + gSavedSettings.setBOOL("RenderVBOEnable", FALSE); } // Anisotropic rendering diff --git a/indra/newview/llfeaturemanager.h b/indra/newview/llfeaturemanager.h index fe37cd7638..8988d790e8 100644 --- a/indra/newview/llfeaturemanager.h +++ b/indra/newview/llfeaturemanager.h @@ -81,8 +81,7 @@ public: void initCPUFeatureMasks(); void initGraphicsFeatureMasks(); - BOOL initPCIFeatureMasks(); - + void applyRecommendedFeatures(); protected: diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp index 98bbf23502..2b2a9fa859 100644 --- a/indra/newview/llfilepicker.cpp +++ b/indra/newview/llfilepicker.cpp @@ -345,6 +345,16 @@ BOOL LLFilePicker::getSaveFile(ESaveFilter filter, const char* filename) mOFN.lpstrFilter = RAW_FILTER \ L"\0"; break; + case FFSAVE_J2C: + if (!filename) + { + wcsncpy( mFilesW,L"untitled.j2c", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L"j2c"; + mOFN.lpstrFilter = + L"Compressed Images (*.j2c)\0*.j2c\0" \ + L"\0"; + break; default: return FALSE; } @@ -660,6 +670,12 @@ OSStatus LLFilePicker::doNavSaveDialog(ESaveFilter filter, const char* filename) extension = CFSTR(".raw"); break; + case FFSAVE_J2C: + type = '\?\?\?\?'; + creator = 'prvw'; + extension = CFSTR(".j2c"); + break; + case FFSAVE_ALL: default: type = '\?\?\?\?'; @@ -1063,6 +1079,10 @@ BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const char* filename ) caption += "RAW File (*.raw)"; suggest_ext += ".raw"; break; + case FFSAVE_J2C: + caption += "Compressed Images (*.j2c)"; + suggest_ext += ".j2c"; + break; default:; break; } diff --git a/indra/newview/llfilepicker.h b/indra/newview/llfilepicker.h index 9b0eddbe2d..c04279ee91 100644 --- a/indra/newview/llfilepicker.h +++ b/indra/newview/llfilepicker.h @@ -87,6 +87,7 @@ public: FFSAVE_XML = 9, FFSAVE_COLLADA = 10, FFSAVE_RAW = 11, + FFSAVE_J2C = 12, }; // open the dialog. This is a modal operation diff --git a/indra/newview/llflexibleobject.cpp b/indra/newview/llflexibleobject.cpp index 5e105ac7e2..4e03e34663 100644 --- a/indra/newview/llflexibleobject.cpp +++ b/indra/newview/llflexibleobject.cpp @@ -25,11 +25,6 @@ #include "llviewerregion.h" #include "llworld.h" -/*static*/ LLVolumeImplFlexible::lodset_t LLVolumeImplFlexible::sLODBins[ FLEXIBLE_OBJECT_MAX_LOD ]; -/*static*/ U64 LLVolumeImplFlexible::sCurrentUpdateFrame = 0; -/*static*/ U32 LLVolumeImplFlexible::sDebugInserted = 0; -/*static*/ U32 LLVolumeImplFlexible::sDebugVisible = 0; - /*static*/ F32 LLVolumeImplFlexible::sUpdateFactor = 1.0f; // LLFlexibleObjectData::pack/unpack now in llprimitive.cpp @@ -40,14 +35,13 @@ LLVolumeImplFlexible::LLVolumeImplFlexible(LLViewerObject* vo, LLFlexibleObjectData* attributes) : mVO(vo), mAttributes(attributes) { + static U32 seed = 0; + mID = seed++; mInitialized = FALSE; mUpdated = FALSE; - mJustShifted = FALSE; mInitializedRes = -1; mSimulateRes = 0; mFrameNum = 0; - mLastUpdate = 0; - }//----------------------------------------------- LLVector3 LLVolumeImplFlexible::getFramePosition() const @@ -75,7 +69,6 @@ void LLVolumeImplFlexible::onShift(const LLVector3 &shift_vector) { mSection[section].mPosition += shift_vector; } - mVO->getVolume()->mBounds[0] += shift_vector; } //----------------------------------------------------------------------------------------------- @@ -88,7 +81,7 @@ void LLVolumeImplFlexible::setParentPositionAndRotationDirectly( LLVector3 p, LL void LLVolumeImplFlexible::remapSections(LLFlexibleObjectSection *source, S32 source_sections, LLFlexibleObjectSection *dest, S32 dest_sections) -{ +{ S32 num_output_sections = 1<<dest_sections; LLVector3 scale = mVO->mDrawable->getScale(); F32 source_section_length = scale.mV[VZ] / (F32)(1<<source_sections); @@ -209,6 +202,7 @@ void LLVolumeImplFlexible::setAttributesOfAllSections() F32 t_inc = 1.f/F32(num_sections); F32 t = t_inc; + for ( int i=1; i<= num_sections; i++) { mSection[i].mAxisRotation.setQuat(lerp(begin_rot,end_rot,t),0,0,1); @@ -217,18 +211,23 @@ void LLVolumeImplFlexible::setAttributesOfAllSections() scale.mV[VY] * lerp(bottom_scale.mV[1], top_scale.mV[1], t)); t += t_inc; } - mLastUpdate = 0; }//----------------------------------------------------------------------------------- void LLVolumeImplFlexible::onSetVolume(const LLVolumeParams &volume_params, const S32 detail) { - doIdleUpdate(gAgent, *gWorldp, 0.0); + if (mVO && mVO->mDrawable.notNull()) + { + LLVOVolume* volume = (LLVOVolume*) mVO; + volume->regenFaces(); + } + + /*doIdleUpdate(gAgent, *gWorldp, 0.0); if (mVO && mVO->mDrawable.notNull()) { gPipeline.markRebuild(mVO->mDrawable, LLDrawable::REBUILD_VOLUME, TRUE); gPipeline.markMoved(mVO->mDrawable); - } + }*/ } //--------------------------------------------------------------------------------- @@ -238,6 +237,13 @@ void LLVolumeImplFlexible::onSetVolume(const LLVolumeParams &volume_params, cons //--------------------------------------------------------------------------------- BOOL LLVolumeImplFlexible::doIdleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) { + if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_FLEXIBLE)) + { + return TRUE; + } + + LLFastTimer ftm(LLFastTimer::FTM_FLEXIBLE_UPDATE); + if (mVO->mDrawable.isNull()) { // Don't do anything until we have a drawable @@ -248,46 +254,17 @@ BOOL LLVolumeImplFlexible::doIdleUpdate(LLAgent &agent, LLWorld &world, const F6 mVO->mDrawable->mQuietCount = 0; if (!mVO->mDrawable->isRoot()) { - mVO->mDrawable->getParent()->mQuietCount = 0; - } - - if (((LLVOVolume*)mVO)->mLODChanged || - mVO->mDrawable->isState(LLDrawable::IN_REBUILD_Q1)) - { - mLastUpdate = 0; // Force an immediate update + LLViewerObject* parent = (LLViewerObject*) mVO->getParent(); + parent->mDrawable->mQuietCount = 0; } - // Relegate invisible objects to the lowest priority bin - S32 lod = 0; - F32 app_angle = mVO->getAppAngle()*DEG_TO_RAD/gCamera->getView(); - if (mVO->mDrawable->isVisible()) - { - sDebugVisible++; - if (mVO->isSelected()) - { - // Force selected objects to update *every* frame - lod = FLEXIBLE_OBJECT_MAX_LOD-1; - } - else - { - if (app_angle > 0) - { - lod = 5 - (S32)(1.0f/sqrtf(app_angle)); - if (lod < 1) - { - lod = 1; - } - } + + S32 new_res = mAttributes->getSimulateLOD(); - if (mVO->isAttachment()) - { - lod += 3; - } - } - } + //number of segments only cares about z axis + F32 app_angle = llround((F32) atan2( mVO->getScale().mV[2]*2.f, mVO->mDrawable->mDistanceWRTCamera) * RAD_TO_DEG, 0.01f); - S32 new_res = mAttributes->getSimulateLOD(); // Rendering sections increases with visible angle on the screen - mRenderRes = (S32)(FLEXIBLE_OBJECT_MAX_SECTIONS*4*app_angle); + mRenderRes = (S32)(FLEXIBLE_OBJECT_MAX_SECTIONS*4*app_angle*DEG_TO_RAD/gCamera->getView()); if (mRenderRes > FLEXIBLE_OBJECT_MAX_SECTIONS) { mRenderRes = FLEXIBLE_OBJECT_MAX_SECTIONS; @@ -310,22 +287,32 @@ BOOL LLVolumeImplFlexible::doIdleUpdate(LLAgent &agent, LLWorld &world, const F6 mInitialized = TRUE; } - sLODBins[lod].insert(this); - sDebugInserted++; - return TRUE; -} - -// static -void LLVolumeImplFlexible::resetUpdateBins() -{ - U32 lod; - for (lod=0; lod<FLEXIBLE_OBJECT_MAX_LOD; ++lod) + if (mVO->mDrawable->isVisible() && + !mVO->mDrawable->isState(LLDrawable::IN_REBUILD_Q1) && + mVO->getPixelArea() > 256.f) { - sLODBins[lod].clear(); + U32 id; + F32 pixel_area = mVO->getPixelArea(); + + if (mVO->isRootEdit()) + { + id = mID; + } + else + { + LLVOVolume* parent = (LLVOVolume*) mVO->getParent(); + id = parent->getVolumeInterfaceID(); + } + + U32 update_period = (U32) (gCamera->getScreenPixelArea()*0.01f/(pixel_area*(sUpdateFactor+1.f)))+1; + + if ((LLDrawable::getCurrentFrame()+id)%update_period == 0) + { + gPipeline.markRebuild(mVO->mDrawable, LLDrawable::REBUILD_POSITION, FALSE); + } } - ++sCurrentUpdateFrame; - sDebugInserted = 0; - sDebugVisible = 0; + + return TRUE; } inline S32 log2(S32 x) @@ -339,80 +326,15 @@ inline S32 log2(S32 x) return ret; } -// static -void LLVolumeImplFlexible::doFlexibleUpdateBins() -{ - U32 lod; - U32 updated = 0; - U32 regen = 0; - U32 newflexies = 0; - F32 time_alloc[FLEXIBLE_OBJECT_MAX_LOD]; - F32 total_time_alloc = 0; - - bool new_objects_only = false; - - if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_FLEXIBLE)) - { - new_objects_only = true; - } - - for (lod=0; lod<FLEXIBLE_OBJECT_MAX_LOD; ++lod) - { - int count = sLODBins[lod].size(); - if (count > 0) - { - time_alloc[lod] = (F32)((lod+1)*(log2(count))); - } - else - { - time_alloc[lod] = 0; - } - total_time_alloc += time_alloc[lod]; - } - total_time_alloc = FLEXIBLE_OBJECT_TIMESLICE * (sUpdateFactor+0.01f) / total_time_alloc; - - { - LLFastTimer t(LLFastTimer::FTM_FLEXIBLE_UPDATE); - LLTimer timer; - for (lod=0; lod<FLEXIBLE_OBJECT_MAX_LOD; ++lod) - { - LLVolumeImplFlexible::lodset_t::iterator itor = sLODBins[lod].begin(); - int bin_count = 0; - if (!new_objects_only) - { - timer.reset(); - double end_time = time_alloc[lod] * total_time_alloc; - for (; itor!=sLODBins[lod].end(); ++itor) - { - - (*itor)->doFlexibleUpdate(); - ++updated; - (*itor)->doFlexibleRebuild(); - ++bin_count; - ++regen; - if (timer.getElapsedTimeF64() > end_time) - { - break; - } - } - } - for (; itor != sLODBins[lod].end(); ++itor) - { - if ((*itor)->getLastUpdate() == 0) - { - // *Always* update newly-created objects, or objects which have changed LOD - (*itor)->doFlexibleUpdate(); - (*itor)->doFlexibleRebuild(); - ++newflexies; - } - } - } - } -} - void LLVolumeImplFlexible::doFlexibleUpdate() { LLPath *path = &mVO->getVolume()->getPath(); + if (mSimulateRes == 0) + { + mVO->markForUpdate(TRUE); + doIdleUpdate(gAgent, *gWorldp, 0.0); + } + S32 num_sections = 1 << mSimulateRes; F32 secondsThisFrame = mTimer.getElapsedTimeAndResetF32(); @@ -584,6 +506,10 @@ void LLVolumeImplFlexible::doFlexibleUpdate() // calculate velocity //------------------------------------------------------------------------------------------ mSection[i].mVelocity = mSection[i].mPosition - lastPosition; + if (mSection[i].mVelocity.magVecSquared() > 1.f) + { + mSection[i].mVelocity.normVec(); + } } // Calculate derivatives (not necessary until normals are automagically generated) @@ -624,11 +550,38 @@ void LLVolumeImplFlexible::doFlexibleUpdate() LLFlexibleObjectSection newSection[ (1<<FLEXIBLE_OBJECT_MAX_SECTIONS)+1 ]; remapSections(mSection, mSimulateRes, newSection, mRenderRes); + //generate transform from global to prim space + LLVector3 delta_scale = LLVector3(1,1,1); + LLVector3 delta_pos; + LLQuaternion delta_rot; + + delta_rot = ~getFrameRotation(); + delta_pos = -getFramePosition()*delta_rot; + + // Vertex transform (4x4) + LLVector3 x_axis = LLVector3(delta_scale.mV[VX], 0.f, 0.f) * delta_rot; + LLVector3 y_axis = LLVector3(0.f, delta_scale.mV[VY], 0.f) * delta_rot; + LLVector3 z_axis = LLVector3(0.f, 0.f, delta_scale.mV[VZ]) * delta_rot; + + LLMatrix4 rel_xform; + rel_xform.initRows(LLVector4(x_axis, 0.f), + LLVector4(y_axis, 0.f), + LLVector4(z_axis, 0.f), + LLVector4(delta_pos, 1.f)); + for (i=0; i<=num_render_sections; ++i) { new_point = &path->mPath[i]; - new_point->mPos = newSection[i].mPosition; - new_point->mRot = mSection[i].mAxisRotation * newSection[i].mRotation; + LLVector3 pos = newSection[i].mPosition * rel_xform; + LLQuaternion rot = mSection[i].mAxisRotation * newSection[i].mRotation * delta_rot; + + if (!mUpdated || (new_point->mPos-pos).magVecSquared() > 0.000001f) + { + new_point->mPos = newSection[i].mPosition * rel_xform; + mUpdated = FALSE; + } + + new_point->mRot = rot; new_point->mScale = newSection[i].mScale; new_point->mTexT = ((F32)i)/(num_render_sections); } @@ -639,13 +592,10 @@ void LLVolumeImplFlexible::doFlexibleUpdate() void LLVolumeImplFlexible::doFlexibleRebuild() { mVO->getVolume()->regen(); - - mVO->markForUpdate(TRUE); - mUpdated = TRUE; +} - mLastUpdate = sCurrentUpdateFrame; -}//------------------------------------------------------------------ +//------------------------------------------------------------------ void LLVolumeImplFlexible::onSetScale(const LLVector3& scale, BOOL damped) { @@ -654,8 +604,6 @@ void LLVolumeImplFlexible::onSetScale(const LLVector3& scale, BOOL damped) BOOL LLVolumeImplFlexible::doUpdateGeometry(LLDrawable *drawable) { - BOOL compiled = FALSE; - LLVOVolume *volume = (LLVOVolume*)mVO; if (volume->mDrawable.isNull()) // Not sure why this is happening, but it is... @@ -663,60 +611,26 @@ BOOL LLVolumeImplFlexible::doUpdateGeometry(LLDrawable *drawable) return TRUE; // No update to complete } - volume->calcAllTEsSame(); - - if (volume->mVolumeChanged || volume->mFaceMappingChanged) + if (volume->mLODChanged) { - compiled = TRUE; - volume->regenFaces(); - } - else if (volume->mLODChanged) - { - LLPointer<LLVolume> old_volumep, new_volumep; - F32 old_lod, new_lod; - - old_volumep = volume->getVolume(); - old_lod = old_volumep->getDetail(); - - LLVolumeParams volume_params = volume->getVolume()->getParams(); + LLVolumeParams volume_params = volume->getVolume()->getParams(); volume->setVolume(volume_params, 0); - doFlexibleUpdate(); - volume->getVolume()->regen(); - - new_volumep = volume->getVolume(); - new_lod = new_volumep->getDetail(); - - if (new_lod != old_lod) - { - compiled = TRUE; - if (new_volumep->getNumFaces() != old_volumep->getNumFaces()) - { - volume->regenFaces(); - } - } - } - - if (mUpdated) - { - compiled = TRUE; - mUpdated = FALSE; } - if(compiled) + volume->updateRelativeXform(); + doFlexibleUpdate(); + if (!mUpdated || volume->mFaceMappingChanged) { - volume->updateRelativeXform(isVolumeGlobal()); - volume->genTriangles(isVolumeGlobal()); - LLPipeline::sCompiles++; + doFlexibleRebuild(); + volume->genBBoxes(isVolumeGlobal()); } - + volume->mVolumeChanged = FALSE; volume->mLODChanged = FALSE; volume->mFaceMappingChanged = FALSE; // clear UV flag drawable->clearState(LLDrawable::UV); - - drawable->movePartition(); return TRUE; } @@ -792,42 +706,32 @@ LLQuaternion LLVolumeImplFlexible::getEndRotation() }//------------------------------------------------------------------ -void LLVolumeImplFlexible::updateRelativeXform(BOOL global_volume) +void LLVolumeImplFlexible::updateRelativeXform() { - LLVOVolume* vo = (LLVOVolume*) mVO; - - LLVector3 delta_scale = LLVector3(1,1,1); - LLVector3 delta_pos; LLQuaternion delta_rot; + LLVector3 delta_pos, delta_scale; + LLVOVolume* vo = (LLVOVolume*) mVO; + + //matrix from local space to parent relative/global space + delta_rot = vo->mDrawable->isSpatialRoot() ? LLQuaternion() : vo->mDrawable->getRotation(); + delta_pos = vo->mDrawable->isSpatialRoot() ? LLVector3(0,0,0) : vo->mDrawable->getPosition(); + delta_scale = LLVector3(1,1,1); - if (!mVO->mDrawable->isRoot()) - { //global to parent relative - LLViewerObject* parent = (LLViewerObject*) vo->getParent(); - delta_rot = ~parent->getRenderRotation(); - delta_pos = -parent->getRenderPosition()*delta_rot; - } - else - { //global to local - delta_rot = ~getFrameRotation(); - delta_pos = -getFramePosition()*delta_rot; - } - // Vertex transform (4x4) LLVector3 x_axis = LLVector3(delta_scale.mV[VX], 0.f, 0.f) * delta_rot; LLVector3 y_axis = LLVector3(0.f, delta_scale.mV[VY], 0.f) * delta_rot; LLVector3 z_axis = LLVector3(0.f, 0.f, delta_scale.mV[VZ]) * delta_rot; vo->mRelativeXform.initRows(LLVector4(x_axis, 0.f), - LLVector4(y_axis, 0.f), - LLVector4(z_axis, 0.f), - LLVector4(delta_pos, 1.f)); + LLVector4(y_axis, 0.f), + LLVector4(z_axis, 0.f), + LLVector4(delta_pos, 1.f)); x_axis.normVec(); y_axis.normVec(); z_axis.normVec(); vo->mRelativeXformInvTrans.setRows(x_axis, y_axis, z_axis); - } const LLMatrix4& LLVolumeImplFlexible::getWorldMatrix(LLXformMatrix* xform) const diff --git a/indra/newview/llflexibleobject.h b/indra/newview/llflexibleobject.h index 0d782d96ac..5a782bc617 100644 --- a/indra/newview/llflexibleobject.h +++ b/indra/newview/llflexibleobject.h @@ -57,6 +57,7 @@ class LLVolumeImplFlexible : public LLVolumeInterface LLVolumeImplFlexible(LLViewerObject* volume, LLFlexibleObjectData* attributes); // Implements LLVolumeInterface + U32 getID() const { return mID; } LLVector3 getFramePosition() const; LLQuaternion getFrameRotation() const; LLVolumeInterfaceType getInterfaceType() const { return INTERFACE_FLEXIBLE; } @@ -71,12 +72,10 @@ class LLVolumeImplFlexible : public LLVolumeInterface bool isVolumeGlobal() const { return true; } bool isActive() const { return true; } const LLMatrix4& getWorldMatrix(LLXformMatrix* xform) const; - void updateRelativeXform(BOOL global_volume = FALSE); + void updateRelativeXform(); void doFlexibleUpdate(); // Called to update the simulation void doFlexibleRebuild(); // Called to rebuild the geometry - static void resetUpdateBins(); - static void doFlexibleUpdateBins(); - + //void setAttributes( LLFlexibleObjectData ); void setParentPositionAndRotationDirectly( LLVector3 p, LLQuaternion r ); void setUsingCollisionSphere( bool u ); @@ -109,10 +108,7 @@ class LLVolumeImplFlexible : public LLVolumeInterface U32 mFrameNum; LLVector3 mCollisionSpherePosition; F32 mCollisionSphereRadius; - - U64 mLastUpdate; - - BOOL mJustShifted; + U32 mID; //-------------------------------------- // private methods @@ -121,29 +117,7 @@ class LLVolumeImplFlexible : public LLVolumeInterface void remapSections(LLFlexibleObjectSection *source, S32 source_sections, LLFlexibleObjectSection *dest, S32 dest_sections); - - U64 getLastUpdate() const { return mLastUpdate; } - - // LOD Bins - struct FlexCompare - { - bool operator()(LLVolumeImplFlexible* a, LLVolumeImplFlexible* b) const - { - U64 a_update = a->getLastUpdate(); - U64 b_update = b->getLastUpdate(); - if (a_update == b_update) - { - return a < b; // compare pointers - } - return a_update < b_update; - } - }; - typedef std::set<LLVolumeImplFlexible*, FlexCompare> lodset_t; - static lodset_t sLODBins[ FLEXIBLE_OBJECT_MAX_LOD ]; - static U64 sCurrentUpdateFrame; - static U32 sDebugInserted; - static U32 sDebugVisible; - + public: // Global setting for update rate static F32 sUpdateFactor; diff --git a/indra/newview/llfloateranimpreview.cpp b/indra/newview/llfloateranimpreview.cpp index 21248c7406..e37850c997 100644 --- a/indra/newview/llfloateranimpreview.cpp +++ b/indra/newview/llfloateranimpreview.cpp @@ -997,7 +997,7 @@ LLPreviewAnimation::LLPreviewAnimation(S32 width, S32 height) : LLDynamicTexture mDummyAvatar->updateGeometry(mDummyAvatar->mDrawable); mDummyAvatar->startMotion(ANIM_AGENT_STAND, 5.f); mDummyAvatar->mSkirtLOD.setVisible(FALSE, TRUE); - gPipeline.markVisible(mDummyAvatar->mDrawable); + gPipeline.markVisible(mDummyAvatar->mDrawable, *gCamera); // stop extraneous animations mDummyAvatar->stopMotion( ANIM_AGENT_HEAD_ROT, TRUE ); @@ -1073,6 +1073,10 @@ BOOL LLPreviewAnimation::render() avatarp->updateMotion(); } + LLVertexBuffer::stopRender(); + avatarp->updateLOD(); + LLVertexBuffer::startRender(); + avatarp->mRoot.updateWorldMatrixChildren(); stop_glerror(); @@ -1082,13 +1086,7 @@ BOOL LLPreviewAnimation::render() if (avatarp->mDrawable.notNull()) { LLDrawPoolAvatar *avatarPoolp = (LLDrawPoolAvatar *)avatarp->mDrawable->getFace(0)->getPool(); - gPipeline.unbindAGP(); - avatarPoolp->syncAGP(); - if (avatarPoolp->canUseAGP() && gPipeline.usingAGP()) - { - gPipeline.bindAGP(); - } - avatarPoolp->renderAvatars(avatarp, TRUE); // renders only one avatar (no shaders) + avatarPoolp->renderAvatars(avatarp); // renders only one avatar } return TRUE; diff --git a/indra/newview/llfloaterimagepreview.cpp b/indra/newview/llfloaterimagepreview.cpp index 1ae6decfdd..2e77bbcfbd 100644 --- a/indra/newview/llfloaterimagepreview.cpp +++ b/indra/newview/llfloaterimagepreview.cpp @@ -535,7 +535,7 @@ LLImagePreviewAvatar::LLImagePreviewAvatar(S32 width, S32 height) : LLDynamicTex mDummyAvatar->slamPosition(); mDummyAvatar->updateJointLODs(); mDummyAvatar->updateGeometry(mDummyAvatar->mDrawable); - gPipeline.markVisible(mDummyAvatar->mDrawable); + gPipeline.markVisible(mDummyAvatar->mDrawable, *gCamera); mTextureName = 0; } @@ -623,6 +623,10 @@ BOOL LLImagePreviewAvatar::render() gCamera->setView(gCamera->getDefaultFOV() / mCameraZoom); gCamera->setPerspective(FALSE, mOrigin.mX, mOrigin.mY, mWidth, mHeight, FALSE); + LLVertexBuffer::stopRender(); + avatarp->updateLOD(); + LLVertexBuffer::startRender(); + if (avatarp->mDrawable.notNull()) { LLGLDepthTest gls_depth(GL_TRUE, GL_TRUE); @@ -631,13 +635,7 @@ BOOL LLImagePreviewAvatar::render() LLDrawPoolAvatar *avatarPoolp = (LLDrawPoolAvatar *)avatarp->mDrawable->getFace(0)->getPool(); - gPipeline.unbindAGP(); - avatarPoolp->syncAGP(); - if (avatarPoolp->canUseAGP() && gPipeline.usingAGP()) - { - gPipeline.bindAGP(); - } - avatarPoolp->renderAvatars(avatarp, TRUE); // renders only one avatar (no shaders) + avatarPoolp->renderAvatars(avatarp); // renders only one avatar } return TRUE; diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp index 05047e1a4a..ac77b3c3f0 100644 --- a/indra/newview/llfloatersnapshot.cpp +++ b/indra/newview/llfloatersnapshot.cpp @@ -805,8 +805,10 @@ void LLFloaterSnapshot::Impl::updateLayout(LLFloaterSnapshot* floaterp) //RN: freeze all avatars LLCharacter* avatarp; - for (avatarp = LLCharacter::sInstances.getFirstData(); avatarp; avatarp = LLCharacter::sInstances.getNextData()) + for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin(); + iter != LLCharacter::sInstances.end(); ++iter) { + avatarp = *iter; sInstance->impl.mAvatarPauseHandles.push_back(avatarp->requestPause()); } diff --git a/indra/newview/llglsandbox.cpp b/indra/newview/llglsandbox.cpp index 2cb6db5a16..7a6b7b1bf3 100644 --- a/indra/newview/llglsandbox.cpp +++ b/indra/newview/llglsandbox.cpp @@ -162,15 +162,17 @@ void LLToolSelectRect::handleRectangleSelection(S32 x, S32 y, MASK mask) F32 select_dist_squared = gSavedSettings.getF32("MaxSelectDistance"); select_dist_squared = select_dist_squared * select_dist_squared; - x = llround((F32)x * LLUI::sGLScaleFactor.mV[VX]); - y = llround((F32)y * LLUI::sGLScaleFactor.mV[VY]); - BOOL deselect = (mask == MASK_CONTROL); S32 left = llmin(x, mDragStartX); S32 right = llmax(x, mDragStartX); S32 top = llmax(y, mDragStartY); S32 bottom =llmin(y, mDragStartY); + left = llround((F32) left * LLUI::sGLScaleFactor.mV[VX]); + right = llround((F32) right * LLUI::sGLScaleFactor.mV[VX]); + top = llround((F32) top * LLUI::sGLScaleFactor.mV[VY]); + bottom = llround((F32) bottom * LLUI::sGLScaleFactor.mV[VY]); + F32 old_far_plane = gCamera->getFar(); F32 old_near_plane = gCamera->getNear(); @@ -238,7 +240,7 @@ void LLToolSelectRect::handleRectangleSelection(S32 x, S32 y, MASK mask) continue; } - S32 result = gCamera->sphereInFrustum(drawable->getWorldPosition(), drawable->getRadius()); + S32 result = gCamera->sphereInFrustum(drawable->getPositionAgent(), drawable->getRadius()); switch (result) { case 0: @@ -261,11 +263,16 @@ void LLToolSelectRect::handleRectangleSelection(S32 x, S32 y, MASK mask) { std::vector<LLDrawable*> potentials; - if (gPipeline.mObjectPartition) + + for (U32 i = 0; i < LLPipeline::NUM_PARTITIONS-1; i++) { - gPipeline.mObjectPartition->cull(*gCamera, &potentials, TRUE); + LLSpatialPartition* part = gPipeline.getSpatialPartition(i); + if (part) + { + part->cull(*gCamera, &potentials, TRUE); + } } - + for (std::vector<LLDrawable*>::iterator iter = potentials.begin(); iter != potentials.end(); iter++) { @@ -285,7 +292,7 @@ void LLToolSelectRect::handleRectangleSelection(S32 x, S32 y, MASK mask) continue; } - S32 result = gCamera->sphereInFrustum(drawable->getWorldPosition(), drawable->getRadius()); + S32 result = gCamera->sphereInFrustum(drawable->getPositionAgent(), drawable->getRadius()); if (result) { switch (result) @@ -939,119 +946,6 @@ void LLViewerParcelMgr::renderCollisionSegments(U8* segments, BOOL use_pass, LLV glEnd(); } - -const S32 CLIENT_RECT_VPAD = 4; -void LLPreviewTexture::draw() -{ - if( getVisible() ) - { - updateAspectRatio(); - - LLPreview::draw(); - - if (!mMinimized) - { - LLGLSUIDefault gls_ui; - LLGLSNoTexture gls_notex; - - const LLRect& border = mClientRect; - LLRect interior = mClientRect; - interior.stretch( -PREVIEW_BORDER_WIDTH ); - - // ...border - gl_rect_2d( border, LLColor4(0.f, 0.f, 0.f, 1.f)); - gl_rect_2d_checkerboard( interior ); - - if ( mImage.notNull() ) - { - LLGLSTexture gls_no_texture; - // Draw the texture - glColor3f( 1.f, 1.f, 1.f ); - gl_draw_scaled_image(interior.mLeft, - interior.mBottom, - interior.getWidth(), - interior.getHeight(), - mImage); - - // Pump the texture priority - F32 pixel_area = mLoadingFullImage ? (F32)MAX_IMAGE_AREA : (F32)(interior.getWidth() * interior.getHeight() ); - mImage->addTextureStats( pixel_area ); - - // Don't bother decoding more than we can display, unless - // we're loading the full image. - if (!mLoadingFullImage) - { - S32 int_width = interior.getWidth(); - S32 int_height = interior.getHeight(); - mImage->setKnownDrawSize(int_width, int_height); - } - else - { - // Don't use this feature - mImage->setKnownDrawSize(0, 0); - } - - if( mLoadingFullImage ) - { - LLFontGL::sSansSerif->renderUTF8("Receiving:", 0, - interior.mLeft + 4, - interior.mBottom + 4, - LLColor4::white, LLFontGL::LEFT, LLFontGL::BOTTOM, - LLFontGL::DROP_SHADOW); - - F32 data_progress = 0.0f; - F32 decode_progress = mImage->getDecodeProgress(&data_progress); - - // Draw the progress bar. - const S32 BAR_HEIGHT = 12; - const S32 BAR_LEFT_PAD = 80; - S32 left = interior.mLeft + 4 + BAR_LEFT_PAD; - S32 bar_width = mRect.getWidth() - left - RESIZE_HANDLE_WIDTH - 2; - S32 top = interior.mBottom + 4 + BAR_HEIGHT; - S32 right = left + bar_width; - S32 bottom = top - BAR_HEIGHT; - - LLColor4 background_color(0.f, 0.f, 0.f, 0.75f); - LLColor4 decoded_color(0.f, 1.f, 0.f, 1.0f); - LLColor4 downloaded_color(0.f, 0.5f, 0.f, 1.0f); - - gl_rect_2d(left, top, right, bottom, background_color); - - if (data_progress > 0.0f) - { - // Decoded bytes - right = left + llfloor(decode_progress * (F32)bar_width); - - if (left < right) - { - gl_rect_2d(left, top, right, bottom, decoded_color); - } - - // Downloaded bytes - left = right; - right = left + llfloor((data_progress - decode_progress) * (F32)bar_width); - - if (left < right) - { - gl_rect_2d(left, top, right, bottom, downloaded_color); - } - } - } - else - if( !mSavedFileTimer.hasExpired() ) - { - LLFontGL::sSansSerif->renderUTF8("File Saved", 0, - interior.mLeft + 4, - interior.mBottom + 4, - LLColor4::white, LLFontGL::LEFT, LLFontGL::BOTTOM, - LLFontGL::DROP_SHADOW); - } - } - } - } -} - - void draw_line_cube(F32 width, const LLVector3& center) { width = 0.5f * width; diff --git a/indra/newview/llhudeffecttrail.cpp b/indra/newview/llhudeffecttrail.cpp index d76250d10a..05da40f214 100644 --- a/indra/newview/llhudeffecttrail.cpp +++ b/indra/newview/llhudeffecttrail.cpp @@ -156,7 +156,7 @@ void LLHUDEffectSpiral::triggerLocal() mKillTime = mTimer.getElapsedTimeF32() + mDuration; BOOL show_beam = gSavedSettings.getBOOL("ShowSelectionBeam"); - + LLColor4 color; color.setVec(mColor); @@ -250,20 +250,12 @@ void LLHUDEffectSpiral::setTargetObject(LLViewerObject *objp) void LLHUDEffectSpiral::render() { - if (!mSourceObject.isNull() && mSourceObject->isDead()) - { - markDead(); - return; - } - - if(!mTargetObject.isNull() && mTargetObject->isDead()) - { - markDead(); - return; - } - F32 time = mTimer.getElapsedTimeF32(); - if (mKillTime < time) + + if (!mSourceObject.isNull() && mSourceObject->isDead() || + !mTargetObject.isNull() && mTargetObject->isDead() || + mKillTime < time || + !gSavedSettings.getBOOL("ShowSelectionBeam")) { markDead(); return; diff --git a/indra/newview/llhudicon.cpp b/indra/newview/llhudicon.cpp index f2ab2dab11..02a3576dff 100644 --- a/indra/newview/llhudicon.cpp +++ b/indra/newview/llhudicon.cpp @@ -15,6 +15,7 @@ #include "llviewerobject.h" #include "lldrawable.h" #include "llviewercamera.h" +#include "llviewerimage.h" #include "llviewerwindow.h" //----------------------------------------------------------------------------- diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index f4280aae9c..f090cea5f2 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -3187,7 +3187,7 @@ void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attach rez_action->mItemID = item->getUUID(); rez_action->mAttachPt = gAgent.getAvatarObject()->mAttachmentPoints.reverseLookup(attachment); - if (attachment && attachment->getObject(0)) + if (attachment && attachment->getObject()) { gViewerWindow->alertXml("ReplaceAttachment", confirm_replace_attachment_rez, (void*)rez_action); } diff --git a/indra/newview/lljoystickbutton.h b/indra/newview/lljoystickbutton.h index 8b0a5665d4..8e0668ad8f 100644 --- a/indra/newview/lljoystickbutton.h +++ b/indra/newview/lljoystickbutton.h @@ -11,6 +11,7 @@ #include "llbutton.h" #include "llcoord.h" +#include "llviewerimage.h" typedef enum e_joystick_quadrant { diff --git a/indra/newview/llmaniprotate.cpp b/indra/newview/llmaniprotate.cpp index e9a6b1d1ba..5a52fc5b0a 100644 --- a/indra/newview/llmaniprotate.cpp +++ b/indra/newview/llmaniprotate.cpp @@ -445,11 +445,7 @@ BOOL LLManipRotate::handleMouseUp(S32 x, S32 y, MASK mask) mManipPart = LL_NO_PART; // Might have missed last update due to timing. - if (mSendUpdateOnMouseUp) - { - gSelectMgr->sendMultipleUpdate( UPD_ROTATION | UPD_POSITION ); - mSendUpdateOnMouseUp = FALSE; - } + gSelectMgr->sendMultipleUpdate( UPD_ROTATION | UPD_POSITION ); gSelectMgr->enableSilhouette(TRUE); //gAgent.setObjectTracking(gSavedSettings.getBOOL("TrackFocusObject")); @@ -505,12 +501,6 @@ extern U32 gFrameCount; // Freeform rotation void LLManipRotate::drag( S32 x, S32 y ) { - static LLTimer update_timer; - F32 elapsed_time = update_timer.getElapsedTimeF32(); - const F32 UPDATE_DELAY = 0.1f; // min time between transmitted updates - BOOL send_rotation_update = FALSE; - BOOL send_position_update = FALSE; - if( !updateVisiblity() ) { return; @@ -530,7 +520,6 @@ void LLManipRotate::drag( S32 x, S32 y ) LLViewerObject* object; LLSelectNode* selectNode; - BOOL using_linked_selection = gSavedSettings.getBOOL("SelectLinkedSet"); for( selectNode = mObjectSelection->getFirstNode(); selectNode != NULL; selectNode = mObjectSelection->getNextNode() ) { @@ -577,12 +566,6 @@ void LLManipRotate::drag( S32 x, S32 y ) rebuild(object); } - // don't send updates all the time for sub-objects - if (using_linked_selection && object->getRenderRotation() != new_rot) - { - send_rotation_update = TRUE; - } - // for individually selected roots, we need to counterrotate all the children if (object->isRootEdit() && selectNode->mIndividualSelection) { @@ -674,11 +657,6 @@ void LLManipRotate::drag( S32 x, S32 y ) } } - if (using_linked_selection && object->getPositionAgent() != new_position) - { - send_position_update = TRUE; - } - // for individually selected roots, we need to counter-translate all unselected children if (object->isRootEdit() && selectNode->mIndividualSelection) { @@ -709,27 +687,19 @@ void LLManipRotate::drag( S32 x, S32 y ) } } - if ((send_position_update || send_rotation_update) && (elapsed_time > UPDATE_DELAY)) + // store changes to override updates + for (LLSelectNode* selectNode = gSelectMgr->getSelection()->getFirstNode(); + selectNode != NULL; + selectNode = gSelectMgr->getSelection()->getNextNode()) { - U32 flag = UPD_NONE; - if (send_rotation_update) - { - flag |= UPD_ROTATION; - } - if (send_position_update) + LLViewerObject*cur = selectNode->getObject(); + if( cur->permModify() && cur->permMove() && !cur->isAvatar()) { - flag |= UPD_POSITION; + selectNode->mLastRotation = cur->getRotation(); + selectNode->mLastPositionLocal = cur->getPosition(); } + } - gSelectMgr->sendMultipleUpdate( flag ); - update_timer.reset(); - mSendUpdateOnMouseUp = FALSE; - } - else - { - mSendUpdateOnMouseUp = TRUE; - } - gSelectMgr->updateSelectionCenter(); // RN: just clear focus so camera doesn't follow spurious object updates diff --git a/indra/newview/llmanipscale.cpp b/indra/newview/llmanipscale.cpp index cec8ff0b13..56a4352e22 100644 --- a/indra/newview/llmanipscale.cpp +++ b/indra/newview/llmanipscale.cpp @@ -360,15 +360,27 @@ BOOL LLManipScale::handleMouseUp(S32 x, S32 y, MASK mask) // first, perform normal processing in case this was a quick-click handleHover(x, y, mask); + if( (LL_FACE_MIN <= (S32)mManipPart) + && ((S32)mManipPart <= LL_FACE_MAX) ) + { + sendUpdates(TRUE,TRUE,FALSE); + } + else + if( (LL_CORNER_MIN <= (S32)mManipPart) + && ((S32)mManipPart <= LL_CORNER_MAX) ) + { + sendUpdates(TRUE,TRUE,TRUE); + } + + //send texture update + gSelectMgr->adjustTexturesByScale(TRUE, getStretchTextures()); + gSelectMgr->enableSilhouette(TRUE); mManipPart = LL_NO_PART; // Might have missed last update due to UPDATE_DELAY timing - if (mSendUpdateOnMouseUp) - { - gSelectMgr->sendMultipleUpdate( mLastUpdateFlags ); - } - + gSelectMgr->sendMultipleUpdate( mLastUpdateFlags ); + //gAgent.setObjectTracking(gSavedSettings.getBOOL("TrackFocusObject")); gSelectMgr->saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK); return LLManip::handleMouseUp(x, y, mask); @@ -398,7 +410,7 @@ BOOL LLManipScale::handleHover(S32 x, S32 y, MASK mask) } // Patch up textures, if possible. - gSelectMgr->adjustTexturesByScale(TRUE, getStretchTextures()); + gSelectMgr->adjustTexturesByScale(FALSE, getStretchTextures()); gViewerWindow->getWindow()->setCursor(UI_CURSOR_TOOLSCALE); return TRUE; @@ -789,8 +801,21 @@ void LLManipScale::drag( S32 x, S32 y ) dragCorner( x, y ); } - //gAgent.setObjectTracking(FALSE); - gAgent.clearFocusObject(); + // store changes to override updates + for (LLSelectNode* selectNode = gSelectMgr->getSelection()->getFirstNode(); + selectNode != NULL; + selectNode = gSelectMgr->getSelection()->getNextNode()) + { + LLViewerObject*cur = selectNode->getObject(); + if( cur->permModify() && cur->permMove() && !cur->isAvatar()) + { + selectNode->mLastScale = cur->getScale(); + selectNode->mLastPositionLocal = cur->getPosition(); + } + } + + gSelectMgr->updateSelectionCenter(); + gAgent.clearFocusObject(); } // Scale around the @@ -801,10 +826,7 @@ void LLManipScale::dragCorner( S32 x, S32 y ) // Suppress scale if mouse hasn't moved. if (x == mLastMouseX && y == mLastMouseY) { - if (mSendUpdateOnMouseUp) - { - sendUpdates(TRUE,TRUE,TRUE); - } + // sendUpdates(TRUE,TRUE,TRUE); return; } @@ -1003,11 +1025,8 @@ void LLManipScale::dragCorner( S32 x, S32 y ) if (!selectNode->mIndividualSelection) { cur->setPosition(selectNode->mSavedPositionLocal * scale_factor); - continue; } - LLVector3d new_pos_global = drag_global + (selectNode->mSavedPositionGlobal - drag_global) * scale_factor; - cur->setPositionAbsoluteGlobal( new_pos_global ); rebuild(cur); } } @@ -1015,8 +1034,6 @@ void LLManipScale::dragCorner( S32 x, S32 y ) mDragPointGlobal = drag_point_global; - - sendUpdates( TRUE, TRUE, TRUE ); } @@ -1025,10 +1042,7 @@ void LLManipScale::dragFace( S32 x, S32 y ) // Suppress scale if mouse hasn't moved. if (x == mLastMouseX && y == mLastMouseY) { - if (mSendUpdateOnMouseUp) - { - sendUpdates(TRUE,TRUE,FALSE); - } + // sendUpdates(TRUE,TRUE,FALSE); return; } @@ -1162,8 +1176,6 @@ void LLManipScale::dragFace( S32 x, S32 y ) send_scale_update = TRUE; mDragPointGlobal = drag_point_global; - - sendUpdates( send_position_update, send_scale_update ); } void LLManipScale::sendUpdates( BOOL send_position_update, BOOL send_scale_update, BOOL corner ) @@ -1198,8 +1210,6 @@ void LLManipScale::sendUpdates( BOOL send_position_update, BOOL send_scale_updat { mSendUpdateOnMouseUp = TRUE; } - - gSelectMgr->updateSelectionCenter(); dialog_refresh_all(); } } diff --git a/indra/newview/llmaniptranslate.cpp b/indra/newview/llmaniptranslate.cpp index f308eb9f5c..93ae74db22 100644 --- a/indra/newview/llmaniptranslate.cpp +++ b/indra/newview/llmaniptranslate.cpp @@ -40,6 +40,7 @@ #include "llworld.h" #include "viewer.h" #include "llui.h" +#include "pipeline.h" const S32 NUM_AXES = 3; const S32 MOUSE_DRAG_SLOP = 2; // pixels @@ -404,6 +405,8 @@ BOOL LLManipTranslate::handleHover(S32 x, S32 y, MASK mask) } } + LLViewerObject *object; + // Suppress processing if mouse hasn't actually moved. // This may cause problems if the camera moves outside of the // rotation above. @@ -450,7 +453,6 @@ BOOL LLManipTranslate::handleHover(S32 x, S32 y, MASK mask) LLVector3 axis_f; LLVector3d axis_d; - LLViewerObject *object; // pick the first object to constrain to grid w/ common origin // this is so we don't screw up groups @@ -631,7 +633,7 @@ BOOL LLManipTranslate::handleHover(S32 x, S32 y, MASK mask) selectNode = mObjectSelection->getNextNode() ) { object = selectNode->getObject(); - + // Only apply motion to root objects and objects selected // as "individual". if (!object->isRootEdit() && !selectNode->mIndividualSelection) @@ -762,27 +764,12 @@ BOOL LLManipTranslate::handleHover(S32 x, S32 y, MASK mask) send_update = TRUE; } } + selectNode->mLastPositionLocal = object->getPosition(); } } - // Handle throttling to 10 updates per second. - F32 elapsed_time = mUpdateTimer.getElapsedTimeF32(); - const F32 UPDATE_DELAY = 0.1f; // min time between transmitted updates - if (send_update && (elapsed_time > UPDATE_DELAY)) - { - gSelectMgr->sendMultipleUpdate(UPD_POSITION); - mUpdateTimer.reset(); - mSendUpdateOnMouseUp = FALSE; - } - else - { - // ...suppressed update - mSendUpdateOnMouseUp = TRUE; - } - gSelectMgr->updateSelectionCenter(); gAgent.clearFocusObject(); - //gAgent.setObjectTracking(FALSE); dialog_refresh_all(); // ??? is this necessary? lldebugst(LLERR_USER_INPUT) << "hover handled by LLManipTranslate (active)" << llendl; @@ -1039,17 +1026,8 @@ BOOL LLManipTranslate::handleMouseUp(S32 x, S32 y, MASK mask) gSelectMgr->enableSilhouette(TRUE); // Might have missed last update due to UPDATE_DELAY timing. - if (mSendUpdateOnMouseUp) - { - gSelectMgr->sendMultipleUpdate( UPD_POSITION ); - mSendUpdateOnMouseUp = FALSE; - } - -// if (mCopyMadeThisDrag) -// { -// gSelectMgr->clearGridObjects(); -// } - + gSelectMgr->sendMultipleUpdate( UPD_POSITION ); + mInSnapRegime = FALSE; gSelectMgr->saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK); //gAgent.setObjectTracking(gSavedSettings.getBOOL("TrackFocusObject")); @@ -1122,6 +1100,30 @@ void LLManipTranslate::renderSnapGuides() //pick appropriate projection plane for snap rulers according to relative camera position if (mManipPart >= LL_X_ARROW && mManipPart <= LL_Z_ARROW) { + LLVector3 normal; + LLColor4 inner_color; + LLManip::EManipPart temp_manip = mManipPart; + switch (mManipPart) + { + case LL_X_ARROW: + normal.setVec(1,0,0); + inner_color.setVec(0,1,1,line_alpha); + mManipPart = LL_YZ_PLANE; + break; + case LL_Y_ARROW: + normal.setVec(0,1,0); + inner_color.setVec(1,0,1,line_alpha); + mManipPart = LL_XZ_PLANE; + break; + case LL_Z_ARROW: + normal.setVec(0,0,1); + inner_color.setVec(1,1,0,line_alpha); + mManipPart = LL_XY_PLANE; + break; + } + + highlightIntersection(normal, selection_center, grid_rotation, inner_color); + mManipPart = temp_manip; getManipAxis(first_object, mManipPart, translate_axis); LLVector3 at_axis_abs; @@ -1438,18 +1440,13 @@ void LLManipTranslate::renderSnapGuides() // render gridlines for planar snapping F32 u = 0, v = 0; - glPushMatrix(); - - F32 x,y,z,angle_radians; - grid_rotation.getAngleAxis(&angle_radians, &x, &y, &z); - glTranslatef(selection_center.mV[VX], selection_center.mV[VY], selection_center.mV[VZ]); - glRotatef(angle_radians * RAD_TO_DEG, x, y, z); - + LLColor4 inner_color; + LLVector3 normal; LLVector3 grid_center = selection_center - grid_origin; - grid_center *= ~grid_rotation; - F32 usc = 1; F32 vsc = 1; + + grid_center *= ~grid_rotation; switch (mManipPart) { @@ -1458,23 +1455,38 @@ void LLManipTranslate::renderSnapGuides() v = grid_center.mV[VZ]; usc = grid_scale.mV[VY]; vsc = grid_scale.mV[VZ]; + inner_color.setVec(0,1,1,line_alpha); + normal.setVec(1,0,0); break; case LL_XZ_PLANE: u = grid_center.mV[VX]; v = grid_center.mV[VZ]; usc = grid_scale.mV[VX]; vsc = grid_scale.mV[VZ]; + inner_color.setVec(1,0,1,line_alpha); + normal.setVec(0,1,0); break; case LL_XY_PLANE: u = grid_center.mV[VX]; v = grid_center.mV[VY]; usc = grid_scale.mV[VX]; vsc = grid_scale.mV[VY]; + inner_color.setVec(1,1,0,line_alpha); + normal.setVec(0,0,1); break; default: break; } + highlightIntersection(normal, selection_center, grid_rotation, inner_color); + + glPushMatrix(); + + F32 x,y,z,angle_radians; + grid_rotation.getAngleAxis(&angle_radians, &x, &y, &z); + glTranslatef(selection_center.mV[VX], selection_center.mV[VY], selection_center.mV[VZ]); + glRotatef(angle_radians * RAD_TO_DEG, x, y, z); + F32 sz = mGridSizeMeters; F32 tiles = sz; glMatrixMode(GL_TEXTURE); @@ -1591,6 +1603,104 @@ void LLManipTranslate::renderGrid(F32 x, F32 y, F32 size, F32 r, F32 g, F32 b, F } +void LLManipTranslate::highlightIntersection(LLVector3 normal, + LLVector3 selection_center, + LLQuaternion grid_rotation, + LLColor4 inner_color) +{ + if (!gSavedSettings.getBOOL("GridCrossSections")) + { + return; + } + + U32 types[] = { LLRenderPass::PASS_SIMPLE, LLRenderPass::PASS_ALPHA, LLRenderPass::PASS_FULLBRIGHT }; + + GLuint stencil_mask = 0xFFFFFFFF; + //stencil in volumes + { + glStencilMask(stencil_mask); + glClearStencil(1); + glClear(GL_STENCIL_BUFFER_BIT); + LLGLEnable cull_face(GL_CULL_FACE); + LLGLEnable stencil(GL_STENCIL_TEST); + LLGLDepthTest depth (GL_TRUE, GL_FALSE, GL_ALWAYS); + glStencilFunc(GL_ALWAYS, 0, stencil_mask); + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + LLGLDisable tex(GL_TEXTURE_2D); + glColor4f(1,1,1,1); + + //setup clip plane + normal = normal * grid_rotation; + if (normal * (gCamera->getOrigin()-selection_center) < 0) + { + normal = -normal; + } + F32 d = -(selection_center * normal); + F64 plane[] = { normal.mV[0], normal.mV[1], normal.mV[2], d }; + LLGLEnable clip(GL_CLIP_PLANE0); + glClipPlane(GL_CLIP_PLANE0, plane); + + BOOL particles = gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES); + BOOL clouds = gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_CLOUDS); + + if (particles) + { + LLPipeline::toggleRenderType(LLPipeline::RENDER_TYPE_PARTICLES); + } + if (clouds) + { + LLPipeline::toggleRenderType(LLPipeline::RENDER_TYPE_CLOUDS); + } + + //stencil in volumes + glStencilOp(GL_INCR, GL_INCR, GL_INCR); + glCullFace(GL_FRONT); + for (U32 i = 0; i < 3; i++) + { + gPipeline.renderObjects(types[i], LLVertexBuffer::MAP_VERTEX, FALSE); + } + + glStencilOp(GL_DECR, GL_DECR, GL_DECR); + glCullFace(GL_BACK); + for (U32 i = 0; i < 3; i++) + { + gPipeline.renderObjects(types[i], LLVertexBuffer::MAP_VERTEX, FALSE); + } + + if (particles) + { + LLPipeline::toggleRenderType(LLPipeline::RENDER_TYPE_PARTICLES); + } + if (clouds) + { + LLPipeline::toggleRenderType(LLPipeline::RENDER_TYPE_CLOUDS); + } + + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + } + + glPushMatrix(); + + F32 x,y,z,angle_radians; + grid_rotation.getAngleAxis(&angle_radians, &x, &y, &z); + glTranslatef(selection_center.mV[VX], selection_center.mV[VY], selection_center.mV[VZ]); + glRotatef(angle_radians * RAD_TO_DEG, x, y, z); + + F32 sz = mGridSizeMeters; + F32 tiles = sz; + + //draw volume/plane intersections + { + LLGLDisable tex(GL_TEXTURE_2D); + LLGLDepthTest depth(GL_FALSE); + LLGLEnable stencil(GL_STENCIL_TEST); + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + glStencilFunc(GL_EQUAL, 0, stencil_mask); + renderGrid(0,0,tiles,inner_color.mV[0], inner_color.mV[1], inner_color.mV[2], 0.25f); + } + + glPopMatrix(); +} void LLManipTranslate::renderText() { diff --git a/indra/newview/llmaniptranslate.h b/indra/newview/llmaniptranslate.h index 5a93c0a24f..6a317cabcd 100644 --- a/indra/newview/llmaniptranslate.h +++ b/indra/newview/llmaniptranslate.h @@ -58,6 +58,10 @@ protected: void renderSnapGuides(); void renderGrid(F32 x, F32 y, F32 size, F32 r, F32 g, F32 b, F32 a); void renderGridVert(F32 x_trans, F32 y_trans, F32 r, F32 g, F32 b, F32 alpha); + void highlightIntersection(LLVector3 normal, + LLVector3 selection_center, + LLQuaternion grid_rotation, + LLColor4 inner_color); F32 getMinGridScale(); private: diff --git a/indra/newview/llmemoryview.cpp b/indra/newview/llmemoryview.cpp index 5edb373cbb..7fd2572e08 100644 --- a/indra/newview/llmemoryview.cpp +++ b/indra/newview/llmemoryview.cpp @@ -16,6 +16,7 @@ #include "llgl.h" #include "llmath.h" #include "llfontgl.h" +#include "llmemtype.h" #include "viewer.h" #include "llui.h" @@ -95,6 +96,7 @@ static struct mtv_display_info mtv_display_table[] = { LLMemType::MTYPE_PIPELINE, "Pipeline", &LLColor4::green3 }, { LLMemType::MTYPE_PARTICLES, "Particles", &LLColor4::green4 }, { LLMemType::MTYPE_SPACE_PARTITION, "Space Partition", &LLColor4::blue2 }, + { LLMemType::MTYPE_VERTEX_DATA, "Vertex Buffer", &LLColor4::blue3 }, { LLMemType::MTYPE_AVATAR, "Avatar", &LLColor4::purple1 }, { LLMemType::MTYPE_REGIONS, "Regions", &LLColor4::blue1 }, { LLMemType::MTYPE_TEMP1, "Temp1", &LLColor4::red1 }, diff --git a/indra/newview/llpanelpick.cpp b/indra/newview/llpanelpick.cpp index ab2a298a06..c13d76886f 100644 --- a/indra/newview/llpanelpick.cpp +++ b/indra/newview/llpanelpick.cpp @@ -487,8 +487,11 @@ void LLPanelPick::onCommitAny(LLUICtrl* ctrl, void* data) } else {*/ - LLTabContainerVertical* tab = (LLTabContainerVertical*)self->getParent(); + LLTabContainerVertical* tab = (LLTabContainerVertical*)self->getParent(); + if (tab) + { if(tab) tab->setCurrentTabName(self->mNameEditor->getText()); + } //} } } diff --git a/indra/newview/llpolymesh.cpp b/indra/newview/llpolymesh.cpp index 76769c6c7c..e818170ed2 100644 --- a/indra/newview/llpolymesh.cpp +++ b/indra/newview/llpolymesh.cpp @@ -1056,10 +1056,10 @@ BOOL LLPolySkeletalDistortion::setInfo(LLPolySkeletalDistortionInfo *info) mJointScales[joint] = bone_info->mScaleDeformation; // apply to children that need to inherit it - for ( LLViewerJoint *child_joint = (LLViewerJoint *)joint->mChildren.getFirstData(); - child_joint != NULL; - child_joint = (LLViewerJoint *)joint->mChildren.getNextData() ) + for (LLJoint::child_list_t::iterator iter = joint->mChildren.begin(); + iter != joint->mChildren.end(); ++iter) { + LLViewerJoint* child_joint = (LLViewerJoint*)(*iter); if (child_joint->inheritScale()) { LLVector3 childDeformation = LLVector3(child_joint->getScale()); diff --git a/indra/newview/llpolymesh.h b/indra/newview/llpolymesh.h index cefda92288..2874f11798 100644 --- a/indra/newview/llpolymesh.h +++ b/indra/newview/llpolymesh.h @@ -305,6 +305,7 @@ public: U32 mFaceVertexOffset; U32 mFaceVertexCount; + U32 mFaceIndexOffset; U32 mFaceIndexCount; U32 mCurVertexCount; private: diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp index f6b9f0e018..479f1b1812 100644 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -1453,9 +1453,9 @@ void LLLiveLSLEditor::onLoadComplete(LLVFS *vfs, const LLUUID& asset_id, if( LLLiveLSLEditor::sInstances.checkData(*xored_id) ) { + instance = LLLiveLSLEditor::sInstances[*xored_id]; if( LL_ERR_NOERR == status ) { - instance = LLLiveLSLEditor::sInstances[*xored_id]; instance->loadScriptText(vfs, asset_id, type); instance->mAssetStatus = PREVIEW_ASSET_LOADED; } diff --git a/indra/newview/llpreviewtexture.cpp b/indra/newview/llpreviewtexture.cpp index 95973a102e..4b7be3701b 100644 --- a/indra/newview/llpreviewtexture.cpp +++ b/indra/newview/llpreviewtexture.cpp @@ -10,19 +10,20 @@ #include "llpreviewtexture.h" -#include "llviewerimage.h" -#include "llviewerimagelist.h" -#include "llresmgr.h" #include "llagent.h" #include "llbutton.h" -#include "llui.h" +#include "llfilepicker.h" +#include "llimagetga.h" #include "llinventoryview.h" #include "llinventory.h" -#include "llviewerwindow.h" +#include "llresmgr.h" #include "lltextbox.h" -#include "llimagetga.h" -#include "llfilepicker.h" +#include "lltextureview.h" +#include "llui.h" +#include "llviewerimage.h" +#include "llviewerimagelist.h" #include "llvieweruictrlfactory.h" +#include "llviewerwindow.h" #include "lllineeditor.h" const S32 PREVIEW_TEXTURE_MIN_WIDTH = 300; @@ -167,6 +168,105 @@ void LLPreviewTexture::init() } } +void LLPreviewTexture::draw() +{ + if( getVisible() ) + { + updateAspectRatio(); + + LLPreview::draw(); + + if (!mMinimized) + { + LLGLSUIDefault gls_ui; + LLGLSNoTexture gls_notex; + + const LLRect& border = mClientRect; + LLRect interior = mClientRect; + interior.stretch( -PREVIEW_BORDER_WIDTH ); + + // ...border + gl_rect_2d( border, LLColor4(0.f, 0.f, 0.f, 1.f)); + gl_rect_2d_checkerboard( interior ); + + if ( mImage.notNull() ) + { + LLGLSTexture gls_no_texture; + // Draw the texture + glColor3f( 1.f, 1.f, 1.f ); + gl_draw_scaled_image(interior.mLeft, + interior.mBottom, + interior.getWidth(), + interior.getHeight(), + mImage); + + // Pump the texture priority + F32 pixel_area = mLoadingFullImage ? (F32)MAX_IMAGE_AREA : (F32)(interior.getWidth() * interior.getHeight() ); + mImage->addTextureStats( pixel_area ); + + // Don't bother decoding more than we can display, unless + // we're loading the full image. + if (!mLoadingFullImage) + { + S32 int_width = interior.getWidth(); + S32 int_height = interior.getHeight(); + mImage->setKnownDrawSize(int_width, int_height); + } + else + { + // Don't use this feature + mImage->setKnownDrawSize(0, 0); + } + + if( mLoadingFullImage ) + { + LLFontGL::sSansSerif->renderUTF8("Receiving:", 0, + interior.mLeft + 4, + interior.mBottom + 4, + LLColor4::white, LLFontGL::LEFT, LLFontGL::BOTTOM, + LLFontGL::DROP_SHADOW); + + F32 data_progress = mImage->mDownloadProgress; + + // Draw the progress bar. + const S32 BAR_HEIGHT = 12; + const S32 BAR_LEFT_PAD = 80; + S32 left = interior.mLeft + 4 + BAR_LEFT_PAD; + S32 bar_width = mRect.getWidth() - left - RESIZE_HANDLE_WIDTH - 2; + S32 top = interior.mBottom + 4 + BAR_HEIGHT; + S32 right = left + bar_width; + S32 bottom = top - BAR_HEIGHT; + + LLColor4 background_color(0.f, 0.f, 0.f, 0.75f); + LLColor4 decoded_color(0.f, 1.f, 0.f, 1.0f); + LLColor4 downloaded_color(0.f, 0.5f, 0.f, 1.0f); + + gl_rect_2d(left, top, right, bottom, background_color); + + if (data_progress > 0.0f) + { + // Downloaded bytes + right = left + llfloor(data_progress * (F32)bar_width); + if (right > left) + { + gl_rect_2d(left, top, right, bottom, downloaded_color); + } + } + } + else + if( !mSavedFileTimer.hasExpired() ) + { + LLFontGL::sSansSerif->renderUTF8("File Saved", 0, + interior.mLeft + 4, + interior.mBottom + 4, + LLColor4::white, LLFontGL::LEFT, LLFontGL::BOTTOM, + LLFontGL::DROP_SHADOW); + } + } + } + } +} + // virtual BOOL LLPreviewTexture::canSaveAs() diff --git a/indra/newview/llprogressview.cpp b/indra/newview/llprogressview.cpp index 2faa9ba351..1172bd8cf0 100644 --- a/indra/newview/llprogressview.cpp +++ b/indra/newview/llprogressview.cpp @@ -20,8 +20,9 @@ #include "llglheaders.h" #include "llagent.h" -#include "llfocusmgr.h" #include "llbutton.h" +#include "llfocusmgr.h" +#include "llstartup.h" #include "llviewercontrol.h" #include "llviewerimagelist.h" #include "llviewerwindow.h" @@ -29,9 +30,8 @@ LLProgressView* LLProgressView::sInstance = NULL; -LLPointer<LLImageGL> gStartImageGL = NULL; -S32 gStartImageWidth = 1; -S32 gStartImageHeight = 1; +S32 gStartImageWidth = 1; +S32 gStartImageHeight = 1; const F32 FADE_IN_TIME = 1.f; const LLString ANIMATION_FILENAME = "Login Sequence "; diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index c4e166d68d..27cf29cee0 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -196,6 +196,34 @@ void LLSelectMgr::updateEffects() } } +void LLSelectMgr::overrideObjectUpdates() +{ + //override any position updates from simulator on objects being edited + LLSelectNode* selectNode; + for (selectNode = gSelectMgr->getSelection()->getFirstNode(); + selectNode != NULL; + selectNode = gSelectMgr->getSelection()->getNextNode()) + { + LLViewerObject* object = selectNode->getObject(); + + if (object->permMove()) + { + if (!selectNode->mLastPositionLocal.isExactlyZero()) + { + object->setPosition(selectNode->mLastPositionLocal); + } + if (selectNode->mLastRotation != LLQuaternion()) + { + object->setRotation(selectNode->mLastRotation); + } + if (!selectNode->mLastScale.isExactlyZero()) + { + object->setScale(selectNode->mLastScale); + } + } + } +} + //----------------------------------------------------------------------------- // Select just the object, not any other group members. //----------------------------------------------------------------------------- @@ -3520,7 +3548,8 @@ void LLSelectMgr::sendAttach(U8 attachment_point) BOOL build_mode = gToolMgr->inEdit(); // Special case: Attach to default location for this object. - if (0 == attachment_point) + if (0 == attachment_point || + gAgent.getAvatarObject()->mAttachmentPoints.getIfThere(attachment_point)) { sendListToRegions( "ObjectAttach", @@ -3533,48 +3562,6 @@ void LLSelectMgr::sendAttach(U8 attachment_point) deselectAll(); } } - else - { - LLViewerJointAttachment* attachment = gAgent.getAvatarObject()->mAttachmentPoints.getIfThere(attachment_point); - if (attachment) - { - LLQuaternion object_world_rot = attach_object->getRenderRotation(); - LLQuaternion attachment_pt__world_rot = attachment->getWorldRotation(); - LLQuaternion local_rot = object_world_rot * ~attachment_pt__world_rot; - - F32 x,y,z; - local_rot.getEulerAngles(&x, &y, &z); - // snap to nearest 90 degree rotation - // make sure all euler angles are positive - if (x < F_PI_BY_TWO) x += F_TWO_PI; - if (y < F_PI_BY_TWO) y += F_TWO_PI; - if (z < F_PI_BY_TWO) z += F_TWO_PI; - - // add 45 degrees so that rounding down becomes rounding off - x += F_PI_BY_TWO / 2.f; - y += F_PI_BY_TWO / 2.f; - z += F_PI_BY_TWO / 2.f; - // round down to nearest multiple of 90 degrees - x -= fmodf(x, F_PI_BY_TWO); - y -= fmodf(y, F_PI_BY_TWO); - z -= fmodf(z, F_PI_BY_TWO); - - // pass the requested rotation on to the simulator - local_rot.setQuat(x, y, z); - attach_object->setRotation(local_rot); - - sendListToRegions( - "ObjectAttach", - packAgentIDAndSessionAndAttachment, - packObjectIDAndRotation, - &attachment_point, - SEND_ONLY_ROOTS ); - if (!build_mode) - { - deselectAll(); - } - } - } } void LLSelectMgr::sendDetach() @@ -3764,7 +3751,10 @@ void LLSelectMgr::saveSelectedObjectTransform(EActionType action_type) if (object->isRootEdit()) { LLXform* parent_xform = object->mDrawable->getXform()->getParent(); - selectNode->mSavedPositionGlobal = gAgent.getPosGlobalFromAgent((object->getPosition() * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition()); + if (parent_xform) + { + selectNode->mSavedPositionGlobal = gAgent.getPosGlobalFromAgent((object->getPosition() * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition()); + } } else { @@ -4065,6 +4055,17 @@ void LLSelectMgr::sendListToRegions(const LLString& message_name, S32 packets_sent = 0; S32 objects_in_this_packet = 0; + + //clear update override data (allow next update through) + for (node = mSelectedObjects->getFirstNode(); + node; + node = mSelectedObjects->getNextNode()) + { + node->mLastPositionLocal.setVec(0,0,0); + node->mLastRotation = LLQuaternion(); + node->mLastScale.setVec(0,0,0); + } + std::queue<LLSelectNode*> nodes_to_send; switch(send_type) @@ -4583,7 +4584,7 @@ void LLSelectMgr::updateSilhouettes() || objectp->isChanged(LLXform::SILHOUETTE) || (objectp->getParent() && objectp->getParent()->isChanged(LLXform::SILHOUETTE))) { - if (num_sils_genned++ < MAX_SILS_PER_FRAME && objectp->mDrawable->isVisible()) + if (num_sils_genned++ < MAX_SILS_PER_FRAME)// && objectp->mDrawable->isVisible()) { generateSilhouette(node, gCamera->getOrigin()); changed_objects.put(objectp); @@ -4816,7 +4817,6 @@ void LLSelectMgr::renderSilhouettes(BOOL for_hud) } if (mSelectedObjects->getNumNodes()) { - glPushAttrib(GL_FOG_BIT); LLUUID inspect_item_id = LLFloaterInspect::getSelectedUUID(); for (S32 pass = 0; pass < 2; pass++) { @@ -4848,7 +4848,6 @@ void LLSelectMgr::renderSilhouettes(BOOL for_hud) } } } - glPopAttrib(); } if (mHighlightedObjects->getNumNodes()) @@ -5266,12 +5265,7 @@ void LLSelectNode::renderOneSilhouette(const LLColor4 &color) } BOOL is_hud_object = objectp->isHUDAttachment(); - - if (!drawable->isVisible() && !is_hud_object) - { - return; - } - + if (mSilhouetteVertices.size() == 0 || mSilhouetteNormals.size() != mSilhouetteVertices.size()) { return; @@ -5302,7 +5296,7 @@ void LLSelectNode::renderOneSilhouette(const LLColor4 &color) else { LLVector3 view_vector = gCamera->getOrigin() - objectp->getRenderPosition(); - silhouette_thickness = drawable->mDistanceWRTCamera * LLSelectMgr::sHighlightThickness * (gCamera->getView() / gCamera->getDefaultFOV()); + silhouette_thickness = view_vector.magVec() * LLSelectMgr::sHighlightThickness * (gCamera->getView() / gCamera->getDefaultFOV()); } F32 animationTime = (F32)LLFrameTimer::getElapsedSeconds(); @@ -5328,7 +5322,6 @@ void LLSelectNode::renderOneSilhouette(const LLColor4 &color) S32 i = 0; for (S32 seg_num = 0; seg_num < (S32)mSilhouetteSegments.size(); seg_num++) { -// S32 first_i = i; for(; i < mSilhouetteSegments[seg_num]; i++) { u_coord += u_divisor * LLSelectMgr::sHighlightUScale; @@ -5337,11 +5330,6 @@ void LLSelectNode::renderOneSilhouette(const LLColor4 &color) glTexCoord2f( u_coord, v_coord ); glVertex3fv( mSilhouetteVertices[i].mV ); } - - /*u_coord += u_divisor * LLSelectMgr::sHighlightUScale; - glColor4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], 0.4f); - glTexCoord2f( u_coord, v_coord ); - glVertex3fv( mSilhouetteVertices[first_i].mV );*/ } } glEnd(); @@ -5349,7 +5337,6 @@ void LLSelectNode::renderOneSilhouette(const LLColor4 &color) } glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - //glAlphaFunc(GL_GREATER, LLSelectMgr::sHighlightAlphaTest); glBegin(GL_TRIANGLES); { S32 i = 0; @@ -5468,6 +5455,10 @@ void LLSelectMgr::updateSelectionCenter() const F32 MOVE_SELECTION_THRESHOLD = 1.f; // Movement threshold in meters for updating selection // center (tractor beam) + //override any object updates received + //for selected objects + gSelectMgr->overrideObjectUpdates(); + LLViewerObject* object = mSelectedObjects->getFirstObject(); if (!object) { diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h index 2b1568fb45..c0ddad41eb 100644 --- a/indra/newview/llselectmgr.h +++ b/indra/newview/llselectmgr.h @@ -210,6 +210,7 @@ public: virtual BOOL canDuplicate(); void updateEffects(); // Update HUD effects + void overrideObjectUpdates(); void setForceSelection(BOOL force) { mForceSelection = force; } @@ -580,9 +581,12 @@ public: LLCategory mCategory; S16 mInventorySerial; LLVector3 mSavedPositionLocal; // for interactively modifying object position + LLVector3 mLastPositionLocal; LLVector3d mSavedPositionGlobal; // for interactively modifying object position LLVector3 mSavedScale; // for interactively modifying object scale + LLVector3 mLastScale; LLQuaternion mSavedRotation; // for interactively modifying object rotation + LLQuaternion mLastRotation; BOOL mDuplicated; LLVector3d mDuplicatePos; LLQuaternion mDuplicateRot; diff --git a/indra/newview/llsky.cpp b/indra/newview/llsky.cpp index 022f02c57e..02f3855ace 100644 --- a/indra/newview/llsky.cpp +++ b/indra/newview/llsky.cpp @@ -347,7 +347,7 @@ void LLSky::updateCull() if (mVOStarsp.notNull() && mVOStarsp->mDrawable.notNull()) { - gPipeline.markVisible(mVOStarsp->mDrawable); + gPipeline.markVisible(mVOStarsp->mDrawable, *gCamera); } else { @@ -372,10 +372,10 @@ void LLSky::updateSky() } if (mVOStarsp) { - if (mVOStarsp->mDrawable) - { - gPipeline.markRebuild(mVOStarsp->mDrawable, LLDrawable::REBUILD_VOLUME, TRUE); - } + //if (mVOStarsp->mDrawable) + //{ + // gPipeline.markRebuild(mVOStarsp->mDrawable, LLDrawable::REBUILD_VOLUME, TRUE); + //} } } diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index 8b5db02c85..739d30bfe6 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -10,25 +10,21 @@ #include "llspatialpartition.h" -#include "llglheaders.h" - +#include "llviewerwindow.h" #include "llviewerobjectlist.h" #include "llvovolume.h" #include "llviewercamera.h" #include "llface.h" #include "viewer.h" - +#include "llagent.h" +#include "llviewerregion.h" #include "llcamera.h" #include "pipeline.h" -static BOOL sIgnoreOcclusion = TRUE; static GLuint sBoxList = 0; -const S32 SG_LOD_SWITCH_STAGGER = 4; -const F32 SG_MAX_OBJ_RAD = 1.f; -const F32 SG_OCCLUSION_FUDGE = 1.1f; -const S32 SG_MOVE_PERIOD = 32; -const S32 SG_LOD_PERIOD = 16; +const F32 SG_OCCLUSION_FUDGE = 1.01f; +//const S32 SG_LOD_PERIOD = 16; #define SG_DISCARD_TOLERANCE 0.25f @@ -38,11 +34,12 @@ const S32 SG_LOD_PERIOD = 16; #define assert_octree_valid(x) #endif +static U32 sZombieGroups = 0; + static F32 sLastMaxTexPriority = 1.f; static F32 sCurMaxTexPriority = 1.f; //static counter for frame to switch LOD on -S32 LLSpatialGroup::sLODSeed = 0; void sg_assert(BOOL expr) { @@ -125,25 +122,22 @@ S32 LLSphereAABB(const LLVector3& center, const LLVector3& size, const LLVector3 LLSpatialGroup::~LLSpatialGroup() { - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - if (!safeToDelete()) + if (isState(DEAD)) { -#ifdef LL_RELEASE_FOR_DOWNLOAD - llwarns << "Spatial Group deleted while being tracked " << ((void*) mState) << llendl; -#else - llerrs << "Spatial Group deleted while being tracked " << ((void*) mState) << llendl; -#endif + sZombieGroups--; } -#if LL_OCTREE_PARANOIA_CHECK - for (U32 i = 0; i < mSpatialPartition->mOccludedList.size(); i++) + LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); + clearDrawMap(); +} + +void LLSpatialGroup::clearDrawMap() +{ + for (LLSpatialGroup::draw_map_t::iterator i = mDrawMap.begin(); i != mDrawMap.end(); ++i) { - if (mSpatialPartition->mOccludedList[i] == this) - { - llerrs << "Spatial Group deleted while being tracked STATE ERROR " << ((void*) mState) << llendl; - } + std::for_each(i->second.begin(), i->second.end(), DeletePointer()); } -#endif + mDrawMap.clear(); } BOOL LLSpatialGroup::safeToDelete() @@ -193,13 +187,13 @@ public: BOOL LLSpatialGroup::isVisible() { - if (sIgnoreOcclusion) + if (LLPipeline::sUseOcclusion) { - return !isState(CULLED); + return !isState(CULLED | OCCLUDED); } else { - return !isState(CULLED | OCCLUDED); + return !isState(CULLED); } } @@ -235,6 +229,88 @@ void LLSpatialGroup::validate() #endif } +void validate_draw_info(LLDrawInfo& params) +{ +#if LL_DEBUG +/* if (params.mVertexBuffer.isNull()) + { + llerrs << "Draw batch has no vertex buffer." << llendl; + } + + //bad range + if (params.mStart >= params.mEnd) + { + llerrs << "Draw batch has invalid range." << llendl; + } + + if (params.mEnd >= params.mVertexBuffer->getNumVerts()) + { + llerrs << "Draw batch has buffer overrun error." << llendl; + } + + if (params.mOffset + params.mCount > params.mVertexBuffer->getNumIndices()) + { + llerrs << "Draw batch has index buffer ovverrun error." << llendl; + } + + //bad indices + U32* indicesp = (U32*) params.mVertexBuffer->getIndicesPointer(); + if (indicesp) + { + for (U32 i = params.mOffset; i < params.mOffset+params.mCount; i++) + { + if (indicesp[i] < params.mStart) + { + llerrs << "Draw batch has vertex buffer index out of range error (index too low)." << llendl; + } + + if (indicesp[i] > params.mEnd) + { + llerrs << "Draw batch has vertex buffer index out of range error (index too high)." << llendl; + } + } + }*/ +#endif +} + +void LLSpatialGroup::validateDrawMap() +{ +/* for (draw_map_t::iterator i = mDrawMap.begin(); i != mDrawMap.end(); ++i) + { + std::vector<LLDrawInfo*>& draw_vec = i->second; + for (std::vector<LLDrawInfo*>::iterator j = draw_vec.begin(); j != draw_vec.end(); ++j) + { + LLDrawInfo& params = **j; + + validate_draw_info(params); + } + }*/ +} + +void LLSpatialGroup::makeStatic() +{ + if (isState(GEOM_DIRTY | ALPHA_DIRTY)) + { + return; + } + + if (mSpatialPartition->mRenderByGroup && mBufferUsage != GL_STATIC_DRAW_ARB) + { + mBufferUsage = GL_STATIC_DRAW_ARB; + if (mVertexBuffer.notNull()) + { + mVertexBuffer->makeStatic(); + } + + for (buffer_map_t::iterator i = mBufferMap.begin(); i != mBufferMap.end(); ++i) + { + i->second->makeStatic(); + } + + mBuilt = 1.f; + } +} + BOOL LLSpatialGroup::updateInGroup(LLDrawable *drawablep, BOOL immediate) { LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); @@ -246,6 +322,8 @@ BOOL LLSpatialGroup::updateInGroup(LLDrawable *drawablep, BOOL immediate) { unbound(); setState(OBJECT_DIRTY); + setState(GEOM_DIRTY); + gPipeline.markRebuild(this); validate_drawable(drawablep); return TRUE; } @@ -265,11 +343,83 @@ BOOL LLSpatialGroup::addObject(LLDrawable *drawablep, BOOL add_all, BOOL from_oc { drawablep->setSpatialGroup(this, 0); validate_drawable(drawablep); + setState(OBJECT_DIRTY | GEOM_DIRTY); + gPipeline.markRebuild(this); + mLastAddTime = gFrameTimeSeconds; + if (drawablep->isSpatialBridge()) + { + mBridgeList.push_back((LLSpatialBridge*) drawablep); + } + setState(IMAGE_DIRTY); } return TRUE; } +void LLSpatialGroup::rebuildGeom() +{ + LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); + if (!isDead()) + { + mSpatialPartition->rebuildGeom(this); + } +} + +void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group) +{ + if (group->changeLOD()) + { + group->mLastUpdateDistance = group->mDistance; + group->mLastUpdateViewAngle = group->mViewAngle; + } + + if (group->isDead() || !group->isState(LLSpatialGroup::GEOM_DIRTY)) + { + return; + } + + LLFastTimer ftm(LLFastTimer::FTM_REBUILD_VBO); + + group->clearDrawMap(); + + //get geometry count + group->mIndexCount = 0; + group->mVertexCount = 0; + + addGeometryCount(group, group->mVertexCount, group->mIndexCount); + + if (group->mVertexCount > 0 && group->mIndexCount > 0) + { //create vertex buffer containing volume geometry for this node + group->mBuilt = 1.f; + if (group->mVertexBuffer.isNull() || (group->mBufferUsage != group->mVertexBuffer->getUsage() && LLVertexBuffer::sEnableVBOs)) + { + //LLFastTimer ftm(LLFastTimer::FTM_REBUILD_NONE_VB); + group->mVertexBuffer = createVertexBuffer(mVertexDataMask, group->mBufferUsage); + group->mVertexBuffer->allocateBuffer(group->mVertexCount, group->mIndexCount, true); + stop_glerror(); + } + else + { + //LLFastTimer ftm(LLFastTimer::FTM_REBUILD_NONE_VB); + group->mVertexBuffer->resizeBuffer(group->mVertexCount, group->mIndexCount); + stop_glerror(); + } + + { + LLFastTimer ftm((LLFastTimer::EFastTimerType) ((U32) LLFastTimer::FTM_REBUILD_VOLUME_VB + mPartitionType)); + getGeometry(group); + } + } + else + { + group->mVertexBuffer = NULL; + group->mBufferMap.clear(); + } + + group->mLastUpdateTime = gFrameTimeSeconds; + group->clearState(LLSpatialGroup::GEOM_DIRTY | LLSpatialGroup::MATRIX_DIRTY); +} + BOOL LLSpatialGroup::boundObjects(BOOL empty, LLVector3& minOut, LLVector3& maxOut) { const OctreeState* node = mOctreeNode->getOctState(); @@ -285,7 +435,7 @@ BOOL LLSpatialGroup::boundObjects(BOOL empty, LLVector3& minOut, LLVector3& maxO LLVector3& newMin = mObjectExtents[0]; LLVector3& newMax = mObjectExtents[1]; - + if (isState(OBJECT_DIRTY)) { //calculate new bounding box clearState(OBJECT_DIRTY); @@ -371,11 +521,28 @@ void LLSpatialGroup::unbound() } } +LLSpatialGroup* LLSpatialGroup::getParent() +{ + if (isDead()) + { + return NULL; + } + + OctreeNode* parent = mOctreeNode->getOctParent(); + + if (parent) + { + return (LLSpatialGroup*) parent->getListener(0); + } + + return NULL; +} + BOOL LLSpatialGroup::removeObject(LLDrawable *drawablep, BOOL from_octree) { LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); unbound(); - if (!from_octree) + if (mOctreeNode && !from_octree) { if (!mOctreeNode->remove(drawablep)) { @@ -385,6 +552,19 @@ BOOL LLSpatialGroup::removeObject(LLDrawable *drawablep, BOOL from_octree) else { drawablep->setSpatialGroup(NULL, -1); + setState(GEOM_DIRTY); + gPipeline.markRebuild(this); + if (drawablep->isSpatialBridge()) + { + for (bridge_list_t::iterator i = mBridgeList.begin(); i != mBridgeList.end(); ++i) + { + if (*i == drawablep) + { + mBridgeList.erase(i); + break; + } + } + } } return TRUE; } @@ -401,6 +581,9 @@ void LLSpatialGroup::shift(const LLVector3 &offset) mObjectBounds[0] += offset; mObjectExtents[0] += offset; mObjectExtents[1] += offset; + + gPipeline.markRebuild(this); + setState(GEOM_DIRTY | MATRIX_DIRTY | OCCLUSION_DIRTY); } class LLSpatialSetState : public LLSpatialGroup::OctreeTraveler @@ -515,29 +698,152 @@ void LLSpatialGroup::clearState(U32 state, S32 mode) //====================================== LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) -: mState(0), mOctreeNode(node), mSpatialPartition(part) +: mOctreeNode(node), mState(0), mSpatialPartition(part), mVertexBuffer(NULL), + mDistance(0.f), mLastUpdateDistance(-1.f), + mViewAngle(0.f), mLastUpdateViewAngle(-1.f), + mDepth(0.f), mBuilt(0.f), + mLastUpdateTime(gFrameTimeSeconds), mLastRenderTime(gFrameTimeSeconds), + mLastAddTime(gFrameTimeSeconds), + mBufferUsage(GL_STATIC_DRAW_ARB) { LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); + sg_assert(mOctreeNode->getListenerCount() == 0); mOctreeNode->addListener(this); - setState(DIRTY); + setState(SG_INITIAL_STATE_MASK); mBounds[0] = LLVector3(node->getCenter()); mBounds[1] = LLVector3(node->getSize()); - sLODSeed = (sLODSeed+1)%SG_LOD_PERIOD; - mLODHash = sLODSeed; + part->mLODSeed = (part->mLODSeed+1)%part->mLODPeriod; + mLODHash = part->mLODSeed; + + mRadius = 1; + mPixelArea = 1024.f; +} + +void LLSpatialGroup::updateDistance(LLCamera &camera) +{ +#if !LL_RELEASE_FOR_DOWNLOAD + if (isState(LLSpatialGroup::OBJECT_DIRTY)) + { + llerrs << "Spatial group dirty on distance update." << llendl; + } +#endif + if (!getData().empty()) + { + mRadius = mSpatialPartition->mRenderByGroup ? mObjectBounds[1].magVec() : + (F32) mOctreeNode->getSize().magVec(); + mDistance = mSpatialPartition->calcDistance(this, camera); + mPixelArea = mSpatialPartition->calcPixelArea(this, camera); + } +} + +F32 LLSpatialPartition::calcDistance(LLSpatialGroup* group, LLCamera& camera) +{ + LLVector3 eye = group->mObjectBounds[0] - camera.getOrigin(); + + F32 dist = 0.f; + + if (group->mDrawMap.find(LLRenderPass::PASS_ALPHA) != group->mDrawMap.end()) + { + LLVector3 v = eye; + dist = eye.normVec(); + + if (!group->isState(LLSpatialGroup::ALPHA_DIRTY)) + { + LLVector3 view_angle = LLVector3(eye * LLVector3(1,0,0), + eye * LLVector3(0,1,0), + eye * LLVector3(0,0,1)); + + if ((view_angle-group->mLastUpdateViewAngle).magVec() > 0.64f) + { + group->mViewAngle = view_angle; + group->mLastUpdateViewAngle = view_angle; + //for occasional alpha sorting within the group + //NOTE: If there is a trivial way to detect that alpha sorting here would not change the render order, + //not setting this node to dirty would be a very good thing + group->setState(LLSpatialGroup::ALPHA_DIRTY); + } + } + + //calculate depth of node for alpha sorting + + LLVector3 at = camera.getAtAxis(); + + //front of bounding box + for (U32 i = 0; i < 3; i++) + { + v.mV[i] -= group->mObjectBounds[1].mV[i]*0.25f * at.mV[i]; + } + + group->mDepth = v * at; + + F32 water_height = gAgent.getRegion()->getWaterHeight(); + //figure out if this node is above or below water + if (group->mObjectBounds[0].mV[2] < water_height) + { + group->setState(LLSpatialGroup::BELOW_WATER); + } + else + { + group->clearState(LLSpatialGroup::BELOW_WATER); + } + } + else + { + dist = eye.magVec(); + } + + if (dist < 16.f) + { + dist /= 16.f; + dist *= dist; + dist *= 16.f; + } + + return dist; +} + +F32 LLSpatialPartition::calcPixelArea(LLSpatialGroup* group, LLCamera& camera) +{ + return LLPipeline::calcPixelArea(group->mObjectBounds[0], group->mObjectBounds[1], camera); } BOOL LLSpatialGroup::changeLOD() { - return LLDrawable::getCurrentFrame()%SG_LOD_PERIOD == mLODHash; + if (isState(ALPHA_DIRTY)) + { ///an alpha sort is going to happen, update distance and LOD + return TRUE; + } + + if (mSpatialPartition->mSlopRatio > 0.f) + { + F32 ratio = (mDistance - mLastUpdateDistance)/(llmax(mLastUpdateDistance, mRadius)); + + if (fabsf(ratio) >= mSpatialPartition->mSlopRatio) + { + return TRUE; + } + + if (mDistance > mRadius) + { + return FALSE; + } + } + + if (LLDrawable::getCurrentFrame()%mSpatialPartition->mLODPeriod == mLODHash) + { + return TRUE; + } + + return FALSE; } -void LLSpatialGroup::handleInsertion(const TreeNode* node, LLDrawable* drawable) +void LLSpatialGroup::handleInsertion(const TreeNode* node, LLDrawable* drawablep) { LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - addObject(drawable, FALSE, TRUE); + addObject(drawablep, FALSE, TRUE); unbound(); setState(OBJECT_DIRTY); } @@ -552,29 +858,13 @@ void LLSpatialGroup::handleRemoval(const TreeNode* node, LLDrawable* drawable) void LLSpatialGroup::handleDestruction(const TreeNode* node) { LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - - if (mOctreeNode) - { - OctreeState* state = mOctreeNode->getOctState(); - for (OctreeState::element_iter i = state->getData().begin(); i != state->getData().end(); ++i) - { - LLDrawable* drawable = *i; - if (!drawable->isDead()) - { - drawable->setSpatialGroup(NULL, -1); - } - } - } - - if (safeToDelete()) - { - delete this; - } - else - { - setState(DEAD); - mOctreeNode = NULL; - } + setState(DEAD); + clearDrawMap(); + mOcclusionVerts = NULL; + mVertexBuffer = NULL; + mBufferMap.clear(); + sZombieGroups++; + mOctreeNode = NULL; } void LLSpatialGroup::handleStateChange(const TreeNode* node) @@ -592,7 +882,8 @@ void LLSpatialGroup::handleChildAddition(const OctreeNode* parent, OctreeNode* c LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); if (child->getListenerCount() == 0) { - (new LLSpatialGroup(child, mSpatialPartition))->setState(mState & SG_STATE_INHERIT_MASK); + LLSpatialGroup* group = new LLSpatialGroup(child, mSpatialPartition); + group->setState(mState & SG_STATE_INHERIT_MASK); } else { @@ -616,7 +907,7 @@ BOOL LLSpatialGroup::rebound() LLVector3 oldBounds[2]; - if (isState(QUERY_OUT)) + if (mSpatialPartition->isVolatile() && isState(QUERY_OUT)) { //a query has been issued, if our bounding box changes significantly //we need to discard the issued query oldBounds[0] = mBounds[0]; @@ -681,7 +972,7 @@ BOOL LLSpatialGroup::rebound() mBounds[1] = (newMax - newMin)*0.5f; } - if (isState(QUERY_OUT)) + if (mSpatialPartition->isVolatile() && isState(QUERY_OUT)) { for (U32 i = 0; i < 3 && !isState(DISCARD_QUERY); i++) { @@ -694,6 +985,8 @@ BOOL LLSpatialGroup::rebound() } } + setState(OCCLUSION_DIRTY); + clearState(DIRTY); return TRUE; @@ -701,9 +994,21 @@ BOOL LLSpatialGroup::rebound() //============================================== -LLSpatialPartition::LLSpatialPartition() +LLSpatialPartition::LLSpatialPartition(U32 data_mask, BOOL is_volatile, U32 buffer_usage) { LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); + mDrawableType = 0; + mPartitionType = LLPipeline::PARTITION_NONE; + mVolatile = is_volatile; + mLODSeed = 0; + mLODPeriod = 1; + mVertexDataMask = data_mask; + mBufferUsage = buffer_usage; + mDepthMask = FALSE; + mSlopRatio = 0.25f; + mRenderByGroup = TRUE; + mImageEnabled = FALSE; + mOctree = new LLSpatialGroup::OctreeNode(LLVector3d(0,0,0), LLVector3d(1,1,1), new LLSpatialGroup::OctreeRoot(), NULL); @@ -714,12 +1019,18 @@ LLSpatialPartition::LLSpatialPartition() LLSpatialPartition::~LLSpatialPartition() { LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); + + for (U32 i = 0; i < mOcclusionQueries.size(); i++) + { + glDeleteQueriesARB(1, (GLuint*)(&(mOcclusionQueries[i]))); + } + delete mOctree; mOctree = NULL; } -LLSpatialGroup *LLSpatialPartition::put(LLDrawable *drawablep) +LLSpatialGroup *LLSpatialPartition::put(LLDrawable *drawablep, BOOL was_visible) { LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); const F32 MAX_MAG = 1000000.f*1000000.f; // 1 million @@ -751,7 +1062,13 @@ LLSpatialGroup *LLSpatialPartition::put(LLDrawable *drawablep) LLSpatialGroup::OctreeNode* node = mOctree->getNodeAt(drawablep); - return (LLSpatialGroup*) node->getListener(0); + LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0); + if (was_visible && group->isState(LLSpatialGroup::QUERY_OUT)) + { + group->setState(LLSpatialGroup::DISCARD_QUERY); + } + + return group; } BOOL LLSpatialPartition::remove(LLDrawable *drawablep, LLSpatialGroup *curp) @@ -774,14 +1091,16 @@ void LLSpatialPartition::move(LLDrawable *drawablep, LLSpatialGroup *curp, BOOL { LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); LLFastTimer t(LLFastTimer::FTM_UPDATE_MOVE); - + + BOOL was_visible = curp ? curp->isVisible() : FALSE; + if (curp && curp->mSpatialPartition != this) { //keep drawable from being garbage collected LLPointer<LLDrawable> ptr = drawablep; if (curp->mSpatialPartition->remove(drawablep, curp)) { - put(drawablep); + put(drawablep, was_visible); return; } else @@ -804,7 +1123,7 @@ void LLSpatialPartition::move(LLDrawable *drawablep, LLSpatialGroup *curp, BOOL OCT_ERRS << "Move couldn't find existing spatial group!" << llendl; } - put(drawablep); + put(drawablep, was_visible); } class LLSpatialShift : public LLSpatialGroup::OctreeTraveler @@ -829,13 +1148,9 @@ void LLSpatialPartition::shift(const LLVector3 &offset) BOOL LLSpatialPartition::checkOcclusion(LLSpatialGroup* group, LLCamera* camera) { - if (sIgnoreOcclusion) - { - return FALSE; - } - - if (!group->isState(LLSpatialGroup::ACTIVE_OCCLUSION | LLSpatialGroup::OCCLUDED) && - !earlyFail(camera, group)) + if (LLPipeline::sUseOcclusion && + !group->isState(LLSpatialGroup::ACTIVE_OCCLUSION | LLSpatialGroup::OCCLUDED) && + (!camera || !earlyFail(camera, group))) { group->setState(LLSpatialGroup::ACTIVE_OCCLUSION); mQueryQueue.push(group); @@ -853,8 +1168,8 @@ public: virtual bool earlyFail(const LLSpatialGroup* group) { - if (mRes && //never occlusion cull the root node - !sIgnoreOcclusion && //never occlusion cull selection + if (group->mOctreeNode->getParent() && //never occlusion cull the root node + LLPipeline::sUseOcclusion && //never occlusion cull selection group->isState(LLSpatialGroup::OCCLUDED)) { return true; @@ -931,22 +1246,19 @@ public: group->mSpatialPartition->checkOcclusion(group, mCamera); } } + + if (LLPipeline::sDynamicReflections && + group->mOctreeNode->getSize().mdV[0] == 16.0 && + group->mDistance < 64.f && + group->mLastAddTime < gFrameTimeSeconds - 2.f) + { + group->mSpatialPartition->markReimage(group); + } } - virtual void processDrawable(LLDrawable* drawable) + virtual void processGroup(LLSpatialGroup* group) { - if (!drawable->isDead()) - { - const LLVector3* extents = drawable->getSpatialExtents(); - - F32 objRad = drawable->getRadius(); - objRad *= objRad; - F32 distSqr = ((extents[0]+extents[1])*0.5f - mCamera->getOrigin()).magVecSquared(); - if (objRad/distSqr > SG_MIN_DIST_RATIO) - { - gPipeline.markNotCulled(drawable, *mCamera); - } - } + gPipeline.markNotCulled(group, *mCamera); } virtual void visit(const LLSpatialGroup::OctreeState* branch) @@ -957,10 +1269,7 @@ public: if (checkObjects(branch, group)) { - for (LLSpatialGroup::OctreeState::const_element_iter i = branch->getData().begin(); i != branch->getData().end(); ++i) - { - processDrawable(*i); - } + processGroup(group); } } @@ -979,34 +1288,32 @@ public: virtual void lateFail(LLSpatialGroup* group) { } virtual void preprocess(LLSpatialGroup* group) { } - virtual void processDrawable(LLDrawable* drawable) + virtual void processGroup(LLSpatialGroup* group) { - if (!drawable->isDead()) + LLSpatialGroup::OctreeState* branch = group->mOctreeNode->getOctState(); + + for (LLSpatialGroup::OctreeState::const_element_iter i = branch->getData().begin(); i != branch->getData().end(); ++i) { - if (drawable->isSpatialBridge()) - { - drawable->setVisible(*mCamera, mResults, TRUE); - } - else + LLDrawable* drawable = *i; + + if (!drawable->isDead()) { - mResults->push_back(drawable); - } - } + if (drawable->isSpatialBridge()) + { + drawable->setVisible(*mCamera, mResults, TRUE); + } + else + { + mResults->push_back(drawable); + } + } + } } std::vector<LLDrawable*>* mResults; }; -void drawBox(const LLVector3& c, const LLVector3& r) -{ - glPushMatrix(); - glTranslatef(c.mV[0], c.mV[1], c.mV[2]); - glScalef(r.mV[0], r.mV[1], r.mV[2]); - glCallList(sBoxList); - glPopMatrix(); -} - void genBoxList() { if (sBoxList != 0) @@ -1058,6 +1365,99 @@ void genBoxList() glEndList(); } +void drawBox(const LLVector3& c, const LLVector3& r) +{ + genBoxList(); + + glPushMatrix(); + glTranslatef(c.mV[0], c.mV[1], c.mV[2]); + glScalef(r.mV[0], r.mV[1], r.mV[2]); + glCallList(sBoxList); + glPopMatrix(); +} + +void drawBoxOutline(const LLVector3& pos, const LLVector3& size) +{ + LLVector3 v1 = size.scaledVec(LLVector3( 1, 1,1)); + LLVector3 v2 = size.scaledVec(LLVector3(-1, 1,1)); + LLVector3 v3 = size.scaledVec(LLVector3(-1,-1,1)); + LLVector3 v4 = size.scaledVec(LLVector3( 1,-1,1)); + + glBegin(GL_LINE_LOOP); //top + glVertex3fv((pos+v1).mV); + glVertex3fv((pos+v2).mV); + glVertex3fv((pos+v3).mV); + glVertex3fv((pos+v4).mV); + glEnd(); + + glBegin(GL_LINE_LOOP); //bottom + glVertex3fv((pos-v1).mV); + glVertex3fv((pos-v2).mV); + glVertex3fv((pos-v3).mV); + glVertex3fv((pos-v4).mV); + glEnd(); + + + glBegin(GL_LINES); + + //right + glVertex3fv((pos+v1).mV); + glVertex3fv((pos-v3).mV); + + glVertex3fv((pos+v4).mV); + glVertex3fv((pos-v2).mV); + + //left + glVertex3fv((pos+v2).mV); + glVertex3fv((pos-v4).mV); + + glVertex3fv((pos+v3).mV); + glVertex3fv((pos-v1).mV); + + glEnd(); +} + +class LLOctreeDirty : public LLOctreeTraveler<LLDrawable> +{ +public: + virtual void visit(const LLOctreeState<LLDrawable>* state) + { + LLSpatialGroup* group = (LLSpatialGroup*) state->getListener(0); + + group->setState(LLSpatialGroup::GEOM_DIRTY | + LLSpatialGroup::OCCLUSION_DIRTY | + LLSpatialGroup::IMAGE_DIRTY); + group->mLastUpdateTime = gFrameTimeSeconds; + group->mVertexBuffer = NULL; + group->mBufferMap.clear(); + + group->mOcclusionVerts = NULL; + group->mReflectionMap = NULL; + group->clearDrawMap(); + + for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i) + { + LLDrawable* drawable = *i; + for (S32 j = 0; j < drawable->getNumFaces(); j++) + { + LLFace* facep = drawable->getFace(j); + facep->mVertexBuffer = NULL; + facep->mLastVertexBuffer = NULL; + } + + if (drawable->getVObj() && !group->mSpatialPartition->mRenderByGroup) + { + gPipeline.markRebuild(drawable, LLDrawable::REBUILD_ALL, TRUE); + } + } + + for (LLSpatialGroup::bridge_list_t::iterator i = group->mBridgeList.begin(); i != group->mBridgeList.end(); ++i) + { + LLSpatialBridge* bridge = *i; + traverse(bridge->mOctree); + } + } +}; void LLSpatialPartition::restoreGL() { LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); @@ -1080,6 +1480,14 @@ void LLSpatialPartition::restoreGL() genBoxList(); } +void LLSpatialPartition::resetVertexBuffers() +{ + LLOctreeDirty dirty; + dirty.traverse(mOctree); + + mOcclusionIndices = NULL; +} + S32 LLSpatialPartition::cull(LLCamera &camera, std::vector<LLDrawable *>* results, BOOL for_select) { LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); @@ -1096,11 +1504,11 @@ S32 LLSpatialPartition::cull(LLCamera &camera, std::vector<LLDrawable *>* result } else { + LLFastTimer ftm(LLFastTimer::FTM_FRUSTUM_CULL); LLOctreeCull culler(&camera); culler.traverse(mOctree); } - sIgnoreOcclusion = !(gSavedSettings.getBOOL("UseOcclusion") && gGLManager.mHasOcclusionQuery); return 0; } @@ -1155,9 +1563,10 @@ public: BOOL earlyFail(LLCamera* camera, LLSpatialGroup* group) { LLVector3 c = group->mBounds[0]; - LLVector3 r = group->mBounds[1] * (SG_OCCLUSION_FUDGE*2.f) + LLVector3(0.01f,0.01f,0.01f); + LLVector3 r = group->mBounds[1]*SG_OCCLUSION_FUDGE + LLVector3(0.2f,0.2f,0.2f); - if (group->isState(LLSpatialGroup::CULLED) || !camera->AABBInFrustum(c, r)) + //if (group->isState(LLSpatialGroup::CULLED)) // || + if (!camera->AABBInFrustum(c, r)) { return TRUE; } @@ -1178,6 +1587,160 @@ BOOL earlyFail(LLCamera* camera, LLSpatialGroup* group) return TRUE; } +void LLSpatialPartition::processGeometry(LLCamera* camera) +{ + if (!mRenderByGroup || mBufferUsage == GL_STREAM_DRAW_ARB) + { + return; + } + + U32 process_count = 8; + + LLSpatialGroup* root = (LLSpatialGroup*) mOctree->getListener(0); + if (!root->isState(LLSpatialGroup::IN_GEOMETRY_QUEUE)) + { + root->setState(LLSpatialGroup::IN_GEOMETRY_QUEUE); + mUpdateQueue.push(root); + } + + while (process_count > 0 && !mUpdateQueue.empty()) + { + process_count--; + LLPointer<LLSpatialGroup> group = mUpdateQueue.front(); + mUpdateQueue.pop(); + + group->clearState(LLSpatialGroup::IN_GEOMETRY_QUEUE); + + if (group->isDead()) + { + continue; + } + + //push children onto queue + for (U32 i = 0; i < group->mOctreeNode->getChildCount(); i++) + { + LLSpatialGroup* child = (LLSpatialGroup*) group->mOctreeNode->getChild(i)->getListener(0); + + if (!child->isState(LLSpatialGroup::IN_GEOMETRY_QUEUE)) + { + child->setState(LLSpatialGroup::IN_GEOMETRY_QUEUE); + mUpdateQueue.push(child); + } + } + + if (!group->isDead() && + !group->isVisible() && + !group->isState(LLSpatialGroup::OBJECT_DIRTY) && + group->mBufferUsage != GL_STREAM_DRAW_ARB) + { + group->updateDistance(*camera); + for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i) + { + LLDrawable* drawablep = *i; + if (!drawablep->isDead()) + { + drawablep->updateDistance(*camera); + } + } + } + } +} + +void LLSpatialPartition::markReimage(LLSpatialGroup* group) +{ + if (mImageEnabled && group->isState(LLSpatialGroup::IMAGE_DIRTY)) + { + if (!group->isState(LLSpatialGroup::IN_IMAGE_QUEUE)) + { + group->setState(LLSpatialGroup::IN_IMAGE_QUEUE); + mImageQueue.push(group); + } + } +} + +void LLSpatialPartition::processImagery(LLCamera* camera) +{ + if (!mImageEnabled) + { + return; + } + + U32 process_count = 1; + + while (process_count > 0 && !mImageQueue.empty()) + { + LLPointer<LLSpatialGroup> group = mImageQueue.front(); + mImageQueue.pop(); + + group->clearState(LLSpatialGroup::IN_IMAGE_QUEUE); + + if (group->isDead()) + { + continue; + } + + if (LLPipeline::sDynamicReflections) + { + process_count--; + LLVector3 origin = group->mBounds[0]; + + LLCamera cube_cam; + cube_cam.setOrigin(origin); + cube_cam.setFar(64.f); + + LLPointer<LLCubeMap> cube_map = group->mReflectionMap; + group->mReflectionMap = NULL; + if (cube_map.isNull()) + { + cube_map = new LLCubeMap(); + cube_map->initGL(); + } + + if (gPipeline.mCubeBuffer == NULL) + { + gPipeline.mCubeBuffer = new LLCubeMap(); + gPipeline.mCubeBuffer->initGL(); + } + + gPipeline.generateReflectionMap(gPipeline.mCubeBuffer, cube_cam, 128); + gPipeline.blurReflectionMap(gPipeline.mCubeBuffer, cube_map, 32); + group->mReflectionMap = cube_map; + group->setState(LLSpatialGroup::GEOM_DIRTY); + gPipeline.markRebuild(group); + } + + group->clearState(LLSpatialGroup::IMAGE_DIRTY); + } +} + +void validate_occlusion_list(std::vector<LLPointer<LLSpatialGroup> >& occluded_list) +{ +#if !LL_RELEASE_FOR_DOWNLOAD + for (U32 i = 0; i < occluded_list.size(); i++) + { + LLSpatialGroup* group = occluded_list[i]; + for (U32 j = i+1; j < occluded_list.size(); j++) + { + if (occluded_list[i] == occluded_list[j]) + { + llerrs << "Duplicate node in occlusion list." << llendl; + } + } + + LLSpatialGroup::OctreeNode* parent = group->mOctreeNode->getOctParent(); + while (parent) + { + LLSpatialGroup* parent_group = (LLSpatialGroup*) parent->getListener(0); + if (parent_group->isState(LLSpatialGroup::OCCLUDED)) + { + llerrs << "Child node of occluded node in occlusion list (redundant query)." << llendl; + } + parent = parent->getOctParent(); + } + } +#endif +} + void LLSpatialPartition::processOcclusion(LLCamera* camera) { LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); @@ -1198,12 +1761,12 @@ void LLSpatialPartition::processOcclusion(LLCamera* camera) const U32 MAX_PUSHED = mOcclusionQueue.size(); U32 count = 0; U32 pcount = 0; - + while (pcount < MAX_PUSHED && count < MAX_PULLED && !mOcclusionQueue.empty()) { - LLFastTimer t(LLFastTimer::FTM_OCCLUSION); + LLFastTimer t(LLFastTimer::FTM_OCCLUSION); - LLSpatialGroup* group = mOcclusionQueue.front(); + LLPointer<LLSpatialGroup> group = mOcclusionQueue.front(); if (!group->isState(LLSpatialGroup::IN_QUEUE)) { OCT_ERRS << "Spatial Group State Error. Group in queue not tagged as such." << llendl; @@ -1214,10 +1777,6 @@ void LLSpatialPartition::processOcclusion(LLCamera* camera) if (group->isDead()) { - if (group->safeToDelete()) - { - delete group; - } continue; } @@ -1231,22 +1790,14 @@ void LLSpatialPartition::processOcclusion(LLCamera* camera) { LLSpatialGroup* child = (LLSpatialGroup*) group->mOctreeNode->getChild(i)->getListener(0); - if (!child->isState(LLSpatialGroup::OCCLUDED | LLSpatialGroup::CULLED) - && !child->isState(LLSpatialGroup::IN_QUEUE | LLSpatialGroup::ACTIVE_OCCLUSION)) + //if (!child->isState(LLSpatialGroup::OCCLUDED | LLSpatialGroup::CULLED) + if (!child->isState(LLSpatialGroup::IN_QUEUE | LLSpatialGroup::ACTIVE_OCCLUSION)) { child->setState(LLSpatialGroup::IN_QUEUE); mOcclusionQueue.push(child); } } - - /*if (group->isState(LLSpatialGroup::QUERY_PENDING)) - { //already on the pending group, put it back - group->setState(LLSpatialGroup::IN_QUEUE); - mOcclusionQueue.push(group); - pcount++; - continue; - }*/ - + if (earlyFail(camera, group)) { sg_assert(!group->isState(LLSpatialGroup::OCCLUDED)); @@ -1265,7 +1816,6 @@ void LLSpatialPartition::processOcclusion(LLCamera* camera) sg_assert(mOccludedList[i] != group); } #endif - //group->setState(LLSpatialGroup::QUERY_PENDING); group->setState(LLSpatialGroup::ACTIVE_OCCLUSION); mQueryQueue.push(group); count++; @@ -1277,7 +1827,7 @@ void LLSpatialPartition::processOcclusion(LLCamera* camera) { LLFastTimer t(LLFastTimer::FTM_OCCLUSION_READBACK); - if (mOccludedList[i]->isDead() || !mOccludedList[i]->isState(LLSpatialGroup::ACTIVE_OCCLUSION)) + if (mOccludedList[i]->isDead() || mOccludedList[i]->isState(LLSpatialGroup::DEACTIVATE_OCCLUSION)) { continue; } @@ -1328,8 +1878,7 @@ void LLSpatialPartition::processOcclusion(LLCamera* camera) LLSpatialGroup* parent = (LLSpatialGroup*) oct_parent->getListener(0); if (checkOcclusion(parent, camera)) - { //force a guess on the parent and siblings - + { //force a guess on the parent and siblings for (U32 i = 0; i < parent->mOctreeNode->getChildCount(); i++) { LLSpatialGroup* child = (LLSpatialGroup*) parent->mOctreeNode->getChild(i)->getListener(0); @@ -1337,13 +1886,17 @@ void LLSpatialPartition::processOcclusion(LLCamera* camera) } } } + + //take children off the active list + mOccludedList[i]->setState(LLSpatialGroup::DEACTIVATE_OCCLUSION, LLSpatialGroup::STATE_MODE_BRANCH); + mOccludedList[i]->clearState(LLSpatialGroup::DEACTIVATE_OCCLUSION); } mOccludedList[i]->setState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF); } else { //take children off the active list - mOccludedList[i]->setState(LLSpatialGroup::DEACTIVATE_OCCLUSION, LLSpatialGroup::STATE_MODE_DIFF); + mOccludedList[i]->setState(LLSpatialGroup::DEACTIVATE_OCCLUSION, LLSpatialGroup::STATE_MODE_BRANCH); //keep this node on the active list mOccludedList[i]->clearState(LLSpatialGroup::DEACTIVATE_OCCLUSION); @@ -1364,15 +1917,13 @@ void LLSpatialPartition::processOcclusion(LLCamera* camera) mOccludedList[i]->isState(LLSpatialGroup::DEACTIVATE_OCCLUSION)) //parent is occluded { LLSpatialGroup* groupp = mOccludedList[i]; - mOccludedList.erase(mOccludedList.begin()+i); - groupp->clearState(LLSpatialGroup::ACTIVE_OCCLUSION); - groupp->clearState(LLSpatialGroup::DEACTIVATE_OCCLUSION); - groupp->clearState(LLSpatialGroup::OCCLUDING); - - if (groupp->isDead() && groupp->safeToDelete()) + if (!groupp->isDead()) { - delete groupp; + groupp->clearState(LLSpatialGroup::ACTIVE_OCCLUSION); + groupp->clearState(LLSpatialGroup::DEACTIVATE_OCCLUSION); + groupp->clearState(LLSpatialGroup::OCCLUDING); } + mOccludedList.erase(mOccludedList.begin()+i); } else { @@ -1380,11 +1931,13 @@ void LLSpatialPartition::processOcclusion(LLCamera* camera) } } + validate_occlusion_list(mOccludedList); + //pump some non-culled items onto the occlusion list //count = MAX_PULLED; while (!mQueryQueue.empty()) { - LLSpatialGroup* group = mQueryQueue.front(); + LLPointer<LLSpatialGroup> group = mQueryQueue.front(); mQueryQueue.pop(); //group->clearState(LLSpatialGroup::QUERY_PENDING); mOccludedList.push_back(group); @@ -1399,12 +1952,161 @@ void LLSpatialPartition::processOcclusion(LLCamera* camera) } } +class LLOcclusionIndexBuffer : public LLVertexBuffer +{ +public: + LLOcclusionIndexBuffer(U32 size) + : LLVertexBuffer(0, GL_STREAM_DRAW_ARB) + { + allocateBuffer(0, size, TRUE); + + LLStrider<U32> idx; + + getIndexStrider(idx); + + //12 triangles' indices + idx[0] = 1; idx[1] = 0; idx[2] = 2; //front + idx[3] = 3; idx[4] = 2; idx[5] = 0; + + idx[6] = 4; idx[7] = 5; idx[8] = 1; //top + idx[9] = 0; idx[10] = 1; idx[11] = 5; + + idx[12] = 5; idx[13] = 4; idx[14] = 6; //back + idx[15] = 7; idx[16] = 6; idx[17] = 4; + + idx[18] = 6; idx[19] = 7; idx[20] = 3; //bottom + idx[21] = 2; idx[22] = 3; idx[23] = 7; + + idx[24] = 0; idx[25] = 5; idx[26] = 3; //left + idx[27] = 6; idx[28] = 3; idx[29] = 5; + + idx[30] = 4; idx[31] = 1; idx[32] = 7; //right + idx[33] = 2; idx[34] = 7; idx[35] = 1; + } + + //virtual BOOL useVBOs() const { return FALSE; } + + void setBuffer(U32 data_mask) + { + if (useVBOs()) + { + glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, mGLIndices); + sIBOActive = TRUE; + unmapBuffer(); + } + else if (sIBOActive) + { + glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); + sIBOActive = FALSE; + } + + sGLRenderIndices = mGLIndices; + } +}; + +class LLOcclusionVertexBuffer : public LLVertexBuffer +{ +public: + LLOcclusionVertexBuffer(S32 usage) + : LLVertexBuffer(MAP_VERTEX, usage) + { + allocateBuffer(8, 0, TRUE); + } + + //virtual BOOL useVBOs() const { return FALSE; } + + void setBuffer(U32 data_mask) + { + if (useVBOs()) + { + glBindBufferARB(GL_ARRAY_BUFFER_ARB, mGLBuffer); + sVBOActive = TRUE; + unmapBuffer(); + } + else if (sVBOActive) + { + glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); + sVBOActive = FALSE; + } + + if (data_mask) + { + glVertexPointer(3,GL_FLOAT, 0, useVBOs() ? 0 : mMappedData); + } + + sGLRenderBuffer = mGLBuffer; + } +}; + +void LLSpatialPartition::buildOcclusion() +{ + if (mOccludedList.empty()) + { + return; + } + + BOOL reset_all = FALSE; + if (mOcclusionIndices.isNull()) + { + mOcclusionIndices = new LLOcclusionIndexBuffer(36); + reset_all = TRUE; + } + + //fill occlusion vertex buffers + for (U32 i = 0; i < mOccludedList.size(); i++) + { + LLSpatialGroup* group = mOccludedList[i]; + + if (group->isState(LLSpatialGroup::OCCLUSION_DIRTY) || reset_all) + { + LLFastTimer ftm(LLFastTimer::FTM_REBUILD_OCCLUSION_VB); + + if (group->mOcclusionVerts.isNull()) + { + group->mOcclusionVerts = new LLOcclusionVertexBuffer(GL_STREAM_DRAW_ARB); + } + + group->clearState(LLSpatialGroup::OCCLUSION_DIRTY); + + LLStrider<LLVector3> vert; + + group->mOcclusionVerts->getVertexStrider(vert); + + LLVector3 r = group->mBounds[1]*SG_OCCLUSION_FUDGE + LLVector3(0.1f,0.1f,0.1f); + + for (U32 k = 0; k < 3; k++) + { + r.mV[k] = llmin(group->mBounds[1].mV[k]+0.25f, r.mV[k]); + } + + *vert++ = group->mBounds[0] + r.scaledVec(LLVector3(-1,1,1)); // 0 - left top front + *vert++ = group->mBounds[0] + r.scaledVec(LLVector3(1,1,1)); // 1 - right top front + *vert++ = group->mBounds[0] + r.scaledVec(LLVector3(1,-1,1)); // 2 - right bottom front + *vert++ = group->mBounds[0] + r.scaledVec(LLVector3(-1,-1,1)); // 3 - left bottom front + + *vert++ = group->mBounds[0] + r.scaledVec(LLVector3(1,1,-1)); // 4 - left top back + *vert++ = group->mBounds[0] + r.scaledVec(LLVector3(-1,1,-1)); // 5 - right top back + *vert++ = group->mBounds[0] + r.scaledVec(LLVector3(-1,-1,-1)); // 6 - right bottom back + *vert++ = group->mBounds[0] + r.scaledVec(LLVector3(1,-1,-1)); // 7 -left bottom back + } + } + +/* for (U32 i = 0; i < mOccludedList.size(); i++) + { + LLSpatialGroup* group = mOccludedList[i]; + if (!group->mOcclusionVerts.isNull() && group->mOcclusionVerts->isLocked()) + { + LLFastTimer ftm(LLFastTimer::FTM_REBUILD_OCCLUSION_VB); + group->mOcclusionVerts->setBuffer(0); + } + }*/ +} + void LLSpatialPartition::doOcclusion(LLCamera* camera) { LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - sIgnoreOcclusion = gUseWireframe; - LLFastTimer t(LLFastTimer::FTM_RENDER_OCCLUSION); + LLFastTimer t(LLFastTimer::FTM_RENDER_OCCLUSION); #if LL_OCTREE_PARANOIA_CHECK LLSpatialGroup* check = (LLSpatialGroup*) mOctree->getListener(0); @@ -1413,9 +2115,16 @@ void LLSpatialPartition::doOcclusion(LLCamera* camera) stop_glerror(); + U32 num_verts = mOccludedList.size() * 8; + + if (num_verts == 0) + { + return; + } + //actually perform the occlusion queries LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE); - glDisable(GL_TEXTURE_2D); + LLGLDisable(GL_TEXTURE_2D); gPipeline.disableLights(); LLGLEnable cull_face(GL_CULL_FACE); LLGLDisable blend(GL_BLEND); @@ -1424,25 +2133,16 @@ void LLSpatialPartition::doOcclusion(LLCamera* camera) glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); glColor4f(1,1,1,1); - //sort occlusion queries front to back - /*for (U32 i = 0; i < mOccludedList.size(); i++) - { - LLSpatialGroup* group = mOccludedList[i]; - - LLVector3 v = group->mOctreeNode->getCenter()-camera->getOrigin(); - group->mDistance = v*v; - } - - std::sort(mOccludedList.begin(), mOccludedList.end(), dist_greater()); + mOcclusionIndices->setBuffer(0); - glClearStencil(0); - glClear(GL_STENCIL_BUFFER_BIT); - LLGLEnable stencil(GL_STENCIL_TEST); - glStencilFunc(GL_GREATER, 1, 0xFFFFFFFF); - glStencilOp(GL_KEEP, GL_SET, GL_KEEP);*/ - - genBoxList(); + U32* indicesp = (U32*) mOcclusionIndices->getIndicesPointer(); + glDisableClientState(GL_NORMAL_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); +#if !LL_RELEASE_FOR_DOWNLOAD + LLGLState::checkClientArrays(LLVertexBuffer::MAP_VERTEX); +#endif for (U32 i = 0; i < mOccludedList.size(); i++) { #if LL_OCTREE_PARANOIA_CHECK @@ -1463,32 +2163,10 @@ void LLSpatialPartition::doOcclusion(LLCamera* camera) } else { //early rejection criteria passed, send some geometry to the query - LLVector3 c; - LLVector3 r; - - sg_assert(!group->isState(LLSpatialGroup::DIRTY)); - - c = group->mBounds[0]; - r = group->mBounds[1]*SG_OCCLUSION_FUDGE + LLVector3(0.01f,0.01f,0.01f); - for (U32 k = 0; k < 3; k++) - { - r.mV[k] = llmin(group->mBounds[1].mV[k]+0.25f, r.mV[k]); - } - -#if LL_OCTREE_PARANOIA_CHECK - LLVector3 e = camera->getOrigin(); - LLVector3 min = c - r; - LLVector3 max = c + r; - BOOL outside = FALSE; - for (U32 j = 0; j < 3; j++) - { - outside = outside || (e.mV[j] < min.mV[j] || e.mV[j] > max.mV[j]); - } - sg_assert(outside); -#endif - + group->mOcclusionVerts->setBuffer(LLVertexBuffer::MAP_VERTEX); glBeginQueryARB(GL_SAMPLES_PASSED_ARB, mOcclusionQueries[i]); - drawBox(c,r); + glDrawRangeElements(GL_TRIANGLES, 0, 7, 36, + GL_UNSIGNED_INT, indicesp); glEndQueryARB(GL_SAMPLES_PASSED_ARB); group->setState(LLSpatialGroup::QUERY_OUT); @@ -1497,10 +2175,11 @@ void LLSpatialPartition::doOcclusion(LLCamera* camera) } stop_glerror(); + gPipeline.mTrianglesDrawn += mOccludedList.size()*12; + glFlush(); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - glEnable(GL_TEXTURE_2D); } class LLOctreeGet : public LLSpatialGroup::OctreeTraveler @@ -1599,6 +2278,8 @@ S32 LLSpatialPartition::getDrawables(const LLVector3& pos, F32 rad, S32 LLSpatialPartition::getObjects(const LLVector3& pos, F32 rad, LLDrawable::drawable_set_t &results) { + LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0); + group->rebound(); return getDrawables(pos, rad, results, FALSE); } @@ -1607,182 +2288,346 @@ S32 LLSpatialPartition::getLights(const LLVector3& pos, F32 rad, LLDrawable::dra return getDrawables(pos, rad, results, TRUE); } -class LLOctreeRenderNonOccluded : public LLOctreeTraveler<LLDrawable> +void pushVerts(LLSpatialGroup* group, U32 mask) { -public: - LLOctreeRenderNonOccluded() {} - - virtual void traverse(const LLSpatialGroup::OctreeNode* node) + LLDrawInfo* params = NULL; + + for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i) { - const LLSpatialGroup::OctreeState* state = node->getOctState(); - LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0); + for (std::vector<LLDrawInfo*>::iterator j = i->second.begin(); j != i->second.end(); ++j) + { + params = *j; + params->mVertexBuffer->setBuffer(mask); + U32* indicesp = (U32*) params->mVertexBuffer->getIndicesPointer(); + glDrawRangeElements(params->mParticle ? GL_POINTS : GL_TRIANGLES, params->mStart, params->mEnd, params->mCount, + GL_UNSIGNED_INT, indicesp+params->mOffset); + } + } +} + +void pushVertsColorCoded(LLSpatialGroup* group, U32 mask) +{ + LLDrawInfo* params = NULL; + + LLColor4 colors[] = { + LLColor4::green, + LLColor4::green1, + LLColor4::green2, + LLColor4::green3, + LLColor4::green4, + LLColor4::green5, + LLColor4::green6 + }; - if (!group->isState(LLSpatialGroup::OCCLUDED | LLSpatialGroup::CULLED)) + static const U32 col_count = sizeof(colors)/sizeof(LLColor4); + + U32 col = 0; + + for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i) + { + for (std::vector<LLDrawInfo*>::iterator j = i->second.begin(); j != i->second.end(); ++j) { - state->accept(this); + params = *j; + glColor4f(colors[col].mV[0], colors[col].mV[1], colors[col].mV[2], 0.5f); + params->mVertexBuffer->setBuffer(mask); + U32* indicesp = (U32*) params->mVertexBuffer->getIndicesPointer(); + glDrawRangeElements(params->mParticle ? GL_POINTS : GL_TRIANGLES, params->mStart, params->mEnd, params->mCount, + GL_UNSIGNED_INT, indicesp+params->mOffset); + col = (col+1)%col_count; + } + } +} - for (U32 i = 0; i < state->getChildCount(); i++) +void renderOctree(LLSpatialGroup* group) +{ + //render solid object bounding box, color + //coded by buffer usage and activity + LLGLDepthTest depth(GL_TRUE, GL_FALSE); + glBlendFunc(GL_SRC_ALPHA, GL_ONE); + LLVector4 col; + if (group->mBuilt > 0.f) + { + group->mBuilt -= 2.f * gFrameIntervalSeconds; + if (group->mBufferUsage == GL_STATIC_DRAW_ARB) + { + col.setVec(1.0f, 0, 0, group->mBuilt*0.5f); + } + else + { + col.setVec(0.1f,0.1f,1,0.1f); + //col.setVec(1.0f, 1.0f, 0, sinf(group->mBuilt*3.14159f)*0.5f); + } + + if (group->mBufferUsage != GL_STATIC_DRAW_ARB) + { + if (group->mBufferUsage == GL_DYNAMIC_DRAW_ARB) { - traverse(state->getChild(i)); + glColor4f(1,0,0,group->mBuilt); } - - /*if (state->getElementCount() == 0) + else { - return; - }*/ + glColor4f(1,1,0,group->mBuilt); + } - //draw tight fit bounding box for spatial group - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCTREE)) + LLGLDepthTest gl_depth(FALSE, FALSE); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i) { - if (node->getElementCount() == 0) - { - return; - } - - if (node->hasLeafState()) - { - glColor4f(1,1,1,1); - } - else + LLDrawable* drawable = *i; + for (S32 j = 0; j < drawable->getNumFaces(); j++) { - glColor4f(0,1,1,1); + LLFace* face = drawable->getFace(j); + if (gFrameTimeSeconds - face->mLastUpdateTime < 0.5f && face->mVertexBuffer.notNull()) + { + face->mVertexBuffer->setBuffer(LLVertexBuffer::MAP_VERTEX); + //drawBox((face->mExtents[0] + face->mExtents[1])*0.5f, + // (face->mExtents[1]-face->mExtents[0])*0.5f); + glDrawElements(GL_TRIANGLES, face->getIndicesCount(), GL_UNSIGNED_INT, + ((U32*) face->mVertexBuffer->getIndicesPointer())+face->getIndicesStart()); + } } + } + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + } + } + else + { + if (group->mBufferUsage == GL_STATIC_DRAW_ARB && !group->getData().empty() + && group->mSpatialPartition->mRenderByGroup) + { + col.setVec(0.8f, 0.4f, 0.1f, 0.1f); + } + else + { + col.setVec(0.1f, 0.1f, 1.f, 0.1f); + } + } + glColor4fv(col.mV); + drawBox(group->mObjectBounds[0], group->mObjectBounds[1]*1.01f+LLVector3(0.001f, 0.001f, 0.001f)); + glDepthMask(GL_TRUE); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - LLVector3 pos; - LLVector3 size; - - pos = group->mObjectBounds[0]; - size = group->mObjectBounds[1]; - - LLVector3 v1 = size.scaledVec(LLVector3( 1, 1,1)); - LLVector3 v2 = size.scaledVec(LLVector3(-1, 1,1)); - LLVector3 v3 = size.scaledVec(LLVector3(-1,-1,1)); - LLVector3 v4 = size.scaledVec(LLVector3( 1,-1,1)); - - glBegin(GL_LINE_LOOP); //top - glVertex3fv((pos+v1).mV); - glVertex3fv((pos+v2).mV); - glVertex3fv((pos+v3).mV); - glVertex3fv((pos+v4).mV); - glEnd(); - - glBegin(GL_LINE_LOOP); //bottom - glVertex3fv((pos-v1).mV); - glVertex3fv((pos-v2).mV); - glVertex3fv((pos-v3).mV); - glVertex3fv((pos-v4).mV); - glEnd(); - - - glBegin(GL_LINES); - - //right - glVertex3fv((pos+v1).mV); - glVertex3fv((pos-v3).mV); - - glVertex3fv((pos+v4).mV); - glVertex3fv((pos-v2).mV); - - //left - glVertex3fv((pos+v2).mV); - glVertex3fv((pos-v4).mV); - - glVertex3fv((pos+v3).mV); - glVertex3fv((pos-v1).mV); + //draw opaque outline + glColor4f(col.mV[0], col.mV[1], col.mV[2], 1.f); + drawBoxOutline(group->mObjectBounds[0], group->mObjectBounds[1]); - glEnd(); + if (group->mOctreeNode->hasLeafState()) + { + glColor4f(1,1,1,1); + } + else + { + glColor4f(0,1,1,1); + } + + drawBoxOutline(group->mBounds[0],group->mBounds[1]); + +// LLSpatialGroup::OctreeNode* node = group->mOctreeNode; +// glColor4f(0,1,0,1); +// drawBoxOutline(LLVector3(node->getCenter()), LLVector3(node->getSize())); +} - LLVector3 nc = LLVector3(node->getCenter()); - LLVector3 ns = LLVector3(node->getSize()); +void renderVisibility(LLSpatialGroup* group) +{ + LLGLEnable blend(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + LLGLEnable cull(GL_CULL_FACE); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + { + LLGLDepthTest depth_under(GL_TRUE, GL_FALSE, GL_GREATER); + glColor4f(0, 0.5f, 0, 0.5f); + pushVerts(group, LLVertexBuffer::MAP_VERTEX); + } - LLVector3 nv1 = ns.scaledVec(LLVector3( 1, 1,1)); - LLVector3 nv2 = ns.scaledVec(LLVector3(-1, 1,1)); - LLVector3 nv3 = ns.scaledVec(LLVector3(-1,-1,1)); - LLVector3 nv4 = ns.scaledVec(LLVector3( 1,-1,1)); + { + LLGLDepthTest depth_over(GL_TRUE, GL_FALSE, GL_LEQUAL); + pushVertsColorCoded(group, LLVertexBuffer::MAP_VERTEX); - + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - /*if (node->getElementCount() > 0) - { - //spokes - glColor4f(1,1,0,1); - glVertex3fv(pos.mV); - glColor4f(1,1,0,0); - glVertex3fv(nc.mV); - - glColor4f(1,1,0,1); glVertex3fv((pos+v1).mV); glColor4f(1,1,0,0); glVertex3fv(pos.mV); - glColor4f(1,1,0,1); glVertex3fv((pos-v1).mV); glColor4f(1,1,0,0); glVertex3fv(pos.mV); - glColor4f(1,1,0,1); glVertex3fv((pos+v2).mV); glColor4f(1,1,0,0); glVertex3fv(pos.mV); - glColor4f(1,1,0,1); glVertex3fv((pos-v2).mV); glColor4f(1,1,0,0); glVertex3fv(pos.mV); - glColor4f(1,1,0,1); glVertex3fv((pos+v3).mV); glColor4f(1,1,0,0); glVertex3fv(pos.mV); - glColor4f(1,1,0,1); glVertex3fv((pos-v3).mV); glColor4f(1,1,0,0); glVertex3fv(pos.mV); - glColor4f(1,1,0,1); glVertex3fv((pos+v4).mV); glColor4f(1,1,0,0); glVertex3fv(pos.mV); - glColor4f(1,1,0,1); glVertex3fv((pos-v4).mV); glColor4f(1,1,0,0); glVertex3fv(pos.mV); - }*/ + pushVertsColorCoded(group, LLVertexBuffer::MAP_VERTEX); + } +} - +void renderBoundingBox(LLDrawable* drawable) +{ + if (drawable->isSpatialBridge()) + { + glColor4f(1,0.5f,0,1); + } + else if (drawable->getVOVolume()) + { + if (drawable->isRoot()) + { + glColor4f(1,1,0,1); + } + else + { + glColor4f(0,1,0,1); + } + } + else if (drawable->getVObj()) + { + switch (drawable->getVObj()->getPCode()) + { + case LLViewerObject::LL_VO_SURFACE_PATCH: + glColor4f(0,1,1,1); + break; + case LLViewerObject::LL_VO_CLOUDS: + glColor4f(0.5f,0.5f,0.5f,1.0f); + break; + case LLViewerObject::LL_VO_PART_GROUP: + glColor4f(0,0,1,1); + break; + case LLViewerObject::LL_VO_WATER: + glColor4f(0,0.5f,1,1); + break; + case LL_PCODE_LEGACY_TREE: + glColor4f(0,0.5f,0,1); + default: + glColor4f(1,0,1,1); + break; + } + } + else + { + glColor4f(1,0,0,1); + } - /*glColor4f(0,1,0,1); - glBegin(GL_LINE_LOOP); //top - glVertex3fv((nc+nv1).mV); - glVertex3fv((nc+nv2).mV); - glVertex3fv((nc+nv3).mV); - glVertex3fv((nc+nv4).mV); - glEnd(); + const LLVector3* ext; + LLVector3 pos, size; - glBegin(GL_LINE_LOOP); //bottom - glVertex3fv((nc-nv1).mV); - glVertex3fv((nc-nv2).mV); - glVertex3fv((nc-nv3).mV); - glVertex3fv((nc-nv4).mV); - glEnd(); + //render face bounding boxes + for (S32 i = 0; i < drawable->getNumFaces(); i++) + { + LLFace* facep = drawable->getFace(i); + ext = facep->mExtents; - glBegin(GL_LINES); + if (ext[0].isExactlyZero() && ext[1].isExactlyZero()) + { + continue; + } + pos = (ext[0] + ext[1]) * 0.5f; + size = (ext[1] - ext[0]) * 0.5f; + drawBoxOutline(pos,size); + } - //right - glVertex3fv((nc+nv1).mV); - glVertex3fv((nc-nv3).mV); - - glVertex3fv((nc+nv4).mV); - glVertex3fv((nc-nv2).mV); + //render drawable bounding box + ext = drawable->getSpatialExtents(); - //left - glVertex3fv((nc+nv2).mV); - glVertex3fv((nc-nv4).mV); + pos = (ext[0] + ext[1]) * 0.5f; + size = (ext[1] - ext[0]) * 0.5f; + + drawBoxOutline(pos,size); +} - glVertex3fv((nc+nv3).mV); - glVertex3fv((nc-nv1).mV); - glEnd();*/ +void renderTexturePriority(LLDrawable* drawable) +{ + for (int face=0; face<drawable->getNumFaces(); ++face) + { + LLFace *facep = drawable->getFace(face); + + LLVector4 cold(0,0,0.25f); + LLVector4 hot(1,0.25f,0.25f); + + LLVector4 boost_cold(0,0,0,0); + LLVector4 boost_hot(0,1,0,1); + + LLGLDisable blend(GL_BLEND); + + //LLViewerImage* imagep = facep->getTexture(); + //if (imagep) + { + + //F32 vsize = LLVOVolume::getTextureVirtualSize(facep); + //F32 vsize = imagep->mMaxVirtualSize; + F32 vsize = facep->getPixelArea(); - glLineWidth(1); - - glDepthMask(GL_FALSE); - glBlendFunc(GL_SRC_ALPHA, GL_ONE); - glColor4f(0.1f,0.1f,1,0.1f); - drawBox(group->mObjectBounds[0], group->mObjectBounds[1]*1.01f+LLVector3(0.001f, 0.001f, 0.001f)); - glDepthMask(GL_TRUE); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + if (vsize > sCurMaxTexPriority) + { + sCurMaxTexPriority = vsize; } + + F32 t = vsize/sLastMaxTexPriority; + + LLVector4 col = lerp(cold, hot, t); + glColor4fv(col.mV); } - /*else + //else + //{ + // glColor4f(1,0,1,1); + //} + + + + LLVector3 center = (facep->mExtents[1]+facep->mExtents[0])*0.5f; + LLVector3 size = (facep->mExtents[1]-facep->mExtents[0])*0.5f + LLVector3(0.01f, 0.01f, 0.01f); + drawBox(center, size); + + /*S32 boost = imagep->getBoostLevel(); + if (boost) + { + F32 t = (F32) boost / (F32) (LLViewerImage::BOOST_MAX_LEVEL-1); + LLVector4 col = lerp(boost_cold, boost_hot, t); + LLGLEnable blend_on(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE); + glColor4fv(col.mV); + drawBox(center, size); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + }*/ + } +} + +void renderPoints(LLDrawable* drawablep) +{ + LLGLDepthTest depth(GL_FALSE, GL_FALSE); + glBegin(GL_POINTS); + glColor3f(1,1,1); + LLVector3 center(drawablep->getPositionGroup()); + for (S32 i = 0; i < drawablep->getNumFaces(); i++) + { + glVertex3fv(drawablep->getFace(i)->mCenterLocal.mV); + } + glEnd(); +} + +class LLOctreeRenderNonOccluded : public LLOctreeTraveler<LLDrawable> +{ +public: + LLOctreeRenderNonOccluded() {} + + virtual void traverse(const LLSpatialGroup::OctreeNode* node) + { + const LLSpatialGroup::OctreeState* state = node->getOctState(); + LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0); + + + if ((!gPipeline.sUseOcclusion || !group->isState(LLSpatialGroup::OCCLUDED)) && + !group->isState(LLSpatialGroup::CULLED)) { - //occlusion paranoia check - const LLSpatialGroup::OctreeNode* parent = node; - while (parent != NULL) + state->accept(this); + + for (U32 i = 0; i < state->getChildCount(); i++) { - LLSpatialGroup* grp = (LLSpatialGroup*) parent->getListener(0); - if (grp->isState(LLSpatialGroup::ACTIVE_OCCLUSION)) - { - return; - } - parent = (const LLSpatialGroup::OctreeNode*) parent->getParent(); + traverse(state->getChild(i)); + } + + //draw tight fit bounding boxes for spatial group + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCTREE)) + { + renderOctree(group); } - glColor4f(1,0,1,1); - drawBox(group->mBounds[0], group->mBounds[1]); - }*/ + //render visibility wireframe + if (group->mSpatialPartition->mRenderByGroup && + gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION) && + !group->isState(LLSpatialGroup::GEOM_DIRTY)) + { + renderVisibility(group); + } + } } virtual void visit(const LLSpatialGroup::OctreeState* branch) @@ -1797,276 +2642,24 @@ public: LLVector3 nodeCenter = group->mBounds[0]; LLVector3 octCenter = LLVector3(group->mOctreeNode->getCenter()); - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCTREE)) - { - glBegin(GL_LINES); - glColor4f(1,0.5f,0,1); - glVertex3fv(nodeCenter.mV); - glColor4f(0,1,1,0); - glVertex3fv(octCenter.mV); - glEnd(); - } - for (LLSpatialGroup::OctreeState::const_element_iter i = branch->getData().begin(); i != branch->getData().end(); ++i) { LLDrawable* drawable = *i; - - if (drawable->isSpatialBridge()) - { - LLSpatialBridge* bridge = (LLSpatialBridge*) drawable; - glPushMatrix(); - glMultMatrixf((F32*)bridge->mDrawable->getWorldMatrix().mMatrix); - traverse(bridge->mOctree); - glPopMatrix(); - } - - if (!drawable->isVisible()) - { - continue; - } - + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BBOXES)) { - if (drawable->isSpatialBridge()) - { - glColor4f(1,0.5f,0,1); - } - else if (drawable->getVOVolume()) - { - if (drawable->isRoot()) - { - glColor4f(1,1,0,1); - } - else - { - glColor4f(0,1,0,1); - } - } - else if (drawable->getVObj()) - { - switch (drawable->getVObj()->getPCode()) - { - case LLViewerObject::LL_VO_SURFACE_PATCH: - glColor4f(0,1,1,1); - break; - case LLViewerObject::LL_VO_CLOUDS: - glColor4f(0.5f,0.5f,0.5f,1.0f); - break; - case LLViewerObject::LL_VO_PART_GROUP: - glColor4f(0,0,1,1); - break; - case LLViewerObject::LL_VO_WATER: - glColor4f(0,0.5f,1,1); - break; - case LL_PCODE_LEGACY_TREE: - glColor4f(0,0.5f,0,1); - default: - glColor4f(1,0,1,1); - break; - } - } - else - { - glColor4f(1,0,0,1); - } - - - const LLVector3* ext = drawable->getSpatialExtents(); - - LLVector3 pos = (ext[0] + ext[1]) * 0.5f; - LLVector3 size = (ext[1] - ext[0]) * 0.5f; - - LLVector3 v1 = size.scaledVec(LLVector3( 1, 1,1)); - LLVector3 v2 = size.scaledVec(LLVector3(-1, 1,1)); - LLVector3 v3 = size.scaledVec(LLVector3(-1,-1,1)); - LLVector3 v4 = size.scaledVec(LLVector3( 1,-1,1)); - - glBegin(GL_LINE_LOOP); //top - glVertex3fv((pos+v1).mV); - glVertex3fv((pos+v2).mV); - glVertex3fv((pos+v3).mV); - glVertex3fv((pos+v4).mV); - glEnd(); - - glBegin(GL_LINE_LOOP); //bottom - glVertex3fv((pos-v1).mV); - glVertex3fv((pos-v2).mV); - glVertex3fv((pos-v3).mV); - glVertex3fv((pos-v4).mV); - glEnd(); - - - glBegin(GL_LINES); - - //right - glVertex3fv((pos+v1).mV); - glVertex3fv((pos-v3).mV); - - glVertex3fv((pos+v4).mV); - glVertex3fv((pos-v2).mV); - - //left - glVertex3fv((pos+v2).mV); - glVertex3fv((pos-v4).mV); - - glVertex3fv((pos+v3).mV); - glVertex3fv((pos-v1).mV); - - glEnd(); - - //render space partition trace - glBegin(GL_LINE_STRIP); - glColor4f(1,0,0,1); - glVertex3fv(pos.mV); - glColor4f(0,1,0,1); - glVertex3dv(drawable->getPositionGroup().mdV); - glColor4f(0,0,1,1); - glVertex3fv(nodeCenter.mV); - glColor4f(1,1,0,1); - glVertex3fv(octCenter.mV); - glEnd(); + renderBoundingBox(drawable); } - if (drawable->getVOVolume() && gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_FACE_CHAINS | LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY)) + if (drawable->getVOVolume() && gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY)) { - glLineWidth(3); - - for (int face=0; face<drawable->getNumFaces(); ++face) - { - LLFace *facep = drawable->getFace(face); - - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_FACE_CHAINS)) - { - LLGLDepthTest depth(GL_FALSE); - if (facep->mNextFace) - { - glBegin(GL_LINE_STRIP); - - if (facep->isState(LLFace::GLOBAL)) - { - glColor4f(0,1,0,1); - } - else - { - glColor4f(1,0.5f,0.25f,1); - } - - if (drawable->isActive()) - { - glVertex3fv(facep->mCenterLocal.mV); - glVertex3fv(facep->mNextFace->mCenterLocal.mV); - } - else - { - glVertex3fv(facep->mCenterAgent.mV); - glVertex3fv(facep->mNextFace->mCenterAgent.mV); - } - - glEnd(); - } - else - { - glPointSize(5); - glBegin(GL_POINTS); - - if (!facep->isState(LLFace::GLOBAL)) - { - glColor4f(1,0.75f,0,1); - glVertex3fv(facep->mCenterLocal.mV); - } - else - { - glColor4f(0,0.75f,1,1); - glVertex3fv(facep->mCenterAgent.mV); - } - - glEnd(); - glPointSize(1); - } - } - - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY)) - { - LLVector4 cold(0,0,0.25f); - LLVector4 hot(1,0.25f,0.25f); - - LLVector4 boost_cold(0,0,0,0); - LLVector4 boost_hot(0,1,0,1); - - LLGLDisable blend(GL_BLEND); - - LLViewerImage* imagep = facep->getTexture(); - if (imagep) - { - - //F32 vsize = LLVOVolume::getTextureVirtualSize(facep); - F32 vsize = imagep->mMaxVirtualSize; - - if (vsize > sCurMaxTexPriority) - { - sCurMaxTexPriority = vsize; - } - - F32 t = vsize/sLastMaxTexPriority; - - LLVector4 col = lerp(cold, hot, t); - glColor4fv(col.mV); - } - else - { - glColor4f(1,0,1,1); - } - - LLVector3 center = (facep->mExtents[1]+facep->mExtents[0])*0.5f; - LLVector3 size = (facep->mExtents[1]-facep->mExtents[0])*0.5f + LLVector3(0.01f, 0.01f, 0.01f); - drawBox(center, size); - - S32 boost = imagep->getBoostLevel(); - if (boost) - { - F32 t = (F32) boost / (F32) (LLViewerImage::BOOST_MAX_LEVEL-1); - LLVector4 col = lerp(boost_cold, boost_hot, t); - LLGLEnable blend_on(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE); - glColor4fv(col.mV); - drawBox(center, size); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - } - - } - } + renderTexturePriority(drawable); } - + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_POINTS)) { - glPointSize(4); - glColor4f(1,1,1,1); - glBegin(GL_POINTS); - S32 num_faces = drawable->getNumFaces(); - for (S32 i = 0; i < num_faces; i++) - { - LLStrider<LLVector3> vertices; - drawable->getFace(i)->getVertices(vertices); - - LLFace* face = drawable->getFace(i); - - for (S32 v = 0; v < (S32)drawable->getFace(i)->getGeomCount(); v++) - { - if (!face->getDrawable()->isActive()) - { - //glVertex3fv(vertices[v].mV); - } - else - { - glVertex3fv((vertices[v]*face->getRenderMatrix()).mV); - } - } - } - glEnd(); - glPointSize(1); + renderPoints(drawable); } - - glLineWidth(1); } } }; @@ -2077,7 +2670,6 @@ void LLSpatialPartition::renderDebug() LLPipeline::RENDER_DEBUG_OCCLUSION | LLPipeline::RENDER_DEBUG_BBOXES | LLPipeline::RENDER_DEBUG_POINTS | - LLPipeline::RENDER_DEBUG_FACE_CHAINS | LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY)) { return; @@ -2086,7 +2678,7 @@ void LLSpatialPartition::renderDebug() if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY)) { //sLastMaxTexPriority = lerp(sLastMaxTexPriority, sCurMaxTexPriority, gFrameIntervalSeconds); - sLastMaxTexPriority = sCurMaxTexPriority; + sLastMaxTexPriority = (F32) gCamera->getScreenPixelArea(); sCurMaxTexPriority = 0.f; } @@ -2100,78 +2692,50 @@ void LLSpatialPartition::renderDebug() LLOctreeRenderNonOccluded render_debug; render_debug.traverse(mOctree); - - LLGLDisable cull_face(GL_CULL_FACE); - { - LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE); - - //draw frustum - glColor4f(0,0,1,0.5f); - glBegin(GL_QUADS); - //glVertex3fv(gCamera->mAgentFrustum[0].mV); - //glVertex3fv(gCamera->mAgentFrustum[1].mV); - //glVertex3fv(gCamera->mAgentFrustum[2].mV); - //glVertex3fv(gCamera->mAgentFrustum[3].mV); + LLGLDisable cull_face(GL_CULL_FACE); - //glVertex3fv(gCamera->mAgentFrustum[4].mV); - //glVertex3fv(gCamera->mAgentFrustum[5].mV); - //glVertex3fv(gCamera->mAgentFrustum[6].mV); - //glVertex3fv(gCamera->mAgentFrustum[7].mV); - - glVertex3fv(gCamera->mAgentFrustum[0].mV); - glVertex3fv(gCamera->mAgentFrustum[1].mV); - glVertex3fv(gCamera->mAgentFrustum[5].mV); - glVertex3fv(gCamera->mAgentFrustum[4].mV); - - glVertex3fv(gCamera->mAgentFrustum[1].mV); - glVertex3fv(gCamera->mAgentFrustum[2].mV); - glVertex3fv(gCamera->mAgentFrustum[6].mV); - glVertex3fv(gCamera->mAgentFrustum[5].mV); - - glVertex3fv(gCamera->mAgentFrustum[2].mV); - glVertex3fv(gCamera->mAgentFrustum[3].mV); - glVertex3fv(gCamera->mAgentFrustum[7].mV); - glVertex3fv(gCamera->mAgentFrustum[6].mV); - - glVertex3fv(gCamera->mAgentFrustum[3].mV); - glVertex3fv(gCamera->mAgentFrustum[0].mV); - glVertex3fv(gCamera->mAgentFrustum[4].mV); - glVertex3fv(gCamera->mAgentFrustum[7].mV); - - glEnd(); - } - - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION)) + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION) && !mOccludedList.empty() && + mOcclusionIndices.notNull()) { LLGLDisable fog(GL_FOG); LLGLDepthTest gls_depth(GL_FALSE); glBlendFunc(GL_SRC_ALPHA, GL_ONE); + mOcclusionIndices->setBuffer(0); + U32* indicesp = (U32*) mOcclusionIndices->getIndicesPointer(); + + LLGLEnable blend(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + LLGLEnable cull(GL_CULL_FACE); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - for (std::vector<LLSpatialGroup*>::iterator i = mOccludedList.begin(); i != mOccludedList.end(); ++i) + for (U32 i = 0; i < mOccludedList.size(); i++) { //draw occluded nodes - LLSpatialGroup* node = *i; - if (node->isDead()) + LLSpatialGroup* node = mOccludedList[i]; + if (node->isDead() || + !node->isState(LLSpatialGroup::OCCLUDED) || + node->mOcclusionVerts.isNull()) { continue; } - if (!node->isState(LLSpatialGroup::OCCLUDED)) + + node->mOcclusionVerts->setBuffer(LLVertexBuffer::MAP_VERTEX); { - continue; + LLGLDepthTest depth_under(GL_TRUE, GL_FALSE, GL_GREATER); + glColor4f(0.5, 0.5f, 0, 0.25f); + glDrawRangeElements(GL_TRIANGLES, 0, 7, 36, + GL_UNSIGNED_INT, indicesp); } - else + { - glColor4f(0.25f,0.125f,0.1f,0.125f); + LLGLDepthTest depth_over(GL_TRUE, GL_FALSE, GL_LEQUAL); + glColor4f(0.0,1.0f,1.0f,1.0f); + glDrawRangeElements(GL_TRIANGLES, 0, 7, 36, + GL_UNSIGNED_INT, indicesp); } - LLVector3 c; - LLVector3 r; - - c = node->mBounds[0]; - r = node->mBounds[1]*SG_OCCLUSION_FUDGE + LLVector3(0.01f,0.01f,0.01f);; - - drawBox(c,r); } - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } } @@ -2253,3 +2817,19 @@ LLDrawable* LLSpatialPartition::pickDrawable(const LLVector3& start, const LLVec collision.setVec(pick.mEnd); return ret; } + +LLDrawInfo::LLDrawInfo(U32 start, U32 end, U32 count, U32 offset, + LLViewerImage* texture, LLVertexBuffer* buffer, + BOOL fullbright, U8 bump, BOOL particle, F32 part_size) +: mStart(start), mEnd(end), mCount(count), mOffset(offset), + mTexture(texture), mVertexBuffer(buffer), + mFullbright(fullbright), mBump(bump), + mParticle(particle), mPartSize(part_size), + mVSize(0.f), mTextureMatrix(NULL) +{ +} + +LLVertexBuffer* LLGeometryManager::createVertexBuffer(U32 type_mask, U32 usage) +{ + return new LLVertexBuffer(type_mask, usage); +} diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h index 012e3a9e82..10312ba0e6 100644 --- a/indra/newview/llspatialpartition.h +++ b/indra/newview/llspatialpartition.h @@ -14,26 +14,76 @@ #include "llmemory.h" #include "lldrawable.h" #include "lloctree.h" +#include "llvertexbuffer.h" #include "llgltypes.h" +#include "llcubemap.h" #include <queue> -class LLCullInfo +#define SG_STATE_INHERIT_MASK (CULLED | OCCLUDED) +#define SG_INITIAL_STATE_MASK (OCCLUSION_DIRTY | DIRTY | GEOM_DIRTY) + +class LLSpatialPartition; +class LLSpatialBridge; + +class LLDrawInfo { public: - LLVector3 mPos; - F32 mRadius; - LLPointer<LLDrawable> mDrawablep; -}; + LLDrawInfo(U32 start, U32 end, U32 count, U32 offset, + LLViewerImage* image, LLVertexBuffer* buffer, + BOOL fullbright = FALSE, U8 bump = 0, BOOL particle = FALSE, F32 part_size = 0); + + LLPointer<LLVertexBuffer> mVertexBuffer; + LLPointer<LLViewerImage> mTexture; + LLPointer<LLCubeMap> mReflectionMap; + const LLMatrix4* mTextureMatrix; + U32 mStart; + U32 mEnd; + U32 mCount; + U32 mOffset; + BOOL mFullbright; + U8 mBump; + BOOL mParticle; + F32 mPartSize; + F32 mVSize; + + struct CompareTexture + { + bool operator()(const LLDrawInfo& lhs, const LLDrawInfo& rhs) + { + return lhs.mTexture > rhs.mTexture; + } + }; -#define SG_STATE_INHERIT_MASK (CULLED | OCCLUDED) -class LLSpatialPartition; + struct CompareTexturePtr + { + bool operator()(const LLDrawInfo* const& lhs, const LLDrawInfo* const& rhs) + { + + return lhs == NULL || rhs == NULL || lhs->mTexture > rhs->mTexture; + } + }; + + struct CompareBump + { + bool operator()(const LLDrawInfo* const& lhs, const LLDrawInfo* const& rhs) + { + return lhs == NULL || rhs == NULL || lhs->mBump > rhs->mBump; + } + }; +}; class LLSpatialGroup : public LLOctreeListener<LLDrawable> { friend class LLSpatialPartition; public: + typedef std::vector<LLPointer<LLSpatialGroup> > sg_vector_t; + typedef std::set<LLPointer<LLSpatialGroup> > sg_set_t; + typedef std::vector<LLPointer<LLSpatialBridge> > bridge_list_t; + typedef std::map<U32, std::vector<LLDrawInfo*> > draw_map_t; + typedef std::map<LLPointer<LLViewerImage>, LLPointer<LLVertexBuffer> > buffer_map_t; + typedef LLOctreeListener<LLDrawable> BaseType; typedef LLOctreeListener<LLDrawable> OctreeListener; typedef LLTreeNode<LLDrawable> TreeNode; @@ -41,6 +91,24 @@ public: typedef LLOctreeRoot<LLDrawable> OctreeRoot; typedef LLOctreeState<LLDrawable> OctreeState; typedef LLOctreeTraveler<LLDrawable> OctreeTraveler; + typedef LLOctreeState<LLDrawable>::element_iter element_iter; + typedef LLOctreeState<LLDrawable>::element_list element_list; + + struct CompareDistanceGreater + { + bool operator()(const LLSpatialGroup* const& lhs, const LLSpatialGroup* const& rhs) + { + return lhs->mDistance > rhs->mDistance; + } + }; + + struct CompareDepthGreater + { + bool operator()(const LLSpatialGroup* const& lhs, const LLSpatialGroup* const& rhs) + { + return lhs->mDepth > rhs->mDepth; + } + }; typedef enum { @@ -56,10 +124,18 @@ public: RESHADOW_QUEUE = 0x00000200, DIRTY = 0x00000400, OBJECT_DIRTY = 0x00000800, - DISCARD_QUERY = 0x00001000, - QUERY_OUT = 0x00002000, - OCCLUDING = 0x00004000, - SKIP_FRUSTUM_CHECK = 0x00008000, + GEOM_DIRTY = 0x00001000, + MATRIX_DIRTY = 0x00002000, + ALPHA_DIRTY = 0x00004000, + DISCARD_QUERY = 0x00008000, + QUERY_OUT = 0x00010000, + OCCLUDING = 0x00020000, + SKIP_FRUSTUM_CHECK = 0x00040000, + OCCLUSION_DIRTY = 0x00080000, + BELOW_WATER = 0x00100000, + IN_GEOMETRY_QUEUE = 0x00200000, + IN_IMAGE_QUEUE = 0x00400000, + IMAGE_DIRTY = 0x00800000, } eSpatialState; typedef enum @@ -73,17 +149,19 @@ public: BOOL safeToDelete(); virtual ~LLSpatialGroup(); - S32 getCount() const { return mObjects.size(); } BOOL isDead() { return isState(DEAD); } BOOL isState(U32 state) const { return mState & state ? TRUE : FALSE; } U32 getState() { return mState; } void setState(U32 state) { mState |= state; } void clearState(U32 state) { mState &= ~state; } + void clearDrawMap(); void validate(); - + void validateDrawMap(); + void setState(U32 state, S32 mode); + LLSpatialGroup* getParent(); void clearState(U32 state, S32 mode); BOOL addObject(LLDrawable *drawablep, BOOL add_all = FALSE, BOOL from_octree = FALSE); @@ -94,8 +172,15 @@ public: BOOL boundObjects(BOOL empty, LLVector3& newMin, LLVector3& newMax); void unbound(); BOOL rebound(); + + void updateDistance(LLCamera& camera); BOOL changeLOD(); - + void rebuildGeom(); + void makeStatic(); + + void dirtyGeom() { setState(GEOM_DIRTY); } + element_list& getData() { return mOctreeNode->getOctState()->getData(); } + //LISTENER FUNCTIONS virtual void handleInsertion(const TreeNode* node, LLDrawable* face); virtual void handleRemoval(const TreeNode* node, LLDrawable* face); @@ -105,12 +190,15 @@ public: virtual void handleChildRemoval(const OctreeNode* parent, const OctreeNode* child); protected: - std::vector<LLCullInfo> mObjects; U32 mState; S32 mLODHash; static S32 sLODSeed; public: + bridge_list_t mBridgeList; + buffer_map_t mBufferMap; //used by volume buffers to store unique buffers per texture + + F32 mBuilt; OctreeNode* mOctreeNode; LLSpatialPartition* mSpatialPartition; LLVector3 mBounds[2]; @@ -118,69 +206,132 @@ public: LLVector3 mObjectExtents[2]; LLVector3 mObjectBounds[2]; + LLPointer<LLVertexBuffer> mVertexBuffer; + LLPointer<LLVertexBuffer> mOcclusionVerts; + LLPointer<LLCubeMap> mReflectionMap; + + U32 mBufferUsage; + draw_map_t mDrawMap; + + U32 mVertexCount; + U32 mIndexCount; + F32 mDistance; + F32 mDepth; + F32 mLastUpdateDistance; + F32 mLastUpdateTime; + F32 mLastAddTime; + F32 mLastRenderTime; + + LLVector3 mViewAngle; + LLVector3 mLastUpdateViewAngle; + + F32 mPixelArea; + F32 mRadius; }; -class LLSpatialPartition +class LLGeometryManager { public: - LLSpatialPartition(); + std::vector<LLFace*> mFaceList; + virtual ~LLGeometryManager() { } + virtual void rebuildGeom(LLSpatialGroup* group) = 0; + virtual void getGeometry(LLSpatialGroup* group) = 0; + virtual void addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32 &index_count); + virtual LLVertexBuffer* createVertexBuffer(U32 type_mask, U32 usage); +}; + +class LLSpatialPartition: public LLGeometryManager +{ +public: + LLSpatialPartition(U32 data_mask, BOOL is_volatile = FALSE, U32 mBufferUsage = GL_STATIC_DRAW_ARB); virtual ~LLSpatialPartition(); - LLSpatialGroup *put(LLDrawable *drawablep); + LLSpatialGroup *put(LLDrawable *drawablep, BOOL was_visible = FALSE); BOOL remove(LLDrawable *drawablep, LLSpatialGroup *curp); LLDrawable* pickDrawable(const LLVector3& start, const LLVector3& end, LLVector3& collision); // If the drawable moves, move it here. virtual void move(LLDrawable *drawablep, LLSpatialGroup *curp, BOOL immediate = FALSE); - void shift(const LLVector3 &offset); + virtual void shift(const LLVector3 &offset); + + virtual F32 calcDistance(LLSpatialGroup* group, LLCamera& camera); + virtual F32 calcPixelArea(LLSpatialGroup* group, LLCamera& camera); + + virtual void rebuildGeom(LLSpatialGroup* group); S32 cull(LLCamera &camera, std::vector<LLDrawable *>* results = NULL, BOOL for_select = FALSE); // Cull on arbitrary frustum BOOL checkOcclusion(LLSpatialGroup* group, LLCamera* camera); + void markReimage(LLSpatialGroup* group); + void processGeometry(LLCamera* camera); + void processImagery(LLCamera* camera); void processOcclusion(LLCamera* camera); + void buildOcclusion(); void doOcclusion(LLCamera* camera); BOOL isVisible(const LLVector3& v); - + BOOL isVolatile() const { return mVolatile; } + + virtual LLSpatialBridge* asBridge() { return NULL; } S32 getObjects(const LLVector3& pos, F32 rad, LLDrawable::drawable_set_t &results ); S32 getLights(const LLVector3& pos, F32 rad, LLDrawable::drawable_set_t &results ); void renderDebug(); void restoreGL(); + void resetVertexBuffers(); protected: S32 getDrawables(const LLVector3& pos, F32 rad, LLDrawable::drawable_set_t &results, BOOL get_lights ); - LLSpatialGroup *mLastAddedGroupp; - - typedef std::set<LLSpatialGroup*> spatial_group_set_t; + typedef std::set<LLPointer<LLSpatialGroup> > spatial_group_set_t; spatial_group_set_t mSpatialGroups; //things that might be occluded - std::queue<LLSpatialGroup*> mOcclusionQueue; + typedef std::queue<LLPointer<LLSpatialGroup> > spatial_group_queue_t; + spatial_group_queue_t mOcclusionQueue; + + //things that need a terse update + spatial_group_queue_t mUpdateQueue; + + //things that need an image update + spatial_group_queue_t mImageQueue; //things awaiting query - std::queue<LLSpatialGroup*> mQueryQueue; + spatial_group_queue_t mQueryQueue; std::vector<LLGLuint> mOcclusionQueries; public: LLSpatialGroup::OctreeNode* mOctree; - //things that are occluded - std::vector<LLSpatialGroup*> mOccludedList; - - std::queue<LLSpatialGroup*> mReshadowQueue; + U32 mBufferUsage; + BOOL mRenderByGroup; + BOOL mImageEnabled; + U32 mLODSeed; + U32 mLODPeriod; + U32 mVertexDataMask; + F32 mSlopRatio; //percentage distance must change before drawables receive LOD update (default is 0.25); + BOOL mVolatile; //if TRUE, occlusion queries will be discarded when nodes change size + BOOL mDepthMask; //if TRUE, objects in this partition will be written to depth during alpha rendering + U32 mDrawableType; + U32 mPartitionType; + + //index buffer for occlusion verts + LLPointer<LLVertexBuffer> mOcclusionIndices; + //things that are occluded + std::vector<LLPointer<LLSpatialGroup> > mOccludedList; }; // class for creating bridges between spatial partitions class LLSpatialBridge : public LLDrawable, public LLSpatialPartition { public: - LLSpatialBridge(LLDrawable* root); + typedef std::vector<LLPointer<LLSpatialBridge> > bridge_vector_t; + + LLSpatialBridge(LLDrawable* root, U32 data_mask); virtual ~LLSpatialBridge(); - virtual BOOL isSpatialBridge() const { return TRUE; } + virtual BOOL isSpatialBridge() const { return TRUE; } virtual void updateSpatialExtents(); virtual void updateBinRadius(); @@ -193,11 +344,123 @@ public: virtual void shiftPos(const LLVector3& vec); virtual void cleanupReferences(); virtual LLSpatialPartition* asPartition() { return this; } - LLCamera transformCamera(LLCamera& camera); + virtual LLSpatialBridge* asBridge() { return this; } + + virtual LLCamera transformCamera(LLCamera& camera); LLDrawable* mDrawable; }; +//spatial partition for water (implemented in LLVOWater.cpp) +class LLWaterPartition : public LLSpatialPartition +{ +public: + LLWaterPartition(); + virtual void getGeometry(LLSpatialGroup* group) { } + virtual void addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32& index_count) { } +}; + +//spatial partition for terrain (impelmented in LLVOSurfacePatch.cpp) +class LLTerrainPartition : public LLSpatialPartition +{ +public: + LLTerrainPartition(); + virtual void getGeometry(LLSpatialGroup* group); + virtual LLVertexBuffer* createVertexBuffer(U32 type_mask, U32 usage); +}; + +//spatial partition for trees +class LLTreePartition : public LLSpatialPartition +{ +public: + LLTreePartition(); + virtual void getGeometry(LLSpatialGroup* group) { } + virtual void addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32& index_count) { } + +}; + +//spatial partition for particles (implemented in LLVOPartGroup.cpp) +class LLParticlePartition : public LLSpatialPartition +{ +public: + LLParticlePartition(); + virtual void getGeometry(LLSpatialGroup* group); + virtual void addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32& index_count); + virtual F32 calcPixelArea(LLSpatialGroup* group, LLCamera& camera); +protected: + U32 mRenderPass; +}; + +//spatial partition for grass (implemented in LLVOGrass.cpp) +class LLGrassPartition : public LLParticlePartition +{ +public: + LLGrassPartition(); +}; + +//spatial partition for clouds (implemented in LLVOClouds.cpp) +class LLCloudPartition : public LLParticlePartition +{ +public: + LLCloudPartition(); +}; + +//class for wrangling geometry out of volumes (implemented in LLVOVolume.cpp) +class LLVolumeGeometryManager: public LLGeometryManager +{ +public: + virtual ~LLVolumeGeometryManager() { } + virtual void rebuildGeom(LLSpatialGroup* group); + virtual void getGeometry(LLSpatialGroup* group); + void registerFace(LLSpatialGroup* group, LLFace* facep, U32 type); +}; + +//spatial partition that uses volume geometry manager (implemented in LLVOVolume.cpp) +class LLVolumePartition : public LLSpatialPartition, public LLVolumeGeometryManager +{ +public: + LLVolumePartition(); + virtual void rebuildGeom(LLSpatialGroup* group) { LLVolumeGeometryManager::rebuildGeom(group); } + virtual void getGeometry(LLSpatialGroup* group) { LLVolumeGeometryManager::getGeometry(group); } + virtual void addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32& index_count) { LLVolumeGeometryManager::addGeometryCount(group, vertex_count, index_count); } +}; + +//spatial bridge that uses volume geometry manager (implemented in LLVOVolume.cpp) +class LLVolumeBridge : public LLSpatialBridge, public LLVolumeGeometryManager +{ +public: + LLVolumeBridge(LLDrawable* drawable); + virtual void rebuildGeom(LLSpatialGroup* group) { LLVolumeGeometryManager::rebuildGeom(group); } + virtual void getGeometry(LLSpatialGroup* group) { LLVolumeGeometryManager::getGeometry(group); } + virtual void addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32& index_count) { LLVolumeGeometryManager::addGeometryCount(group, vertex_count, index_count); } +}; + +class LLHUDBridge : public LLVolumeBridge +{ +public: + LLHUDBridge(LLDrawable* drawablep); + virtual void shiftPos(const LLVector3& vec); + virtual F32 calcPixelArea(LLSpatialGroup* group, LLCamera& camera); +}; + +//spatial partition that holds nothing but spatial bridges +class LLBridgePartition : public LLSpatialPartition +{ +public: + LLBridgePartition(); + virtual void getGeometry(LLSpatialGroup* group) { } + virtual void addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32& index_count) { } +}; + +class LLHUDPartition : public LLBridgePartition +{ +public: + LLHUDPartition(); + virtual void shift(const LLVector3 &offset); +}; + +void validate_draw_info(LLDrawInfo& params); + extern const F32 SG_BOX_SIDE; extern const F32 SG_BOX_OFFSET; extern const F32 SG_BOX_RAD; diff --git a/indra/newview/llsprite.cpp b/indra/newview/llsprite.cpp index e614134080..d253271b52 100644 --- a/indra/newview/llsprite.cpp +++ b/indra/newview/llsprite.cpp @@ -75,14 +75,7 @@ void LLSprite::updateFace(LLFace &face) // First, figure out how many vertices/indices we need. U32 num_vertices, num_indices; U32 vertex_count = 0; - - - LLStrider<LLVector3> verticesp; - LLStrider<LLVector3> normalsp; - LLStrider<LLVector2> tex_coordsp; - U32 *indicesp; - S32 index_offset; - + // Get the total number of vertices and indices if (mFollow) { @@ -95,14 +88,7 @@ void LLSprite::updateFace(LLFace &face) num_indices = 12; } - // Setup face - face.setPrimType(LLTriangles); face.setSize(num_vertices, num_indices); - index_offset = face.getGeometry(verticesp,normalsp,tex_coordsp, indicesp); - if (-1 == index_offset) - { - return; - } if (mFollow) { @@ -187,7 +173,30 @@ void LLSprite::updateFace(LLFace &face) } face.setFaceColor(mColor); - + + LLStrider<LLVector3> verticesp; + LLStrider<LLVector3> normalsp; + LLStrider<LLVector2> tex_coordsp; + LLStrider<U32> indicesp; + S32 index_offset; + + // Setup face + if (face.mVertexBuffer.isNull()) + { + face.mVertexBuffer = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX | + LLVertexBuffer::MAP_TEXCOORD, + GL_STREAM_DRAW_ARB); + face.mVertexBuffer->allocateBuffer(4, 12, TRUE); + face.setGeomIndex(0); + face.setIndicesIndex(0); + } + + index_offset = face.getGeometry(verticesp,normalsp,tex_coordsp, indicesp); + if (-1 == index_offset) + { + return; + } + *tex_coordsp = LLVector2(0.f, 0.f); *verticesp = mC; tex_coordsp++; @@ -232,6 +241,7 @@ void LLSprite::updateFace(LLFace &face) *indicesp++ = 3 + index_offset; } + //face.mVertexBuffer->setBuffer(0); face.mCenterAgent = mPosition; } diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 04b5fe7340..421e836f93 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -99,6 +99,8 @@ #include "llsky.h" #include "llstatview.h" #include "llsurface.h" +#include "lltexturecache.h" +#include "lltexturefetch.h" #include "lltoolmgr.h" #include "llui.h" #include "llurlwhitelist.h" @@ -167,7 +169,6 @@ const char* SCREEN_LAST_FILENAME = "screen_last.bmp"; // // Imported globals // -extern LLPointer<LLImageGL> gStartImageGL; extern S32 gStartImageWidth; extern S32 gStartImageHeight; extern std::string gSerialNumber; @@ -176,6 +177,8 @@ extern std::string gSerialNumber; // local globals // +LLPointer<LLImageGL> gStartImageGL; + static LLHost gAgentSimHost; static BOOL gSkipOptionalUpdate = FALSE; @@ -234,7 +237,13 @@ public: } }; - +void update_texture_fetch() +{ + gTextureCache->update(1); // unpauses the texture cache thread + gImageDecodeThread->update(1); // unpauses the image thread + gTextureFetch->update(1); // unpauses the texture fetch thread + gImageList.updateImages(0.10f); +} // Returns FALSE to skip other idle processing. Should only return // TRUE when all initialization done. @@ -285,8 +294,6 @@ BOOL idle_startup() static BOOL samename = FALSE; - static BOOL did_precache = FALSE; - BOOL do_normal_idle = FALSE; // HACK: These are things from the main loop that usually aren't done @@ -1590,6 +1597,8 @@ BOOL idle_startup() args["[ERROR_MESSAGE]"] = emsg.str(); gViewerWindow->alertXml("ErrorMessage", args, login_alert_done); gStartupState = STATE_LOGIN_SHOW; + gAutoLogin = FALSE; + show_connect_box = TRUE; } } else @@ -1605,6 +1614,8 @@ BOOL idle_startup() args["[ERROR_MESSAGE]"] = emsg.str(); gViewerWindow->alertXml("ErrorMessage", args, login_alert_done); gStartupState = STATE_LOGIN_SHOW; + gAutoLogin = FALSE; + show_connect_box = TRUE; } return do_normal_idle; } @@ -1637,6 +1648,9 @@ BOOL idle_startup() // // Initialize classes w/graphics stuff. // + gImageList.doPrefetchImages(); + update_texture_fetch(); + LLSurface::initClasses(); LLFace::initClass(); @@ -1799,7 +1813,7 @@ BOOL idle_startup() llinfos << "Decoding images..." << llendl; // For all images pre-loaded into viewer cache, decode them. // Need to do this AFTER we init the sky - gImageList.decodeAllImages(); + gImageList.decodeAllImages(2.f); gStartupState++; // JC - Do this as late as possible to increase likelihood Purify @@ -2368,18 +2382,6 @@ BOOL idle_startup() if (STATE_PRECACHE == gStartupState) { do_normal_idle = TRUE; - if (!did_precache) - { - did_precache = TRUE; - // Don't preload map information! The amount of data for all the - // map items (icons for classifieds, avatar locations, etc.) is - // huge, and not throttled. This overflows the downstream - // pipe during startup, when lots of information is being sent. - // The problem manifests itself as invisible avatars on login. JC - //gWorldMap->setCurrentLayer(0); // pre-load layer 0 of the world map - - gImageList.doPreloadImages(); // pre-load some images from static VFS - } F32 timeout_frac = timeout.getElapsedTimeF32()/PRECACHING_DELAY; // wait precache-delay and for agent's avatar or a lot longer. @@ -2390,6 +2392,7 @@ BOOL idle_startup() } else { + update_texture_fetch(); set_startup_status(0.50f + 0.50f * timeout_frac, "Precaching...", gAgent.mMOTD.c_str()); } @@ -2418,6 +2421,7 @@ BOOL idle_startup() } else { + update_texture_fetch(); set_startup_status(0.f + 0.25f * wearables_time / MAX_WEARABLES_TIME, "Downloading clothing...", gAgent.mMOTD.c_str()); @@ -2520,34 +2524,6 @@ BOOL idle_startup() // local function definition // -void unsupported_graphics_callback(S32 option, void* userdata) -{ - if (0 == option) - { - llinfos << "User cancelled after driver check" << llendl; - std::string help_path; - help_path = gDirUtilp->getExpandedFilename(LL_PATH_HELP, - "unsupported_card.html"); - app_force_quit( help_path.c_str() ); - } - - LLPanelLogin::giveFocus(); -} - -void check_driver_callback(S32 option, void* userdata) -{ - if (0 == option) - { - llinfos << "User cancelled after driver check" << llendl; - std::string help_path; - help_path = gDirUtilp->getExpandedFilename(LL_PATH_HELP, - "graphics_driver_update.html"); - app_force_quit( help_path.c_str() ); - } - - LLPanelLogin::giveFocus(); -} - void login_show() { LLPanelLogin::show( gViewerWindow->getVirtualWindowRect(), @@ -2555,7 +2531,7 @@ void login_show() login_callback, NULL ); // Make sure all the UI textures are present and decoded. - gImageList.decodeAllImages(); + gImageList.decodeAllImages(2.f); if( USERSERVER_OTHER == gUserServerChoice ) { @@ -3027,8 +3003,8 @@ void use_circuit_callback(void**, S32 result) void register_viewer_callbacks(LLMessageSystem* msg) { msg->setHandlerFuncFast(_PREHASH_LayerData, process_layer_data ); - msg->setHandlerFuncFast(_PREHASH_ImageData, LLViewerImage::receiveImage ); - msg->setHandlerFuncFast(_PREHASH_ImagePacket, LLViewerImage::receiveImagePacket ); + msg->setHandlerFuncFast(_PREHASH_ImageData, LLViewerImageList::receiveImageHeader ); + msg->setHandlerFuncFast(_PREHASH_ImagePacket, LLViewerImageList::receiveImagePacket ); msg->setHandlerFuncFast(_PREHASH_ObjectUpdate, process_object_update ); msg->setHandlerFunc("ObjectUpdateCompressed", process_compressed_object_update ); msg->setHandlerFunc("ObjectUpdateCached", process_cached_object_update ); @@ -3869,7 +3845,7 @@ void dialog_choose_gender_first_start() // location_id = 1 => home position void init_start_screen(S32 location_id) { - if (gStartImageGL) + if (gStartImageGL.notNull()) { gStartImageGL = NULL; llinfos << "re-initializing start screen" << llendl; diff --git a/indra/newview/llstartup.h b/indra/newview/llstartup.h index c7b3bc13d5..e5952f4f5b 100644 --- a/indra/newview/llstartup.h +++ b/indra/newview/llstartup.h @@ -9,10 +9,13 @@ #ifndef LL_LLSTARTUP_H #define LL_LLSTARTUP_H +#include "llimagegl.h" + // functions BOOL idle_startup(); void cleanup_app(); LLString load_password_from_disk(); +void release_start_screen(); // constants, variables, & enumerations extern const char* SCREEN_HOME_FILENAME; @@ -59,6 +62,7 @@ enum EStartupState{ // exorted symbol extern S32 gStartupState; extern bool gQuickTimeInitialized; +extern LLPointer<LLImageGL> gStartImageGL; class LLStartUp { diff --git a/indra/newview/llsurface.cpp b/indra/newview/llsurface.cpp index fc0c46bbe1..4087f7f96c 100644 --- a/indra/newview/llsurface.cpp +++ b/indra/newview/llsurface.cpp @@ -31,7 +31,7 @@ #include "noise.h" #include "llviewercamera.h" #include "llglheaders.h" -#include "lldrawpool.h" +#include "lldrawpoolterrain.h" #include "lldrawable.h" extern LLPipeline gPipeline; @@ -101,7 +101,7 @@ LLSurface::~LLSurface() mNumberOfPatches = 0; destroyPatchData(); - LLDrawPool *poolp = gPipeline.findPool(LLDrawPool::POOL_TERRAIN, mSTexturep); + LLDrawPoolTerrain *poolp = (LLDrawPoolTerrain*) gPipeline.findPool(LLDrawPool::POOL_TERRAIN, mSTexturep); if (!poolp) { llwarns << "No pool for terrain on destruction!" << llendl; @@ -312,7 +312,6 @@ void LLSurface::setOriginGlobal(const LLVector3d &origin_global) LLVector3d water_origin_global(x, y, z); mWaterObjp->setPositionGlobal(water_origin_global); - gPipeline.markMoved(mWaterObjp->mDrawable); } } @@ -602,45 +601,45 @@ void LLSurface::updatePatchVisibilities(LLAgent &agent) } } - - -BOOL LLSurface::idleUpdate() +BOOL LLSurface::idleUpdate(F32 max_update_time) { if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_TERRAIN)) { - return TRUE; + return FALSE; } // Perform idle time update of non-critical stuff. // In this case, texture and normal updates. LLTimer update_timer; - LLSurfacePatch *patchp = NULL; + BOOL did_update = FALSE; // If the Z height data has changed, we need to rebuild our // property line vertex arrays. - if (mDirtyPatchList.count() > 0) + if (mDirtyPatchList.size() > 0) { getRegion()->dirtyHeights(); } - S32 i = 0; - while (i < mDirtyPatchList.count()) + // Always call updateNormals() / updateVerticalStats() + // every frame to avoid artifacts + for(std::set<LLSurfacePatch *>::iterator iter = mDirtyPatchList.begin(); + iter != mDirtyPatchList.end(); ) { - patchp = mDirtyPatchList[i]; + std::set<LLSurfacePatch *>::iterator curiter = iter++; + LLSurfacePatch *patchp = *curiter; patchp->updateNormals(); patchp->updateVerticalStats(); - - if ((update_timer.getElapsedTimeF32() < 0.05f) && patchp->updateTexture()) - { - patchp->clearDirty(); - mDirtyPatchList.remove(i); - } - else + if (max_update_time == 0.f || update_timer.getElapsedTimeF32() < max_update_time) { - i++; + if (patchp->updateTexture()) + { + did_update = TRUE; + patchp->clearDirty(); + mDirtyPatchList.erase(curiter); + } } } - return TRUE; + return did_update; } // TODO -- move this to LLViewerRegion class @@ -1210,10 +1209,7 @@ void LLSurface::dirtyAllPatches() void LLSurface::dirtySurfacePatch(LLSurfacePatch *patchp) { // Put surface patch on dirty surface patch list - if (-1 == mDirtyPatchList.find(patchp)) - { - mDirtyPatchList.put(patchp); - } + mDirtyPatchList.insert(patchp); } diff --git a/indra/newview/llsurface.h b/indra/newview/llsurface.h index 7698c272ab..ca22535542 100644 --- a/indra/newview/llsurface.h +++ b/indra/newview/llsurface.h @@ -22,7 +22,6 @@ #include "llvowater.h" #include "llpatchvertexarray.h" -#include "lldarray.h" #include "llviewerimage.h" class LLTimer; @@ -96,7 +95,7 @@ public: LLSurfacePatch *resolvePatchGlobal(const LLVector3d &position_global) const; // Update methods (called during idle, normally) - BOOL idleUpdate(); + BOOL idleUpdate(F32 max_update_time); void renderSurfaceBounds(); @@ -181,7 +180,7 @@ protected: // Array of grid normals, mGridsPerEdge * mGridsPerEdge LLVector3 *mNorm; - LLDynamicArray<LLSurfacePatch *> mDirtyPatchList; + std::set<LLSurfacePatch *> mDirtyPatchList; // The textures should never be directly initialized - use the setter methods! diff --git a/indra/newview/llsurfacepatch.cpp b/indra/newview/llsurfacepatch.cpp index ac0add8ae3..4be7cf41e7 100644 --- a/indra/newview/llsurfacepatch.cpp +++ b/indra/newview/llsurfacepatch.cpp @@ -794,7 +794,7 @@ void LLSurfacePatch::connectNeighbor(LLSurfacePatch *neighbor_patchp, const U32 void LLSurfacePatch::updateVisibility() { - if (mVObjp == (LLVOSurfacePatch*)NULL) + if (mVObjp.isNull()) { return; } diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp new file mode 100644 index 0000000000..13efadf213 --- /dev/null +++ b/indra/newview/lltexturecache.cpp @@ -0,0 +1,1365 @@ +/**
+ * @file texturecache.cpp
+ * @brief Object which handles local texture caching
+ *
+ * Copyright (c) 2000-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "lltexturecache.h"
+
+#include "llapr.h"
+#include "lldir.h"
+#include "llimage.h"
+#include "lllfsthread.h"
+#include "llviewercontrol.h"
+
+#define USE_LFS_READ 0
+#define USE_LFS_WRITE 0
+
+// Note: first 4 bytes store file size, rest is j2c data
+const S32 TEXTURE_CACHE_ENTRY_SIZE = FIRST_PACKET_SIZE; //1024;
+
+class LLTextureCacheWorker : public LLWorkerClass
+{
+ friend class LLTextureCache;
+
+private:
+ enum e_state
+ {
+ INIT = 0,
+ LOCAL = 1,
+ CACHE = 2,
+ HEADER = 3,
+ BODY = 4
+ };
+
+ class ReadResponder : public LLLFSThread::Responder
+ {
+ public:
+ ReadResponder(LLTextureCache* cache, handle_t handle) : mCache(cache), mHandle(handle) {}
+ ~ReadResponder() {}
+ void completed(S32 bytes)
+ {
+ mCache->lockWorkers();
+ LLTextureCacheWorker* reader = mCache->getReader(mHandle);
+ if (reader) reader->ioComplete(bytes);
+ mCache->unlockWorkers();
+ }
+ LLTextureCache* mCache;
+ LLTextureCacheWorker::handle_t mHandle;
+ };
+
+ class WriteResponder : public LLLFSThread::Responder
+ {
+ public:
+ WriteResponder(LLTextureCache* cache, handle_t handle) : mCache(cache), mHandle(handle) {}
+ ~WriteResponder() {}
+ void completed(S32 bytes)
+ {
+ mCache->lockWorkers();
+ LLTextureCacheWorker* writer = mCache->getWriter(mHandle);
+ if (writer) writer->ioComplete(bytes);
+ mCache->unlockWorkers();
+ }
+ LLTextureCache* mCache;
+ LLTextureCacheWorker::handle_t mHandle;
+ };
+
+public:
+ LLTextureCacheWorker(LLTextureCache* cache, U32 priority, const LLUUID& id,
+ U8* data, S32 datasize, S32 offset,
+ S32 imagesize, // for writes
+ LLTextureCache::Responder* responder)
+ : LLWorkerClass(cache, "LLTextureCacheWorker"),
+ mCache(cache),
+ mPriority(priority),
+ mID(id),
+ mState(INIT),
+ mReadData(NULL),
+ mWriteData(data),
+ mDataSize(datasize),
+ mOffset(offset),
+ mImageSize(imagesize),
+ mImageFormat(IMG_CODEC_J2C),
+ mImageLocal(FALSE),
+ mResponder(responder),
+ mFileHandle(LLLFSThread::nullHandle()),
+ mBytesToRead(0),
+ mBytesRead(0)
+ {
+ mPriority &= LLWorkerThread::PRIORITY_LOWBITS;
+ }
+ ~LLTextureCacheWorker()
+ {
+ llassert_always(!haveWork());
+ delete[] mReadData;
+ }
+
+ bool doRead();
+ bool doWrite();
+ virtual bool doWork(S32 param); // Called from LLWorkerThread::processRequest()
+
+ handle_t read() { addWork(0, LLWorkerThread::PRIORITY_HIGH | mPriority); return mRequestHandle; }
+ handle_t write() { addWork(1, LLWorkerThread::PRIORITY_HIGH | mPriority); return mRequestHandle; }
+ bool complete() { return checkWork(); }
+ void ioComplete(S32 bytes)
+ {
+ mBytesRead = bytes;
+ setPriority(LLWorkerThread::PRIORITY_HIGH | mPriority);
+ }
+
+private:
+ virtual void startWork(S32 param); // called from addWork() (MAIN THREAD)
+ virtual void finishWork(S32 param, bool completed); // called from finishRequest() (WORK THREAD)
+ virtual void endWork(S32 param, bool aborted); // called from doWork() (MAIN THREAD)
+
+private:
+ LLTextureCache* mCache;
+ U32 mPriority;
+ LLUUID mID;
+ e_state mState;
+
+ U8* mReadData;
+ U8* mWriteData;
+ S32 mDataSize;
+ S32 mOffset;
+ S32 mImageSize;
+ S32 mImageFormat;
+ BOOL mImageLocal;
+ LLPointer<LLTextureCache::Responder> mResponder;
+ LLLFSThread::handle_t mFileHandle;
+ S32 mBytesToRead;
+ LLAtomicS32 mBytesRead;
+};
+
+//virtual
+void LLTextureCacheWorker::startWork(S32 param)
+{
+}
+
+bool LLTextureCacheWorker::doRead()
+{
+ S32 local_size = 0;
+ std::string local_filename;
+
+ if (mState == INIT)
+ {
+ std::string filename = mCache->getLocalFileName(mID);
+ local_filename = filename + ".j2c";
+ local_size = ll_apr_file_size(local_filename, mCache->getFileAPRPool());
+ if (local_size == 0)
+ {
+ local_filename = filename + ".tga";
+ local_size = ll_apr_file_size(local_filename, mCache->getFileAPRPool());
+ if (local_size > 0)
+ {
+ mImageFormat = IMG_CODEC_TGA;
+ mDataSize = local_size; // Only a complete .tga file is valid
+ }
+ }
+ if (local_size > 0)
+ {
+ mState = LOCAL;
+ }
+ else
+ {
+ mState = CACHE;
+ }
+ }
+
+ if (mState == LOCAL)
+ {
+#if USE_LFS_READ
+ if (mFileHandle == LLLFSThread::nullHandle())
+ {
+ mImageLocal = TRUE;
+ mImageSize = local_size;
+ if (!mDataSize || mDataSize + mOffset > local_size)
+ {
+ mDataSize = local_size - mOffset;
+ }
+ if (mDataSize <= 0)
+ {
+ // no more data to read
+ mDataSize = 0;
+ return true;
+ }
+ mReadData = new U8[mDataSize];
+ mBytesRead = -1;
+ mBytesToRead = mDataSize;
+ setPriority(LLWorkerThread::PRIORITY_LOW | mPriority);
+ mFileHandle = LLLFSThread::sLocal->read(local_filename, mReadData, mOffset, mDataSize,
+ new ReadResponder(mCache, mRequestHandle));
+ return false;
+ }
+ else
+ {
+ if (mBytesRead >= 0)
+ {
+ if (mBytesRead != mBytesToRead)
+ {
+ llwarns << "Error reading file from local cache: " << local_filename
+ << " Bytes: " << mDataSize << " Offset: " << mOffset
+ << " / " << mDataSize << llendl;
+ mDataSize = 0; // failed
+ delete[] mReadData;
+ mReadData = NULL;
+ }
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+#else
+ if (!mDataSize || mDataSize > local_size)
+ {
+ mDataSize = local_size;
+ }
+ mReadData = new U8[mDataSize];
+ S32 bytes_read = ll_apr_file_read_ex(local_filename, mCache->getFileAPRPool(),
+ mReadData, mOffset, mDataSize);
+ if (bytes_read != mDataSize)
+ {
+ llwarns << "Error reading file from local cache: " << local_filename
+ << " Bytes: " << mDataSize << " Offset: " << mOffset
+ << " / " << mDataSize << llendl;
+ mDataSize = 0;
+ delete[] mReadData;
+ mReadData = NULL;
+ }
+ else
+ {
+ mImageSize = local_size;
+ mImageLocal = TRUE;
+ }
+ return true;
+#endif
+ }
+
+ S32 idx = -1;
+
+ if (mState == CACHE)
+ {
+ llassert_always(mImageSize == 0);
+ idx = mCache->getHeaderCacheEntry(mID, false, &mImageSize);
+ if (idx >= 0 && mImageSize > mOffset)
+ {
+ llassert_always(mImageSize > 0);
+ if (!mDataSize || mDataSize > mImageSize)
+ {
+ mDataSize = mImageSize;
+ }
+ mState = mOffset < TEXTURE_CACHE_ENTRY_SIZE ? HEADER : BODY;
+ }
+ else
+ {
+ mDataSize = 0; // no data
+ return true;
+ }
+ }
+
+ if (mState == HEADER)
+ {
+#if USE_LFS_READ
+ if (mFileHandle == LLLFSThread::nullHandle())
+ {
+ llassert_always(idx >= 0);
+ llassert_always(mOffset < TEXTURE_CACHE_ENTRY_SIZE);
+ S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE + mOffset;
+ S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
+ llassert_always(mReadData == NULL);
+ mReadData = new U8[size];
+ mBytesRead = -1;
+ mBytesToRead = size;
+ setPriority(LLWorkerThread::PRIORITY_LOW | mPriority);
+ mFileHandle = LLLFSThread::sLocal->read(mCache->mHeaderDataFileName,
+ mReadData, offset, mBytesToRead,
+ new ReadResponder(mCache, mRequestHandle));
+ return false;
+ }
+ else
+ {
+ if (mBytesRead >= 0)
+ {
+ if (mBytesRead != mBytesToRead)
+ {
+ llwarns << "LLTextureCacheWorker: " << mID
+ << " incorrect number of bytes read from header: " << mBytesRead
+ << " != " << mBytesToRead << llendl;
+ mDataSize = -1; // failed
+ return true;
+ }
+ if (mDataSize <= TEXTURE_CACHE_ENTRY_SIZE)
+ {
+ return true; // done
+ }
+ else
+ {
+ mFileHandle = LLLFSThread::nullHandle();
+ mState = BODY;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+#else
+ llassert_always(idx >= 0);
+ llassert_always(mOffset < TEXTURE_CACHE_ENTRY_SIZE);
+ S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE + mOffset;
+ S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
+ mReadData = new U8[size];
+ S32 bytes_read = ll_apr_file_read_ex(mCache->mHeaderDataFileName, mCache->getFileAPRPool(),
+ mReadData, offset, size);
+ if (bytes_read != size)
+ {
+ llwarns << "LLTextureCacheWorker: " << mID
+ << " incorrect number of bytes read from header: " << bytes_read
+ << " / " << size << llendl;
+ mDataSize = -1; // failed
+ return true;
+ }
+ if (mDataSize <= TEXTURE_CACHE_ENTRY_SIZE)
+ {
+ return true; // done
+ }
+ else
+ {
+ mState = BODY;
+ }
+#endif
+ }
+
+ if (mState == BODY)
+ {
+#if USE_LFS_READ
+ if (mFileHandle == LLLFSThread::nullHandle())
+ {
+ std::string filename = mCache->getTextureFileName(mID);
+ S32 filesize = ll_apr_file_size(filename, mCache->getFileAPRPool());
+ if (filesize > mOffset)
+ {
+ S32 datasize = TEXTURE_CACHE_ENTRY_SIZE + filesize;
+ mDataSize = llmin(datasize, mDataSize);
+ S32 data_offset = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
+ data_offset = llmax(data_offset, 0);
+ S32 file_size = mDataSize - data_offset;
+ S32 file_offset = mOffset - TEXTURE_CACHE_ENTRY_SIZE;
+ file_offset = llmax(file_offset, 0);
+
+ llassert_always(mDataSize > 0);
+ U8* data = new U8[mDataSize];
+ if (data_offset > 0)
+ {
+ llassert_always(mReadData);
+ llassert_always(data_offset <= mDataSize);
+ memcpy(data, mReadData, data_offset);
+ delete[] mReadData;
+ mReadData = NULL;
+ }
+ llassert_always(mReadData == NULL);
+ mReadData = data;
+
+ mBytesRead = -1;
+ mBytesToRead = file_size;
+ setPriority(LLWorkerThread::PRIORITY_LOW | mPriority);
+ llassert_always(data_offset + mBytesToRead <= mDataSize);
+ mFileHandle = LLLFSThread::sLocal->read(filename,
+ mReadData + data_offset, file_offset, mBytesToRead,
+ new ReadResponder(mCache, mRequestHandle));
+ return false;
+ }
+ else
+ {
+ mDataSize = TEXTURE_CACHE_ENTRY_SIZE;
+ return true; // done
+ }
+ }
+ else
+ {
+ if (mBytesRead >= 0)
+ {
+ if (mBytesRead != mBytesToRead)
+ {
+ llwarns << "LLTextureCacheWorker: " << mID
+ << " incorrect number of bytes read from body: " << mBytesRead
+ << " != " << mBytesToRead << llendl;
+ mDataSize = -1; // failed
+ }
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+#else
+ std::string filename = mCache->getTextureFileName(mID);
+ S32 filesize = ll_apr_file_size(filename, mCache->getFileAPRPool());
+ S32 bytes_read = 0;
+ if (filesize > mOffset)
+ {
+ S32 datasize = TEXTURE_CACHE_ENTRY_SIZE + filesize;
+ mDataSize = llmin(datasize, mDataSize);
+ S32 data_offset = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
+ data_offset = llmax(data_offset, 0);
+ S32 file_size = mDataSize - data_offset;
+ S32 file_offset = mOffset - TEXTURE_CACHE_ENTRY_SIZE;
+ file_offset = llmax(file_offset, 0);
+
+ U8* data = new U8[mDataSize];
+ if (data_offset > 0)
+ {
+ llassert_always(mReadData);
+ memcpy(data, mReadData, data_offset);
+ delete[] mReadData;
+ }
+ mReadData = data;
+ bytes_read = ll_apr_file_read_ex(filename, mCache->getFileAPRPool(),
+ mReadData + data_offset,
+ file_offset, file_size);
+ if (bytes_read != file_size)
+ {
+ llwarns << "LLTextureCacheWorker: " << mID
+ << " incorrect number of bytes read from body: " << bytes_read
+ << " / " << file_size << llendl;
+ mDataSize = -1; // failed
+ return true;
+ }
+ }
+ else
+ {
+ mDataSize = TEXTURE_CACHE_ENTRY_SIZE;
+ }
+
+ return true;
+#endif
+ }
+
+ return false;
+}
+
+bool LLTextureCacheWorker::doWrite()
+{
+ S32 idx = -1;
+
+ if (mState == INIT)
+ {
+ llassert_always(mOffset == 0); // Currently don't support offsets
+ mState = CACHE;
+ }
+
+ // No LOCAL state for write()
+
+ if (mState == CACHE)
+ {
+ S32 cur_imagesize = 0;
+ S32 offset = mOffset;
+ idx = mCache->getHeaderCacheEntry(mID, false, &cur_imagesize);
+ if (idx >= 0 && cur_imagesize > 0)
+ {
+ offset = TEXTURE_CACHE_ENTRY_SIZE; // don't re-write header
+ }
+ idx = mCache->getHeaderCacheEntry(mID, true, &mImageSize); // touch entry
+ if (idx >= 0)
+ {
+ llassert_always(cur_imagesize <= 0 || mImageSize == cur_imagesize);
+ mState = offset < TEXTURE_CACHE_ENTRY_SIZE ? HEADER : BODY;
+ }
+ else
+ {
+ mDataSize = -1; // failed
+ return true;
+ }
+ }
+
+ if (mState == HEADER)
+ {
+#if USE_LFS_WRITE
+ if (mFileHandle == LLLFSThread::nullHandle())
+ {
+ llassert_always(idx >= 0);
+ llassert_always(mOffset < TEXTURE_CACHE_ENTRY_SIZE);
+ S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE + mOffset;
+ S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
+ mBytesRead = -1;
+ mBytesToRead = size;
+ setPriority(LLWorkerThread::PRIORITY_LOW | mPriority);
+ mFileHandle = LLLFSThread::sLocal->write(mCache->mHeaderDataFileName,
+ mWriteData, offset, mBytesToRead,
+ new WriteResponder(mCache, mRequestHandle));
+ return false;
+ }
+ else
+ {
+ if (mBytesRead >= 0)
+ {
+ if (mBytesRead != mBytesToRead)
+ {
+ llwarns << "LLTextureCacheWorker: " << mID
+ << " incorrect number of bytes written to header: " << mBytesRead
+ << " != " << mBytesToRead << llendl;
+ mDataSize = -1; // failed
+ return true;
+ }
+ if (mDataSize <= mBytesToRead)
+ {
+ return true; // done
+ }
+ else
+ {
+ mFileHandle = LLLFSThread::nullHandle();
+ mState = BODY;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+#else
+ llassert_always(idx >= 0);
+ llassert_always(mOffset < TEXTURE_CACHE_ENTRY_SIZE);
+ S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE + mOffset;
+ S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
+ S32 bytes_written = ll_apr_file_write_ex(mCache->mHeaderDataFileName, mCache->getFileAPRPool(),
+ mWriteData, offset, size);
+
+ if (bytes_written <= 0)
+ {
+ llwarns << "LLTextureCacheWorker: missing entry: " << mID << llendl;
+ mDataSize = -1; // failed
+ return true;
+ }
+
+ if (mDataSize <= size)
+ {
+ return true; // done
+ }
+ else
+ {
+ mState = BODY;
+ }
+#endif
+ }
+
+ if (mState == BODY)
+ {
+#if USE_LFS_WRITE
+ if (mFileHandle == LLLFSThread::nullHandle())
+ {
+ S32 data_offset = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
+ data_offset = llmax(data_offset, 0);
+ S32 file_size = mDataSize - data_offset;
+ S32 file_offset = mOffset - TEXTURE_CACHE_ENTRY_SIZE;
+ file_offset = llmax(file_offset, 0);
+ if (file_size > 0 && mCache->appendToTextureEntryList(mID, file_size))
+ {
+ std::string filename = mCache->getTextureFileName(mID);
+ mBytesRead = -1;
+ mBytesToRead = file_size;
+ setPriority(LLWorkerThread::PRIORITY_LOW | mPriority);
+ mFileHandle = LLLFSThread::sLocal->write(filename,
+ mWriteData + data_offset, file_offset, mBytesToRead,
+ new WriteResponder(mCache, mRequestHandle));
+ return false;
+ }
+ else
+ {
+ mDataSize = 0; // no data written
+ return true; // done
+ }
+ }
+ else
+ {
+ if (mBytesRead >= 0)
+ {
+ if (mBytesRead != mBytesToRead)
+ {
+ llwarns << "LLTextureCacheWorker: " << mID
+ << " incorrect number of bytes written to body: " << mBytesRead
+ << " != " << mBytesToRead << llendl;
+ mDataSize = -1; // failed
+ }
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+#else
+ S32 data_offset = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
+ data_offset = llmax(data_offset, 0);
+ S32 file_size = mDataSize - data_offset;
+ S32 file_offset = mOffset - TEXTURE_CACHE_ENTRY_SIZE;
+ file_offset = llmax(file_offset, 0);
+ S32 bytes_written = 0;
+ if (file_size > 0 && mCache->appendToTextureEntryList(mID, file_size))
+ {
+ std::string filename = mCache->getTextureFileName(mID);
+ bytes_written = ll_apr_file_write_ex(filename, mCache->getFileAPRPool(),
+ mWriteData + data_offset,
+ file_offset, file_size);
+ if (bytes_written <= 0)
+ {
+ mDataSize = -1; // failed
+ }
+ }
+ else
+ {
+ mDataSize = 0; // no data written
+ }
+
+ return true;
+#endif
+ }
+
+ return false;
+}
+
+//virtual
+bool LLTextureCacheWorker::doWork(S32 param)
+{
+ bool res = false;
+ if (param == 0) // read
+ {
+ res = doRead();
+ }
+ else if (param == 1) // write
+ {
+ res = doWrite();
+ }
+ else
+ {
+ llassert_always(0);
+ }
+ return res;
+}
+
+//virtual (WORKER THREAD)
+void LLTextureCacheWorker::finishWork(S32 param, bool completed)
+{
+ if (mResponder.notNull())
+ {
+ bool success = (completed && mDataSize > 0);
+ if (param == 0)
+ {
+ // read
+ if (success)
+ {
+ mResponder->setData(mReadData, mDataSize, mImageSize, mImageFormat, mImageLocal);
+ mReadData = NULL; // responder owns data
+ mDataSize = 0;
+ }
+ else
+ {
+ delete[] mReadData;
+ mReadData = NULL;
+
+ }
+ }
+ else
+ {
+ // write
+ mWriteData = NULL; // we never owned data
+ mDataSize = 0;
+ }
+ mResponder->completed(success);
+ }
+}
+
+//virtual (MAIN THREAD)
+void LLTextureCacheWorker::endWork(S32 param, bool aborted)
+{
+ if (aborted)
+ {
+ // Let the destructor handle any cleanup
+ return;
+ }
+ switch(param)
+ {
+ default:
+ case 0: // read
+ case 1: // write
+ {
+ if (mDataSize < 0)
+ {
+ // failed
+ mCache->removeFromCache(mID);
+ }
+ break;
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+LLTextureCache::LLTextureCache(bool threaded)
+ : LLWorkerThread("TextureCache", threaded),
+ mWorkersMutex(getAPRPool()),
+ mHeaderMutex(getAPRPool()),
+ mFileAPRPool(NULL),
+ mReadOnly(FALSE),
+ mTexturesSizeTotal(0),
+ mDoPurge(FALSE)
+{
+ apr_pool_create(&mFileAPRPool, NULL);
+}
+
+LLTextureCache::~LLTextureCache()
+{
+ apr_pool_destroy(mFileAPRPool);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+//virtual
+S32 LLTextureCache::update(U32 max_time_ms)
+{
+ S32 res;
+ res = LLWorkerThread::update(max_time_ms);
+
+ lockWorkers();
+ for (std::vector<handle_t>::iterator iter1 = mPrioritizeWriteList.begin();
+ iter1 != mPrioritizeWriteList.end(); ++iter1)
+ {
+ handle_t handle = *iter1;
+ handle_map_t::iterator iter2 = mWriters.find(handle);
+ if(iter2 != mWriters.end())
+ {
+ LLTextureCacheWorker* worker = iter2->second;
+ worker->setPriority(LLWorkerThread::PRIORITY_HIGH | worker->mPriority);
+ }
+ }
+ mPrioritizeWriteList.clear();
+ unlockWorkers();
+ return res;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+std::string LLTextureCache::getLocalFileName(const LLUUID& id)
+{
+ // Does not include extension
+ std::string idstr = id.asString();
+ std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_SKINS, "textures", idstr);
+ return filename;
+}
+
+std::string LLTextureCache::getTextureFileName(const LLUUID& id)
+{
+ std::string idstr = id.asString();
+ std::string delem = gDirUtilp->getDirDelimiter();
+ std::string filename = mTexturesDirName + delem + idstr[0] + delem + idstr;
+ return filename;
+}
+
+bool LLTextureCache::appendToTextureEntryList(const LLUUID& id, S32 bodysize)
+{
+ bool res = false;
+ bool purge = false;
+ // Append UUID to end of texture entries
+ {
+ LLMutexLock lock(&mHeaderMutex);
+ size_map_t::iterator iter = mTexturesSizeMap.find(id);
+ if (iter == mTexturesSizeMap.end() || iter->second < bodysize)
+ {
+ llassert_always(bodysize > 0);
+ Entry* entry = new Entry(id, bodysize, time(NULL));
+ ll_apr_file_write_ex(mTexturesDirEntriesFileName, getFileAPRPool(),
+ (U8*)entry, -1, 1*sizeof(Entry));
+ delete entry;
+ if (iter != mTexturesSizeMap.end())
+ {
+ mTexturesSizeTotal -= iter->second;
+ }
+ mTexturesSizeTotal += bodysize;
+ mTexturesSizeMap[id] = bodysize;
+ if (mTexturesSizeTotal > sCacheMaxTexturesSize)
+ {
+ purge = true;
+ }
+ res = true;
+ }
+ }
+ if (purge)
+ {
+ mDoPurge = TRUE;
+ }
+ return res;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+//static
+const S32 MAX_REASONABLE_FILE_SIZE = 512*1024*1024; // 512 MB
+F32 LLTextureCache::sHeaderCacheVersion = 1.0f;
+U32 LLTextureCache::sCacheMaxEntries = MAX_REASONABLE_FILE_SIZE / TEXTURE_CACHE_ENTRY_SIZE;
+S64 LLTextureCache::sCacheMaxTexturesSize = 0; // no limit
+const char* entries_filename = "texture.entries";
+const char* cache_filename = "texture.cache";
+const char* textures_dirname = "textures";
+
+void LLTextureCache::setDirNames(ELLPath location)
+{
+ std::string delem = gDirUtilp->getDirDelimiter();
+ mHeaderEntriesFileName = gDirUtilp->getExpandedFilename(location, entries_filename);
+ mHeaderDataFileName = gDirUtilp->getExpandedFilename(location, cache_filename);
+ mTexturesDirName = gDirUtilp->getExpandedFilename(location, textures_dirname);
+ mTexturesDirEntriesFileName = mTexturesDirName + delem + entries_filename;
+}
+
+void LLTextureCache::purgeCache(ELLPath location)
+{
+ if (!mReadOnly)
+ {
+ setDirNames(location);
+
+ ll_apr_file_remove(mHeaderEntriesFileName, NULL);
+ ll_apr_file_remove(mHeaderDataFileName, NULL);
+ }
+ purgeAllTextures(true);
+}
+
+S64 LLTextureCache::initCache(ELLPath location, S64 max_size, BOOL read_only)
+{
+ mReadOnly = read_only;
+
+ S64 header_size = (max_size * 2) / 10;
+ S64 max_entries = header_size / TEXTURE_CACHE_ENTRY_SIZE;
+ sCacheMaxEntries = (S32)(llmin((S64)sCacheMaxEntries, max_entries));
+ header_size = sCacheMaxEntries * TEXTURE_CACHE_ENTRY_SIZE;
+ max_size -= header_size;
+ if (sCacheMaxTexturesSize > 0)
+ sCacheMaxTexturesSize = llmin(sCacheMaxTexturesSize, max_size);
+ else
+ sCacheMaxTexturesSize = max_size;
+ max_size -= sCacheMaxTexturesSize;
+
+ llinfos << "TEXTURE CACHE: Headers: " << sCacheMaxEntries
+ << " Textures size: " << sCacheMaxTexturesSize/(1024*1024) << " MB" << llendl;
+
+ setDirNames(location);
+
+ if (!mReadOnly)
+ {
+ LLFile::mkdir(mTexturesDirName.c_str());
+ const char* subdirs = "0123456789abcdef";
+ for (S32 i=0; i<16; i++)
+ {
+ std::string dirname = mTexturesDirName + gDirUtilp->getDirDelimiter() + subdirs[i];
+ LLFile::mkdir(dirname.c_str());
+ }
+ }
+ readHeaderCache();
+ purgeTextures(true); // calc mTexturesSize and make some room in the texture cache if we need it
+
+ return max_size; // unused cache space
+}
+
+struct lru_data
+{
+ lru_data(U32 t, S32 i, const LLUUID& id) { time=t; index=i; uuid=id; }
+ U32 time;
+ S32 index;
+ LLUUID uuid;
+ struct Compare
+ {
+ // lhs < rhs
+ typedef const lru_data* lru_data_ptr;
+ bool operator()(const lru_data_ptr& a, const lru_data_ptr& b) const
+ {
+ if (!(a->time < b->time))
+ return true;
+ else if (!(b->time < a->time))
+ return false;
+ else
+ return a->index < b->index;
+ }
+ };
+};
+
+// Called from either the main thread or the worker thread
+void LLTextureCache::readHeaderCache(apr_pool_t* poolp)
+{
+ LLMutexLock lock(&mHeaderMutex);
+ mHeaderEntriesInfo.mVersion = 0.f;
+ mHeaderEntriesInfo.mEntries = 0;
+ if (ll_apr_file_exists(mHeaderEntriesFileName, poolp))
+ {
+ ll_apr_file_read_ex(mHeaderEntriesFileName, poolp,
+ (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo));
+ }
+ if (mHeaderEntriesInfo.mVersion != sHeaderCacheVersion)
+ {
+ if (!mReadOnly)
+ {
+ // Info with 0 entries
+ mHeaderEntriesInfo.mVersion = sHeaderCacheVersion;
+ ll_apr_file_write_ex(mHeaderEntriesFileName, poolp,
+ (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo));
+ }
+ }
+ else
+ {
+ S32 num_entries = mHeaderEntriesInfo.mEntries;
+ if (num_entries)
+ {
+ Entry* entries = new Entry[num_entries];
+ ll_apr_file_read_ex(mHeaderEntriesFileName, poolp,
+ (U8*)entries, sizeof(EntriesInfo), num_entries*sizeof(Entry));
+ typedef std::set<lru_data*, lru_data::Compare> lru_set_t;
+ lru_set_t lru;
+ for (S32 i=0; i<num_entries; i++)
+ {
+ if (entries[i].mSize >= 0) // -1 indicates erased entry, skip
+ {
+ const LLUUID& id = entries[i].mID;
+ lru.insert(new lru_data(entries[i].mTime, i, id));
+ mHeaderIDMap[id] = i;
+ }
+ }
+ mLRU.clear();
+ S32 lru_entries = sCacheMaxEntries / 10;
+ for (lru_set_t::iterator iter = lru.begin(); iter != lru.end(); ++iter)
+ {
+ lru_data* data = *iter;
+ mLRU[data->index] = data->uuid;
+ if (--lru_entries <= 0)
+ break;
+ }
+ for_each(lru.begin(), lru.end(), DeletePointer());
+ delete[] entries;
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void LLTextureCache::purgeAllTextures(bool purge_directories)
+{
+ if (!mReadOnly)
+ {
+ const char* subdirs = "0123456789abcdef";
+ std::string delem = gDirUtilp->getDirDelimiter();
+ std::string mask = delem + "*";
+ for (S32 i=0; i<16; i++)
+ {
+ std::string dirname = mTexturesDirName + delem + subdirs[i];
+ gDirUtilp->deleteFilesInDir(dirname.c_str(),mask);
+ if (purge_directories)
+ {
+ LLFile::rmdir(dirname.c_str());
+ }
+ }
+ ll_apr_file_remove(mTexturesDirEntriesFileName, NULL);
+ if (purge_directories)
+ {
+ LLFile::rmdir(mTexturesDirName.c_str());
+ }
+ }
+ mTexturesSizeMap.clear();
+}
+
+void LLTextureCache::purgeTextures(bool validate)
+{
+ if (mReadOnly)
+ {
+ return;
+ }
+
+ LLMutexLock lock(&mHeaderMutex);
+
+ S32 filesize = ll_apr_file_size(mTexturesDirEntriesFileName, NULL);
+ S32 num_entries = filesize / sizeof(Entry);
+ if (num_entries * sizeof(Entry) != filesize)
+ {
+ llwarns << "Bad cache file: " << mTexturesDirEntriesFileName << " Purging." << llendl;
+ purgeAllTextures(false);
+ return;
+ }
+ if (num_entries == 0)
+ {
+ return; // nothing to do
+ }
+
+ Entry* entries = new Entry[num_entries];
+ S32 bytes_read = ll_apr_file_read_ex(mTexturesDirEntriesFileName, NULL,
+ (U8*)entries, 0, num_entries*sizeof(Entry));
+ if (bytes_read != filesize)
+ {
+ llwarns << "Bad cache file (2): " << mTexturesDirEntriesFileName << " Purging." << llendl;
+ purgeAllTextures(false);
+ return;
+ }
+
+ llinfos << "TEXTURE CACHE: Reading Entries..." << llendl;
+
+ std::map<LLUUID, S32> entry_idx_map;
+ S64 total_size = 0;
+ for (S32 idx=0; idx<num_entries; idx++)
+ {
+ const LLUUID& id = entries[idx].mID;
+// llinfos << "Entry: " << id << " Size: " << entries[i].mSize << " Time: " << entries[i].mTime << llendl;
+ std::map<LLUUID, S32>::iterator iter = entry_idx_map.find(id);
+ if (iter != entry_idx_map.end())
+ {
+ // Newer entry replacing older entry
+ S32 pidx = iter->second;
+ total_size -= entries[pidx].mSize;
+ entries[pidx].mSize = 0; // flag: skip older entry
+ }
+ entry_idx_map[id] = idx;
+ total_size += entries[idx].mSize;
+ }
+
+ U32 validate_idx = 0;
+ if (validate)
+ {
+ validate_idx = gSavedSettings.getU32("CacheValidateCounter");
+ U32 next_idx = (++validate_idx) % 256;
+ gSavedSettings.setU32("CacheValidateCounter", next_idx);
+ llinfos << "TEXTURE CACHE: Validating: " << validate_idx << llendl;
+ }
+
+ S64 min_cache_size = (sCacheMaxTexturesSize * 9) / 10;
+ S32 purge_count = 0;
+ S32 next_idx = 0;
+ for (S32 idx=0; idx<num_entries; idx++)
+ {
+ if (entries[idx].mSize == 0)
+ {
+ continue;
+ }
+ bool purge_entry = false;
+ std::string filename = getTextureFileName(entries[idx].mID);
+ if (total_size >= min_cache_size)
+ {
+ purge_entry = true;
+ }
+ else if (validate)
+ {
+ // make sure file exists and is the correct size
+ S32 uuididx = entries[idx].mID.mData[0];
+ if (uuididx == validate_idx)
+ {
+// llinfos << "Validating: " << filename << "Size: " << entries[idx].mSize << llendl;
+ S32 bodysize = ll_apr_file_size(filename, NULL);
+ if (bodysize != entries[idx].mSize)
+ {
+ llwarns << "TEXTURE CACHE BODY HAS BAD SIZE: " << bodysize << " != " << entries[idx].mSize
+ << filename << llendl;
+ purge_entry = true;
+ }
+ }
+ }
+ if (purge_entry)
+ {
+ purge_count++;
+// llinfos << "PURGING: " << filename << llendl;
+ ll_apr_file_remove(filename, NULL);
+ total_size -= entries[idx].mSize;
+ entries[idx].mSize = 0;
+ }
+ else
+ {
+ if (next_idx != idx)
+ {
+ entries[next_idx] = entries[idx];
+ }
+ ++next_idx;
+ }
+ }
+ num_entries = next_idx;
+
+ llinfos << "TEXTURE CACHE: Writing Entries: " << num_entries << llendl;
+
+ ll_apr_file_remove(mTexturesDirEntriesFileName, NULL);
+ ll_apr_file_write_ex(mTexturesDirEntriesFileName, NULL,
+ (U8*)&entries[0], 0, num_entries*sizeof(Entry));
+
+ mTexturesSizeTotal = 0;
+ mTexturesSizeMap.clear();
+ for (S32 idx=0; idx<num_entries; idx++)
+ {
+ mTexturesSizeMap[entries[idx].mID] = entries[idx].mSize;
+ mTexturesSizeTotal += entries[idx].mSize;
+ }
+ llassert(mTexturesSizeTotal == total_size);
+
+ delete[] entries;
+
+ llinfos << "TEXTURE CACHE:"
+ << " PURGED: " << purge_count
+ << " ENTRIES: " << num_entries
+ << " CACHE SIZE: " << total_size / 1024*1024 << " MB"
+ << llendl;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+// call lockWorkers() first!
+LLTextureCacheWorker* LLTextureCache::getReader(handle_t handle)
+{
+ LLTextureCacheWorker* res = NULL;
+ handle_map_t::iterator iter = mReaders.find(handle);
+ if (iter != mReaders.end())
+ {
+ res = iter->second;
+ }
+ return res;
+}
+
+LLTextureCacheWorker* LLTextureCache::getWriter(handle_t handle)
+{
+ LLTextureCacheWorker* res = NULL;
+ handle_map_t::iterator iter = mWriters.find(handle);
+ if (iter != mWriters.end())
+ {
+ res = iter->second;
+ }
+ return res;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+// Called from work thread
+S32 LLTextureCache::getHeaderCacheEntry(const LLUUID& id, bool touch, S32* imagesize)
+{
+ bool retry = false;
+ S32 idx = -1;
+
+ {
+ LLMutexLock lock(&mHeaderMutex);
+ id_map_t::iterator iter = mHeaderIDMap.find(id);
+ if (iter != mHeaderIDMap.end())
+ {
+ idx = iter->second;
+ }
+ else if (touch && !mReadOnly)
+ {
+ if (mHeaderEntriesInfo.mEntries < sCacheMaxEntries)
+ {
+ // Add an entry
+ idx = mHeaderEntriesInfo.mEntries++;
+ mHeaderIDMap[id] = idx;
+ // Update Info
+ ll_apr_file_write_ex(mHeaderEntriesFileName, getFileAPRPool(),
+ (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo));
+ }
+ else if (!mLRU.empty())
+ {
+ idx = mLRU.begin()->first; // will be erased below
+ const LLUUID& oldid = mLRU.begin()->second;
+ mHeaderIDMap.erase(oldid);
+ mTexturesSizeMap.erase(oldid);
+ mHeaderIDMap[id] = idx;
+ }
+ else
+ {
+ idx = -1;
+ retry = true;
+ }
+ }
+ if (idx >= 0)
+ {
+ if (touch && !mReadOnly)
+ {
+ // Update the lru entry
+ mLRU.erase(idx);
+ llassert_always(imagesize && *imagesize > 0);
+ Entry* entry = new Entry(id, *imagesize, time(NULL));
+ S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry);
+ ll_apr_file_write_ex(mHeaderEntriesFileName, getFileAPRPool(),
+ (U8*)entry, offset, sizeof(Entry));
+ delete entry;
+ }
+ else if (imagesize)
+ {
+ // Get the image size
+ Entry entry;
+ S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry);
+ ll_apr_file_read_ex(mHeaderEntriesFileName, getFileAPRPool(),
+ (U8*)&entry, offset, sizeof(Entry));
+ *imagesize = entry.mSize;
+ }
+ }
+ }
+ if (retry)
+ {
+ readHeaderCache(getFileAPRPool()); // updates the lru
+ llassert_always(!mLRU.empty() || mHeaderEntriesInfo.mEntries < sCacheMaxEntries);
+ idx = getHeaderCacheEntry(id, touch, imagesize); // assert above ensures no inf. recursion
+ }
+ return idx;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+// Calls from texture pipeline thread (i.e. LLTextureFetch)
+
+LLTextureCache::handle_t LLTextureCache::readFromCache(const LLUUID& id, U32 priority,
+ S32 offset, S32 size, ReadResponder* responder)
+{
+ // Note: checking to see if an entry exists can cause a stall,
+ // so let the thread handle it
+ LLMutexLock lock(&mWorkersMutex);
+ LLTextureCacheWorker* worker = new LLTextureCacheWorker(this, priority, id,
+ NULL, size, offset, 0,
+ responder);
+ handle_t handle = worker->read();
+ mReaders[handle] = worker;
+ return handle;
+}
+
+bool LLTextureCache::readComplete(handle_t handle, bool abort)
+{
+ lockWorkers();
+ handle_map_t::iterator iter = mReaders.find(handle);
+ llassert_always(iter != mReaders.end());
+ LLTextureCacheWorker* worker = iter->second;
+ bool res = worker->complete();
+ if (res || abort)
+ {
+ mReaders.erase(handle);
+ unlockWorkers();
+ worker->scheduleDelete();
+ return true;
+ }
+ else
+ {
+ unlockWorkers();
+ return false;
+ }
+}
+
+LLTextureCache::handle_t LLTextureCache::writeToCache(const LLUUID& id, U32 priority,
+ U8* data, S32 datasize, S32 imagesize,
+ WriteResponder* responder)
+{
+ if (mReadOnly)
+ {
+ return LLWorkerThread::nullHandle();
+ }
+ if (mDoPurge)
+ {
+ // NOTE: This may cause an occasional hiccup,
+ // but it really needs to be done on the control thread
+ // (i.e. here)
+ purgeTextures(false);
+ mDoPurge = FALSE;
+ }
+ if (datasize >= TEXTURE_CACHE_ENTRY_SIZE)
+ {
+ LLMutexLock lock(&mWorkersMutex);
+ llassert_always(imagesize > 0);
+ LLTextureCacheWorker* worker = new LLTextureCacheWorker(this, priority, id,
+ data, datasize, 0,
+ imagesize, responder);
+ handle_t handle = worker->write();
+ mWriters[handle] = worker;
+ return handle;
+ }
+ return LLWorkerThread::nullHandle();
+}
+
+bool LLTextureCache::writeComplete(handle_t handle, bool abort)
+{
+ lockWorkers();
+ handle_map_t::iterator iter = mWriters.find(handle);
+ llassert_always(iter != mWriters.end());
+ LLTextureCacheWorker* worker = iter->second;
+ if (worker->complete() || abort)
+ {
+ mWriters.erase(handle);
+ unlockWorkers();
+ worker->scheduleDelete();
+ return true;
+ }
+ else
+ {
+ unlockWorkers();
+ return false;
+ }
+}
+
+void LLTextureCache::prioritizeWrite(handle_t handle)
+{
+ // Don't prioritize yet, we might be working on this now
+ // which could create a deadlock
+ mPrioritizeWriteList.push_back(handle);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+// Called from MAIN thread (endWork())
+
+bool LLTextureCache::removeHeaderCacheEntry(const LLUUID& id)
+{
+ if (mReadOnly)
+ {
+ return false;
+ }
+ LLMutexLock lock(&mHeaderMutex);
+ id_map_t::iterator iter = mHeaderIDMap.find(id);
+ if (iter != mHeaderIDMap.end())
+ {
+ S32 idx = iter->second;
+ if (idx >= 0)
+ {
+ Entry* entry = new Entry(id, -1, time(NULL));
+ S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry);
+ ll_apr_file_write_ex(mHeaderEntriesFileName, NULL,
+ (U8*)entry, offset, sizeof(Entry));
+ delete entry;
+ mLRU[idx] = id;
+ mHeaderIDMap.erase(id);
+ mTexturesSizeMap.erase(id);
+ return true;
+ }
+ }
+ return false;
+}
+
+void LLTextureCache::removeFromCache(const LLUUID& id)
+{
+ llwarns << "Removing texture from cache: " << id << llendl;
+ if (!mReadOnly)
+ {
+ removeHeaderCacheEntry(id);
+ ll_apr_file_remove(getTextureFileName(id), NULL);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+LLTextureCache::ReadResponder::ReadResponder()
+ : mImageSize(0),
+ mImageLocal(FALSE)
+{
+}
+
+void LLTextureCache::ReadResponder::setData(U8* data, S32 datasize, S32 imagesize, S32 imageformat, BOOL imagelocal)
+{
+ if (mFormattedImage.notNull())
+ {
+ llassert_always(mFormattedImage->getCodec() == imageformat);
+ mFormattedImage->appendData(data, datasize);
+ }
+ else
+ {
+ mFormattedImage = LLImageFormatted::createFromType(imageformat);
+ mFormattedImage->setData(data,datasize);
+ }
+ mImageSize = imagesize;
+ mImageLocal = imagelocal;
+}
+
+//////////////////////////////////////////////////////////////////////////////
diff --git a/indra/newview/lltexturecache.h b/indra/newview/lltexturecache.h new file mode 100644 index 0000000000..3b16b26b4a --- /dev/null +++ b/indra/newview/lltexturecache.h @@ -0,0 +1,149 @@ +/**
+ * @file lltexturecache.h
+ * @brief Object for managing texture cachees.
+ *
+ * Copyright (c) 2000-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#ifndef LL_LLTEXTURECACHE_
+#define LL_LLTEXTURECACHE_H
+
+#include "lldir.h"
+#include "llstl.h"
+#include "llstring.h"
+#include "lluuid.h"
+
+#include "llworkerthread.h"
+
+class LLTextureCacheWorker;
+
+class LLTextureCache : public LLWorkerThread
+{
+ friend class LLTextureCacheWorker;
+
+public:
+
+ class Responder : public LLResponder
+ {
+ public:
+ virtual void setData(U8* data, S32 datasize, S32 imagesize, S32 imageformat, BOOL imagelocal) = 0;
+ };
+
+ class ReadResponder : public Responder
+ {
+ public:
+ ReadResponder();
+ void setData(U8* data, S32 datasize, S32 imagesize, S32 imageformat, BOOL imagelocal);
+ void setImage(LLImageFormatted* image) { mFormattedImage = image; }
+ protected:
+ LLPointer<LLImageFormatted> mFormattedImage;
+ S32 mImageSize;
+ BOOL mImageLocal;
+ };
+
+ class WriteResponder : public Responder
+ {
+ void setData(U8* data, S32 datasize, S32 imagesize, S32 imageformat, BOOL imagelocal)
+ {
+ // not used
+ }
+ };
+
+ LLTextureCache(bool threaded);
+ ~LLTextureCache();
+
+ /*virtual*/ S32 update(U32 max_time_ms);
+
+ void purgeCache(ELLPath location);
+ S64 initCache(ELLPath location, S64 maxsize, BOOL read_only);
+
+ handle_t readFromCache(const LLUUID& id, U32 priority, S32 offset, S32 size,
+ ReadResponder* responder);
+ bool readComplete(handle_t handle, bool abort);
+ handle_t writeToCache(const LLUUID& id, U32 priority, U8* data, S32 datasize, S32 imagesize,
+ WriteResponder* responder);
+ bool writeComplete(handle_t handle, bool abort = false);
+ void prioritizeWrite(handle_t handle);
+
+ void removeFromCache(const LLUUID& id);
+
+ // For LLTextureCacheWorker::Responder
+ LLTextureCacheWorker* getReader(handle_t handle);
+ LLTextureCacheWorker* getWriter(handle_t handle);
+ void lockWorkers() { mWorkersMutex.lock(); }
+ void unlockWorkers() { mWorkersMutex.unlock(); }
+
+ // debug
+ S32 getNumReads() { return mReaders.size(); }
+ S32 getNumWrites() { return mWriters.size(); }
+
+protected:
+ // Accessed by LLTextureCacheWorker
+ apr_pool_t* getFileAPRPool() { return mFileAPRPool; }
+ bool appendToTextureEntryList(const LLUUID& id, S32 size);
+ std::string getLocalFileName(const LLUUID& id);
+ std::string getTextureFileName(const LLUUID& id);
+
+private:
+ void setDirNames(ELLPath location);
+ void readHeaderCache(apr_pool_t* poolp = NULL);
+ void purgeAllTextures(bool purge_directories);
+ void purgeTextures(bool validate);
+ S32 getHeaderCacheEntry(const LLUUID& id, bool touch, S32* imagesize = NULL);
+ bool removeHeaderCacheEntry(const LLUUID& id);
+ void lockHeaders() { mHeaderMutex.lock(); }
+ void unlockHeaders() { mHeaderMutex.unlock(); }
+
+private:
+ // Internal
+ LLMutex mWorkersMutex;
+ LLMutex mHeaderMutex;
+ apr_pool_t* mFileAPRPool;
+
+ typedef std::map<handle_t, LLTextureCacheWorker*> handle_map_t;
+ handle_map_t mReaders;
+ handle_map_t mWriters;
+ std::vector<handle_t> mPrioritizeWriteList;
+
+ BOOL mReadOnly;
+
+ // Entries
+ struct EntriesInfo
+ {
+ F32 mVersion;
+ U32 mEntries;
+ };
+ struct Entry
+ {
+ Entry() {}
+ Entry(const LLUUID& id, S32 size, U32 time) : mID(id), mSize(size), mTime(time) {}
+ LLUUID mID; // 128 bits
+ S32 mSize; // total size of image if known (NOT size cached)
+ U32 mTime; // seconds since 1/1/1970
+ };
+
+ // HEADERS (Include first mip)
+ std::string mHeaderEntriesFileName;
+ std::string mHeaderDataFileName;
+ EntriesInfo mHeaderEntriesInfo;
+ typedef std::map<S32,LLUUID> index_map_t;
+ index_map_t mLRU; // index, id; stored as a map for fast removal
+ typedef std::map<LLUUID,S32> id_map_t;
+ id_map_t mHeaderIDMap;
+
+ // BODIES (TEXTURES minus headers)
+ std::string mTexturesDirName;
+ std::string mTexturesDirEntriesFileName;
+ typedef std::map<LLUUID,S32> size_map_t;
+ size_map_t mTexturesSizeMap;
+ S64 mTexturesSizeTotal;
+ LLAtomic32<BOOL> mDoPurge;
+
+ // Statics
+ static F32 sHeaderCacheVersion;
+ static U32 sCacheMaxEntries;
+ static S64 sCacheMaxTexturesSize;
+};
+
+#endif // LL_LLTEXTURECACHE_H
diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index 75777024da..db747c60fc 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -1,6 +1,6 @@ /** - * @file llviewerimage.cpp - * @brief Object which handles a received image (and associated texture(s)) + * @file lltexturecache.cpp + * @brief Object which fetches textures from the cache and/or network * * Copyright (c) 2000-$CurrentYear$, Linden Research, Inc. * $License$ @@ -12,96 +12,283 @@ #include "lltexturefetch.h" -#include "llworkerthread.h" +#include "llcurl.h" +#include "llhttpclient.h" #include "llimage.h" -#include "llvfs.h" +#include "llimageworker.h" +#include "llworkerthread.h" +#include "llagent.h" +#include "lltexturecache.h" +#include "llviewerimagelist.h" #include "llviewerimage.h" +#include "llviewerregion.h" #include "viewer.h" ////////////////////////////////////////////////////////////////////////////// +//static class LLTextureFetchWorker : public LLWorkerClass { - friend class LLTextureFetchImpl; - -public: - // From LLWorkerClass - static void initClass(bool threaded, bool runalways); - static void updateClass(); - static void cleanupClass(); - - // New methods - static LLTextureFetchWorker* getWorker(const LLUUID& id, const LLHost& host, - F32 mPriority, S32 discard, - BOOL needs_aux = FALSE); - static LLTextureFetchWorker* getActiveWorker(const LLUUID& id); + friend class LLTextureFetch; private: - static void sendRequestListToSimulators(); + class URLResponder : public LLHTTPClient::Responder + { + public: + URLResponder(LLTextureFetch* fetcher, const LLUUID& id) + : mFetcher(fetcher), mID(id) + { + } + ~URLResponder() + { + } + virtual void error(U32 status, const std::string& reason) + { + mFetcher->lockQueue(); + LLTextureFetchWorker* worker = mFetcher->getWorker(mID); + if (worker) + { + llinfos << "LLTextureFetchWorker::URLResponder::error " << status << ": " << reason << llendl; + worker->callbackURLReceived(LLSD(), false); + } + mFetcher->unlockQueue(); + } + virtual void result(const LLSD& content) + { + mFetcher->lockQueue(); + LLTextureFetchWorker* worker = mFetcher->getWorker(mID); + if (worker) + { + worker->callbackURLReceived(content, true); + } + mFetcher->unlockQueue(); + } + private: + LLTextureFetch* mFetcher; + LLUUID mID; + }; + + class HTTPGetResponder : public LLCurl::Responder + { + public: + HTTPGetResponder(LLTextureFetch* fetcher, const LLUUID& id) + : mFetcher(fetcher), mID(id) + { + } + ~HTTPGetResponder() + { + } + virtual void completed(U32 status, const std::stringstream& content) + { + mFetcher->lockQueue(); + LLTextureFetchWorker* worker = mFetcher->getWorker(mID); + if (worker) + { + const std::string& cstr = content.str(); + if (200 <= status && status < 300) + { + if (203 == status) // partial information (i.e. last block) + { + worker->callbackHttpGet((U8*)cstr.c_str(), cstr.length(), true); + } + else + { + worker->callbackHttpGet((U8*)cstr.c_str(), cstr.length(), false); + } + } + else + { + llinfos << "LLTextureFetchWorker::HTTPGetResponder::error " << status << ": " << cstr << llendl; + worker->callbackHttpGet(NULL, -1, true); + } + } + mFetcher->unlockQueue(); + } + private: + LLTextureFetch* mFetcher; + LLUUID mID; + }; + + class CacheReadResponder : public LLTextureCache::ReadResponder + { + public: + CacheReadResponder(LLTextureFetch* fetcher, const LLUUID& id, LLImageFormatted* image) + : mFetcher(fetcher), mID(id) + { + setImage(image); + } + virtual void completed(bool success) + { + mFetcher->lockQueue(); + LLTextureFetchWorker* worker = mFetcher->getWorker(mID); + if (worker) + { + worker->callbackCacheRead(success, mFormattedImage, mImageSize, mImageLocal); + } + mFetcher->unlockQueue(); + } + private: + LLTextureFetch* mFetcher; + LLUUID mID; + }; + + class CacheWriteResponder : public LLTextureCache::WriteResponder + { + public: + CacheWriteResponder(LLTextureFetch* fetcher, const LLUUID& id) + : mFetcher(fetcher), mID(id) + { + } + virtual void completed(bool success) + { + mFetcher->lockQueue(); + LLTextureFetchWorker* worker = mFetcher->getWorker(mID); + if (worker) + { + worker->callbackCacheWrite(success); + } + mFetcher->unlockQueue(); + } + private: + LLTextureFetch* mFetcher; + LLUUID mID; + }; + + class DecodeResponder : public LLResponder + { + public: + DecodeResponder(LLTextureFetch* fetcher, const LLUUID& id, LLTextureFetchWorker* worker) + : mFetcher(fetcher), mID(id), mWorker(worker) + { + } + virtual void completed(bool success) + { + mFetcher->lockQueue(); + LLTextureFetchWorker* worker = mFetcher->getWorker(mID); + if (worker) + { + worker->callbackDecoded(success); + } + mFetcher->unlockQueue(); + } + private: + LLTextureFetch* mFetcher; + LLUUID mID; + LLTextureFetchWorker* mWorker; // debug only (may get deleted from under us, use mFetcher/mID) + }; + + struct Compare + { + // lhs < rhs + bool operator()(const LLTextureFetchWorker* lhs, const LLTextureFetchWorker* rhs) const + { + // greater priority is "less" + const F32 lpriority = lhs->mImagePriority; + const F32 rpriority = rhs->mImagePriority; + if (lpriority > rpriority) // higher priority + return true; + else if (lpriority < rpriority) + return false; + else + return lhs < rhs; + } + }; public: - virtual bool doWork(S32 param); // Called from LLWorkerThread::processRequest() + /*virtual*/ bool doWork(S32 param); // Called from LLWorkerThread::processRequest() + /*virtual*/ void finishWork(S32 param, bool completed); // called from finishRequest() (WORK THREAD) + /*virtual*/ bool deleteOK(); // called from update() (WORK THREAD) ~LLTextureFetchWorker(); void relese() { --mActiveCount; } - protected: - LLTextureFetchWorker(const LLUUID& id, const LLHost& host, F32 mPriority, S32 discard); + LLTextureFetchWorker(LLTextureFetch* fetcher, const LLUUID& id, const LLHost& host, + F32 priority, S32 discard, S32 size); private: - virtual void startWork(S32 param); // called from addWork() (MAIN THREAD) - virtual void endWork(S32 param, bool aborted); // called from doWork() (MAIN THREAD) + /*virtual*/ void startWork(S32 param); // called from addWork() (MAIN THREAD) + /*virtual*/ void endWork(S32 param, bool aborted); // called from doWork() (MAIN THREAD) + void resetFormattedData(); + void setImagePriority(F32 priority); - void setDesiredDiscard(S32 discard); - void insertPacket(S32 index, U8* data, S32 size); + void setDesiredDiscard(S32 discard, S32 size); + bool insertPacket(S32 index, U8* data, S32 size); void clearPackets(); U32 calcWorkPriority(); - bool startVFSLoad(LLVFS* vfs, LLAssetType::EType asset_type); - bool loadFromVFS(); + void removeFromCache(); bool processSimulatorPackets(); void startDecode(); bool decodeImage(); - + bool writeToCacheComplete(); + void lockWorkData() { mWorkMutex.lock(); } void unlockWorkData() { mWorkMutex.unlock(); } - - static void lockQueue() { sDataMutex->lock(); } - static void unlockQueue() { sDataMutex->unlock(); } + + void callbackURLReceived(const LLSD& data, bool success); + void callbackHttpGet(U8* data, S32 data_size, bool last_block); + void callbackCacheRead(bool success, LLImageFormatted* image, + S32 imagesize, BOOL islocal); + void callbackCacheWrite(bool success); + void callbackDecoded(bool success); private: enum e_state { - INIT = 1, - LOAD_FROM_CACHE, + // NOTE: Affects LLTextureBar::draw in lltextureview.cpp (debug hack) + INVALID = 0, + INIT, + LOAD_FROM_TEXTURE_CACHE, + CACHE_POST, + LOAD_FROM_NETWORK, LOAD_FROM_SIMULATOR, - WRITE_TO_VFS, + LOAD_FROM_HTTP_GET_URL, + LOAD_FROM_HTTP_GET_DATA, DECODE_IMAGE, DECODE_IMAGE_UPDATE, + WRITE_TO_CACHE, + WAIT_ON_WRITE, DONE }; + static const char* sStateDescs[]; e_state mState; + LLTextureFetch* mFetcher; + LLImageWorker* mImageWorker; LLPointer<LLImageFormatted> mFormattedImage; LLPointer<LLImageRaw> mRawImage; LLPointer<LLImageRaw> mAuxImage; LLUUID mID; LLHost mHost; - F32 mPriority; + F32 mImagePriority; + U32 mWorkPriority; + F32 mRequestedPriority; S32 mDesiredDiscard; + S32 mSimRequestedDiscard; S32 mRequestedDiscard; + S32 mLoadedDiscard; S32 mDecodedDiscard; LLFrameTimer mRequestedTimer; LLFrameTimer mIdleTimer; - LLVFSThread::handle_t mFileHandle; + LLTextureCache::handle_t mCacheReadHandle; + LLTextureCache::handle_t mCacheWriteHandle; U8* mBuffer; S32 mBufferSize; S32 mRequestedSize; + S32 mDesiredSize; + S32 mFileSize; + S32 mCachedSize; BOOL mLoaded; BOOL mRequested; BOOL mDecoded; + BOOL mWritten; BOOL mNeedsAux; + BOOL mHaveAllData; + BOOL mUseHTTPGet; + BOOL mInLocalCache; + S32 mRetryAttempt; + std::string mURL; S32 mActiveCount; // Work Data @@ -110,638 +297,1450 @@ private: { PacketData(U8* data, S32 size) { mData = data; mSize = size; } ~PacketData() { clearData(); } - void clearData() { delete mData; mData = NULL; } + void clearData() { delete[] mData; mData = NULL; } U8* mData; U32 mSize; }; std::vector<PacketData*> mPackets; + S32 mFirstPacket; S32 mLastPacket; - S32 mTotalPackets; - S32 mTotalBytes; - - // Class variables (statics) - - static LLWorkerThread* sWorkerThread; - static LLMutex* sDataMutex; + U16 mTotalPackets; + U8 mImageCodec; + LLFrameTimer mFetchTimer; // debug +}; - // Map of all requests by UUID - typedef std::map<LLUUID,LLTextureFetchWorker*> map_t; - static map_t sRequests; +//static +const char* LLTextureFetchWorker::sStateDescs[] = { + "INVALID", + "INIT", + "LOAD_FROM_TEXTURE_CACHE", + "CACHE_POST", + "LOAD_FROM_NETWORK", + "LOAD_FROM_SIMULATOR", + "LOAD_FROM_HTTP_URL", + "LOAD_FROM_HTTP_DATA", + "DECODE_IMAGE", + "DECODE_IMAGE_UPDATE", + "WRITE_TO_CACHE", + "WAIT_ON_WRITE", + "DONE", +}; - // Set of requests that require network data - typedef std::set<LLTextureFetchWorker*> queue_t ; - static queue_t sNetworkQueue; +// called from MAIN THREAD - static LLFrameTimer sNetworkTimer; -}; +LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher, + const LLUUID& id, // Image UUID + const LLHost& host, // Simulator host + F32 priority, // Priority + S32 discard, // Desired discard + S32 size) // Desired size + : LLWorkerClass(fetcher, "TextureFetch"), + mState(INIT), + mFetcher(fetcher), + mImageWorker(NULL), + mID(id), + mHost(host), + mImagePriority(priority), + mWorkPriority(0), + mRequestedPriority(0.f), + mDesiredDiscard(-1), + mSimRequestedDiscard(-1), + mRequestedDiscard(-1), + mLoadedDiscard(-1), + mDecodedDiscard(-1), + mCacheReadHandle(LLTextureCache::nullHandle()), + mCacheWriteHandle(LLTextureCache::nullHandle()), + mBuffer(NULL), + mBufferSize(0), + mRequestedSize(0), + mDesiredSize(FIRST_PACKET_SIZE), + mFileSize(0), + mCachedSize(0), + mLoaded(FALSE), + mRequested(FALSE), + mDecoded(FALSE), + mWritten(FALSE), + mNeedsAux(FALSE), + mHaveAllData(FALSE), + mUseHTTPGet(FALSE), + mInLocalCache(FALSE), + mRetryAttempt(0), + mActiveCount(0), + mWorkMutex(fetcher->getWorkerAPRPool()), + mFirstPacket(0), + mLastPacket(-1), + mTotalPackets(0), + mImageCodec(IMG_CODEC_INVALID) +{ + calcWorkPriority(); + if ((gSavedSettings.getBOOL("ImagePipelineUseHTTP")) && + (host == LLHost::invalid)) + { + mUseHTTPGet = TRUE; + } + if (!mFetcher->mDebugPause) + { + U32 work_priority = mWorkPriority | LLWorkerThread::PRIORITY_HIGH; + addWork(0, work_priority ); + } + setDesiredDiscard(discard, size); +} -//statics -LLTextureFetchWorker::map_t LLTextureFetchWorker::sRequests; -LLTextureFetchWorker::queue_t LLTextureFetchWorker::sNetworkQueue; -LLFrameTimer LLTextureFetchWorker::sNetworkTimer; -LLWorkerThread* LLTextureFetchWorker::sWorkerThread = NULL; -LLMutex* LLTextureFetchWorker::sDataMutex = NULL; +LLTextureFetchWorker::~LLTextureFetchWorker() +{ + llassert_always(!haveWork()); + lockWorkData(); + if (mCacheReadHandle != LLTextureCache::nullHandle()) + { + mFetcher->mTextureCache->readComplete(mCacheReadHandle, true); + } + if (mCacheWriteHandle != LLTextureCache::nullHandle()) + { + mFetcher->mTextureCache->writeComplete(mCacheWriteHandle, true); + } + if (mImageWorker) + { + mImageWorker->scheduleDelete(); + } + mFormattedImage = NULL; + clearPackets(); + unlockWorkData(); +} -// called from MAIN THREAD -//static -void LLTextureFetchWorker::initClass(bool threaded, bool runalways) +void LLTextureFetchWorker::clearPackets() { - sWorkerThread = new LLWorkerThread(threaded, runalways); - sDataMutex = new LLMutex(sWorkerThread->getAPRPool()); + for_each(mPackets.begin(), mPackets.end(), DeletePointer()); + mPackets.clear(); + mTotalPackets = 0; + mLastPacket = -1; + mFirstPacket = 0; } -// called from MAIN THREAD -//static -void LLTextureFetchWorker::updateClass() +U32 LLTextureFetchWorker::calcWorkPriority() { - const F32 REQUEST_TIME = 1.f; - const F32 MIN_IDLE_TIME = 1.f * 60.f; // 1 minute - const F32 MAX_IDLE_TIME = 5.f * 60.f; // 5 minutes - const S32 MIN_IDLE_COUNT = 16; // always keep last 16 idle requests - const F32 MAX_IDLE_COUNT = 1024; // max number of idle requests + F32 priority_scale = (F32)LLWorkerThread::PRIORITY_LOWBITS / LLViewerImage::maxDecodePriority(); + mWorkPriority = (U32)(mImagePriority * priority_scale); + return mWorkPriority; +} - // Periodically, gather the list of textures that need data from the network - // And send the requests out to the simulators - if (sNetworkTimer.getElapsedTimeF32() >= REQUEST_TIME) +void LLTextureFetchWorker::setDesiredDiscard(S32 discard, S32 size) +{ + if (mDesiredDiscard != discard) { - sNetworkTimer.reset(); - sendRequestListToSimulators(); + if (!haveWork()) + { + calcWorkPriority(); + if (!mFetcher->mDebugPause) + { + U32 work_priority = mWorkPriority | LLWorkerThread::PRIORITY_HIGH; + addWork(0, work_priority); + } + } + else if (mDesiredDiscard < discard) + { + U32 work_priority = mWorkPriority | LLWorkerThread::PRIORITY_HIGH; + setPriority(work_priority); + } + mDesiredDiscard = discard; + mDesiredSize = size; } - // Remove any old requests (releasing their raw data) - typedef std::pair<F32, LLTextureFetchWorker*> idle_pair; - typedef std::set<idle_pair, compare_pair_greater<F32,LLTextureFetchWorker*> > idle_set; - idle_set remove_set; - for (map_t::iterator iter = sRequests.begin(); iter != sRequests.end(); ++iter) + else if (size > mDesiredSize) { - LLTextureFetchWorker* worker = iter->second; - if (worker->mActiveCount > 0) - continue; - if (worker->haveWork()) - continue; - F32 idletime = worker->mIdleTimer.getElapsedTimeF32(); - if (idletime < MIN_IDLE_TIME) - continue; - remove_set.insert(std::make_pair(idletime, worker)); + mDesiredSize = size; + U32 work_priority = mWorkPriority | LLWorkerThread::PRIORITY_HIGH; + setPriority(work_priority); } - S32 num_left = remove_set.size(); - for (idle_set::iterator iter = remove_set.begin(); iter != remove_set.end(); ++iter) +} + +void LLTextureFetchWorker::setImagePriority(F32 priority) +{ + F32 delta = fabs(priority - mImagePriority); + if (delta > (mImagePriority * .05f)) // 5% { - if (num_left <= MIN_IDLE_COUNT) - break; - if (iter->first < MAX_IDLE_TIME && - num_left < MAX_IDLE_COUNT) - break; - num_left--; + mImagePriority = priority; + calcWorkPriority(); + U32 work_priority = mWorkPriority | (getPriority() & LLWorkerThread::PRIORITY_HIGHBITS); + setPriority(work_priority); } } -// called from MAIN THREAD -//static -void LLTextureFetchWorker::sendRequestListToSimulators() +void LLTextureFetchWorker::resetFormattedData() { - const F32 LAZY_FLUSH_TIMEOUT = 60.f; - const S32 IMAGES_PER_REQUEST = 50; - // Send requests - typedef std::map< LLHost, std::vector<LLTextureFetchWorker*> > work_request_map_t; - work_request_map_t requests; - for (queue_t::iterator iter = sNetworkQueue.begin(); iter != sNetworkQueue.end(); ++iter) + delete[] mBuffer; + mBuffer = NULL; + mBufferSize = 0; + if (mFormattedImage.notNull()) + { + mFormattedImage->deleteData(); + } + mHaveAllData = FALSE; +} + +// Called from MAIN thread +void LLTextureFetchWorker::startWork(S32 param) +{ + llassert(mImageWorker == NULL); + llassert(mFormattedImage.isNull()); +} + +#include "llviewerimagelist.h" // debug + +// Called from LLWorkerThread::processRequest() +bool LLTextureFetchWorker::doWork(S32 param) +{ + LLMutexLock lock(&mWorkMutex); + + e_state old_state = mState; + mFetchTimer.reset(); + + if (mFetcher->mDebugPause) + { + return false; // debug: don't do any work + } + if (mID == mFetcher->mDebugID) + { + mFetcher->mDebugCount++; // for setting breakpoints + } + + if (mState == INIT) { - LLTextureFetchWorker* req = *iter; - if (req->haveWork()) + mRequestedDiscard = -1; + mLoadedDiscard = -1; + mDecodedDiscard = -1; + mRequestedSize = 0; + mFileSize = 0; + mCachedSize = 0; + mLoaded = FALSE; + mRequested = FALSE; + mDecoded = FALSE; + mWritten = FALSE; + delete[] mBuffer; + mBuffer = NULL; + mBufferSize = 0; + mHaveAllData = FALSE; + clearPackets(); + mCacheReadHandle = LLTextureCache::nullHandle(); + mCacheWriteHandle = LLTextureCache::nullHandle(); + mURL.clear(); + mState = LOAD_FROM_TEXTURE_CACHE; + // fall through + } + + if (mState == LOAD_FROM_TEXTURE_CACHE) + { + if (mCacheReadHandle == LLTextureCache::nullHandle()) { - continue; // busy + U32 cache_priority = mWorkPriority; + S32 offset = mFormattedImage.notNull() ? mFormattedImage->getDataSize() : 0; + S32 size = mDesiredSize - offset; + if (size <= 0) + { + mState = CACHE_POST; + return false; + } + mFileSize = 0; + mLoaded = FALSE; + setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it + CacheReadResponder* responder = new CacheReadResponder(mFetcher, mID, mFormattedImage); + mCacheReadHandle = mFetcher->mTextureCache->readFromCache(mID, cache_priority, + offset, size, responder); } - if ((req->mRequestedDiscard == req->mDesiredDiscard) && - (req->mRequestedTimer.getElapsedTimeF32() < LAZY_FLUSH_TIMEOUT)) + + if (mLoaded) { - continue; + // Make sure request is complete. *TODO: make this auto-complete + if (mFetcher->mTextureCache->readComplete(mCacheReadHandle, false)) + { + mCacheReadHandle = LLTextureCache::nullHandle(); + mState = CACHE_POST; + // fall through + } + else + { + return false; + } + } + else + { + return false; } - req->mRequestedDiscard = req->mDesiredDiscard; - req->mRequestedTimer.reset(); - requests[req->mHost].push_back(req); } - for (work_request_map_t::iterator iter1 = requests.begin(); - iter1 != requests.end(); ++iter1) + + if (mState == CACHE_POST) { - LLHost host = iter1->first; - // invalid host = load from static VFS - if (host != LLHost::invalid) + mCachedSize = mFormattedImage.notNull() ? mFormattedImage->getDataSize() : 0; + // Successfully loaded + if ((mCachedSize >= mDesiredSize) || mHaveAllData) { - S32 request_count = 0; - for (std::vector<LLTextureFetchWorker*>::iterator iter2 = iter1->second.begin(); - iter2 != iter1->second.end(); ++iter2) + // we have enough data, decode it + llassert_always(mFormattedImage->getDataSize() > 0); + mState = DECODE_IMAGE; + // fall through + } + else + { + // need more data + mState = LOAD_FROM_NETWORK; + // fall through + } + } + + if (mState == LOAD_FROM_NETWORK) + { + if (mFormattedImage.isNull()) + { + mFormattedImage = new LLImageJ2C; + } + mState = mUseHTTPGet ? LOAD_FROM_HTTP_GET_URL : LOAD_FROM_SIMULATOR; + return false; + } + + if (mState == LOAD_FROM_SIMULATOR) + { + if (!mRequested) + { + S32 data_size = mFormattedImage->getDataSize(); + if (data_size > 0) { - LLTextureFetchWorker* req = *iter2; - if (0 == request_count) + mFirstPacket = (data_size - FIRST_PACKET_SIZE) / MAX_IMG_PACKET_SIZE + 1; + if (FIRST_PACKET_SIZE + (mFirstPacket-1) * MAX_IMG_PACKET_SIZE != data_size) { - gMessageSystem->newMessageFast(_PREHASH_RequestImage); + llwarns << "Bad CACHED TEXTURE size: " << data_size << " removing." << llendl; + removeFromCache(); + resetFormattedData(); + clearPackets(); } - S32 packet = req->mLastPacket + 1; - gMessageSystem->nextBlockFast(_PREHASH_RequestImage); - gMessageSystem->addUUIDFast(_PREHASH_Image, req->mID); - gMessageSystem->addS32Fast(_PREHASH_DiscardLevel, req->mDesiredDiscard); - gMessageSystem->addF32Fast(_PREHASH_DownloadPriority, req->mPriority); - gMessageSystem->addU32Fast(_PREHASH_Packet, packet); + else + { + mLastPacket = mFirstPacket-1; + mTotalPackets = (mFileSize - FIRST_PACKET_SIZE + MAX_IMG_PACKET_SIZE-1) / MAX_IMG_PACKET_SIZE + 1; + } + } + mRequested = TRUE; + mRequestedSize = mDesiredSize; + mRequestedDiscard = mDesiredDiscard; + mFetcher->lockQueue(); + mFetcher->addToNetworkQueue(this); + mFetcher->unlockQueue(); + } + if (processSimulatorPackets()) + { + mFetcher->lockQueue(); + mFetcher->removeFromNetworkQueue(this); + mFetcher->unlockQueue(); + if (!mFormattedImage->getDataSize()) + { + // processSimulatorPackets() failed + llwarns << "processSimulatorPackets() failed to load buffer" << llendl; + return true; // failed + } + setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); + mState = DECODE_IMAGE; + } + else + { + setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); + } + return false; + } + + if (mState == LOAD_FROM_HTTP_GET_URL) + { + if (!mRequested) + { + mRequested = TRUE; + mLoaded = FALSE; + std::string url; + LLViewerRegion* region = gAgent.getRegion(); + if (region) + { + url = region->getCapability("RequestTextureDownload"); + } + if (!url.empty()) + { + LLSD sd; + sd = mID.asString(); + LLHTTPClient::post(url, sd, new URLResponder(mFetcher, mID)); +//*TODO:uncomment setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); + return false; + } + else + { + llwarns << mID << ": HTTP get url failed, requesting from simulator" << llendl; + mRequested = FALSE; + mState = LOAD_FROM_SIMULATOR; + return false; + } + } + else + { + if (mLoaded) + { + if (!mURL.empty()) + { + mState = LOAD_FROM_HTTP_GET_DATA; + mRequested = FALSE; // reset + mLoaded = FALSE; // reset + } + else + { + llwarns << mID << ": HTTP get url is empty, requesting from simulator" << llendl; + mRequested = FALSE; + mState = LOAD_FROM_SIMULATOR; + return false; + } + } + } + // fall through + } + + if (mState == LOAD_FROM_HTTP_GET_DATA) + { + if (!mRequested) + { + mRequested = TRUE; + S32 cur_size = mFormattedImage->getDataSize(); // amount of data we already have + mRequestedSize = mDesiredSize; + mRequestedDiscard = mDesiredDiscard; +#if 1 // *TODO: LLCurl::getByteRange is broken (ignores range) + cur_size = 0; + mFormattedImage->deleteData(); +#endif + mRequestedSize -= cur_size; + // F32 priority = mImagePriority / (F32)LLViewerImage::maxDecodePriority(); // 0-1 + S32 offset = cur_size; + mBufferSize = cur_size; // This will get modified by callbackHttpGet() + std::string url; + if (mURL.empty()) + { + //url = "http://asset.agni/0000002f-38ae-0e17-8e72-712e58964e9c.texture"; + std::stringstream urlstr; + urlstr << "http://asset.agni/" << mID.asString() << ".texture"; + url = urlstr.str(); + } + else + { + url = mURL; + } + mLoaded = FALSE; +// llinfos << "HTTP GET: " << mID << " Offset: " << offset << " Bytes: " << mRequestedSize << llendl; + LLCurl::getByteRange(url, offset, mRequestedSize, + new HTTPGetResponder(mFetcher, mID)); // *TODO: use mWorkPriority +//*TODO:uncomment setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); + return false; // not done + } - request_count++; - if (request_count >= IMAGES_PER_REQUEST) + if (mLoaded) + { + S32 cur_size = mFormattedImage->getDataSize(); + if (mRequestedSize < 0) + { + llwarns << "http get failed for: " << mID << llendl; + if (cur_size == 0) { - gMessageSystem->sendSemiReliable(host, NULL, NULL); - request_count = 0; + resetFormattedData(); + return true; // failed + } + else + { + mState = DECODE_IMAGE; + return false; // use what we have } } - if (request_count >= IMAGES_PER_REQUEST) + llassert(mBufferSize == cur_size + mRequestedSize); + if (mHaveAllData) { - gMessageSystem->sendSemiReliable(host, NULL, NULL); + mFileSize = mBufferSize; + } + if (mRequestedSize > 0) + { + U8* buffer = new U8[mBufferSize]; + if (cur_size > 0) + { + memcpy(buffer, mFormattedImage->getData(), cur_size); + } + memcpy(buffer + cur_size, mBuffer, mRequestedSize); // append + // NOTE: setData releases current data and owns new data (buffer) + mFormattedImage->setData(buffer, mBufferSize); + // delete temp data + delete[] mBuffer; // Note: not 'buffer' (assigned in setData()) + mBuffer = NULL; + mBufferSize = 0; + } + else + { + llassert_always(cur_size); } + mLoadedDiscard = mRequestedDiscard; + setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); + mState = DECODE_IMAGE; + return false; } + + // NOTE: Priority gets updated when the http get completes (in callbackHTTPGet()) + setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); + return false; } -} -//static -LLTextureFetchWorker* LLTextureFetchWorker::getWorker(const LLUUID& id, - const LLHost& host, - F32 priority, - S32 discard, - BOOL needs_aux) -{ - LLTextureFetchWorker* res; - lockQueue(); - map_t::iterator iter = sRequests.find(id); - if (iter != sRequests.end()) + if (mState == DECODE_IMAGE) { - res = iter->second; - if (res->mHost != host) + llassert_always(mFormattedImage->getDataSize() > 0); + setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it + startDecode(); + mState = DECODE_IMAGE_UPDATE; + // fall though (need to call requestDecodedData() to start work) + } + + if (mState == DECODE_IMAGE_UPDATE) + { + if (decodeImage()) { - llerrs << "LLTextureFetchWorker::getWorker called with multiple hosts" << llendl; + if (mDecodedDiscard < 0) + { + if (mCachedSize > 0 && !mInLocalCache && mRetryAttempt == 0) + { + // Cache file should be deleted, try again + llwarns << mID << ": Decode of cached file failed (removed), retrying" << llendl; + mFormattedImage = NULL; + ++mRetryAttempt; + setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); + mState = INIT; + return false; + } + else + { + llwarns << "UNABLE TO LOAD TEXTURE: " << mID << " RETRIES: " << mRetryAttempt << llendl; + mState = DONE; // failed + } + } + else + { + setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); + mState = WRITE_TO_CACHE; + } + // fall through + } + else + { + return false; } - res->setImagePriority(priority); - res->setDesiredDiscard(discard); - } - else + + if (mState == WRITE_TO_CACHE) { - res = new LLTextureFetchWorker(id, host, priority, discard); + if (mInLocalCache || !mFileSize || !mRequested) + { + // If we're in a local cache or we didn't actually receive any new data, skip + mState = DONE; + return false; + } + S32 datasize = mFormattedImage->getDataSize(); + llassert_always(datasize); + setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it + U32 cache_priority = mWorkPriority; + mWritten = FALSE; + CacheWriteResponder* responder = new CacheWriteResponder(mFetcher, mID); + mCacheWriteHandle = mFetcher->mTextureCache->writeToCache(mID, cache_priority, + mFormattedImage->getData(), datasize, + mFileSize, responder); + mState = WAIT_ON_WRITE; + // fall through + } + + if (mState == WAIT_ON_WRITE) + { + if (writeToCacheComplete()) + { + mState = DONE; + // fall through + } + else + { + if (mDesiredDiscard < mDecodedDiscard) + { + // We're waiting for this write to complete before we can receive more data + // (we can't touch mFormattedImage until the write completes) + // Prioritize the write + mFetcher->mTextureCache->prioritizeWrite(mCacheWriteHandle); + } + return false; + } } - unlockQueue(); - res->mActiveCount++; - res->mNeedsAux = needs_aux; - return res; -} -LLTextureFetchWorker* LLTextureFetchWorker::getActiveWorker(const LLUUID& id) -{ - LLTextureFetchWorker* res = NULL; - lockQueue(); - map_t::iterator iter = sRequests.find(id); - if (iter != sRequests.end()) + if (mState == DONE) { - res = iter->second; + if (mDecodedDiscard >= 0 && mDesiredDiscard < mDecodedDiscard) + { + // More data was requested, return to INIT + mState = INIT; + setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); + return false; + } + if (old_state != DONE) + { + mIdleTimer.reset(); + } + return true; } - unlockQueue(); - return res; + + return false; } -LLTextureFetchWorker::LLTextureFetchWorker(const LLUUID& id, // Image UUID - const LLHost& host, // Simulator host - F32 priority, // Priority - S32 discard) // Desired discard level - : LLWorkerClass(sWorkerThread, "TextureFetch"), - mState(INIT), - mID(id), - mHost(host), - mPriority(priority), - mDesiredDiscard(discard), - mRequestedDiscard(-1), - mDecodedDiscard(-1), - mFileHandle(LLVFSThread::nullHandle()), - mBuffer(NULL), - mBufferSize(0), - mRequestedSize(0), - mLoaded(FALSE), - mRequested(FALSE), - mDecoded(FALSE), - mActiveCount(0), - mWorkMutex(sWorkerThread->getAPRPool()), - mLastPacket(-1), - mTotalPackets(0), - mTotalBytes(0) +// Called from MAIN thread +void LLTextureFetchWorker::endWork(S32 param, bool aborted) { - lockQueue(); - sRequests[mID] = this; - unlockQueue(); - addWork(0, calcWorkPriority()); + if (mImageWorker) + { + mImageWorker->scheduleDelete(); + mImageWorker = NULL; + } + mFormattedImage = NULL; } -LLTextureFetchWorker::~LLTextureFetchWorker() +////////////////////////////////////////////////////////////////////////////// + +// virtual +void LLTextureFetchWorker::finishWork(S32 param, bool completed) { - lockQueue(); - mFormattedImage = NULL; - map_t::iterator iter = sRequests.find(mID); - if (iter != sRequests.end() && iter->second == this) + // The following are required in case the work was aborted + if (mCacheReadHandle != LLTextureCache::nullHandle()) { - sRequests.erase(iter); + mFetcher->mTextureCache->readComplete(mCacheReadHandle, true); + mCacheReadHandle = LLTextureCache::nullHandle(); + } + if (mCacheWriteHandle != LLTextureCache::nullHandle()) + { + mFetcher->mTextureCache->writeComplete(mCacheWriteHandle, true); + mCacheWriteHandle = LLTextureCache::nullHandle(); } - sNetworkQueue.erase(this); - unlockQueue(); - clearPackets(); } -void LLTextureFetchWorker::clearPackets() +// virtual +bool LLTextureFetchWorker::deleteOK() { - lockWorkData(); - for_each(mPackets.begin(), mPackets.end(), DeletePointer()); - mPackets.clear(); - unlockWorkData(); + bool delete_ok = true; + // Allow any pending reads or writes to complete + if (mCacheReadHandle != LLTextureCache::nullHandle()) + { + if (mFetcher->mTextureCache->readComplete(mCacheReadHandle, true)) + { + mCacheReadHandle = LLTextureCache::nullHandle(); + } + else + { + delete_ok = false; + } + } + if (mCacheWriteHandle != LLTextureCache::nullHandle()) + { + if (mFetcher->mTextureCache->writeComplete(mCacheWriteHandle)) + { + mCacheWriteHandle = LLTextureCache::nullHandle(); + } + else + { + delete_ok = false; + } + } + // Don't delete while waiting for network requests *TODO: Need LLCurl::abort() + // Don't delete while waiting on writes + if ((mState >= LLTextureFetchWorker::LOAD_FROM_HTTP_GET_URL && + mState <= LLTextureFetchWorker::LOAD_FROM_HTTP_GET_DATA) || + (mState >= LLTextureFetchWorker::WRITE_TO_CACHE && + mState <= LLTextureFetchWorker::WAIT_ON_WRITE)) + { + delete_ok = false; + } + return delete_ok; } -U32 LLTextureFetchWorker::calcWorkPriority() + +void LLTextureFetchWorker::removeFromCache() { - F32 priority_scale = (F32)LLWorkerThread::PRIORITY_LOWBITS / LLViewerImage::maxDecodePriority(); - U32 priority = (U32)(mPriority * priority_scale); - return LLWorkerThread::PRIORITY_NORMAL | priority; + if (!mInLocalCache) + { + mFetcher->mTextureCache->removeFromCache(mID); + } } -void LLTextureFetchWorker::setDesiredDiscard(S32 discard) + +////////////////////////////////////////////////////////////////////////////// + +bool LLTextureFetchWorker::processSimulatorPackets() { - if (mDesiredDiscard != discard) + if (mLastPacket >= mFirstPacket) { - mDesiredDiscard = discard; - if (!haveWork()) + S32 buffer_size = mFormattedImage->getDataSize(); + for (S32 i = mFirstPacket; i<=mLastPacket; i++) { - addWork(0, calcWorkPriority()); + buffer_size += mPackets[i]->mSize; + } + bool have_all_data = mLastPacket >= mTotalPackets-1; + llassert_always(mRequestedSize > 0); + if (buffer_size >= mRequestedSize || have_all_data) + { + /// We have enough (or all) data + if (have_all_data) + { + mHaveAllData = TRUE; + } + S32 cur_size = mFormattedImage->getDataSize(); + if (buffer_size > cur_size) + { + /// We have new data + U8* buffer = new U8[buffer_size]; + S32 offset = 0; + if (cur_size > 0 && mFirstPacket > 0) + { + memcpy(buffer, mFormattedImage->getData(), cur_size); + offset = cur_size; + } + for (S32 i=mFirstPacket; i<=mLastPacket; i++) + { + memcpy(buffer + offset, mPackets[i]->mData, mPackets[i]->mSize); + offset += mPackets[i]->mSize; + } + // NOTE: setData releases current data + mFormattedImage->setData(buffer, buffer_size); + } + mLoadedDiscard = mRequestedDiscard; + return true; } } + return false; } -void LLTextureFetchWorker::setImagePriority(F32 priority) +////////////////////////////////////////////////////////////////////////////// + +void LLTextureFetchWorker::callbackURLReceived(const LLSD& data, bool success) { - if (priority != mPriority) + LLMutexLock lock(&mWorkMutex); + if (success) { - mPriority = priority; - setPriority(calcWorkPriority()); + mURL = data.asString(); } + mLoaded = TRUE; + setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); } -void LLTextureFetchWorker::insertPacket(S32 index, U8* data, S32 size) +////////////////////////////////////////////////////////////////////////////// + +void LLTextureFetchWorker::callbackHttpGet(U8* data, S32 data_size, bool last_block) { - PacketData* packet = new PacketData(data, size); - - lockWorkData(); - if (index >= (S32)mPackets.size()) + LLMutexLock lock(&mWorkMutex); + llassert_always(mRequested); +// llinfos << "HTTP RECEIVED: " << mID.asString() << " Bytes: " << data_size << llendl; + if (mLoaded) { - mPackets.resize(index+1, (PacketData*)NULL); // initializes v to NULL pointers + llwarns << "Duplicate callback for " << mID.asString() << llendl; + return; // ignore duplicate callback } - if (mPackets[index] != NULL) + if (data_size >= 0) { - llwarns << "LLTextureFetchWorker::insertPacket called for duplicate packet: " << index << llendl; + if (data_size > 0) + { + mBuffer = new U8[data_size]; + // *TODO: set the formatted image data here + memcpy(mBuffer, data, data_size); + mBufferSize += data_size; + if (data_size < mRequestedSize || last_block == true) + { + mHaveAllData = TRUE; + } + else if (data_size > mRequestedSize) + { + // *TODO: This will happen until we fix LLCurl::getByteRange() + llinfos << "HUH?" << llendl; + mHaveAllData = TRUE; + mFormattedImage->deleteData(); + mBufferSize = data_size; + } + } + else + { + // We requested data but received none (and no error), + // so presumably we have all of it + mHaveAllData = TRUE; + } + mRequestedSize = data_size; } - mPackets[index] = packet; - while (mLastPacket+1 < (S32)mPackets.size() && mPackets[mLastPacket+1] != NULL) + else { - ++mLastPacket; + mRequestedSize = -1; // error } - unlockWorkData(); + mLoaded = TRUE; + setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); } -// Called from LLWorkerThread::processRequest() -bool LLTextureFetchWorker::doWork(S32 param) +////////////////////////////////////////////////////////////////////////////// + +void LLTextureFetchWorker::callbackCacheRead(bool success, LLImageFormatted* image, + S32 imagesize, BOOL islocal) { - switch(mState) - { - case INIT: - { - // fall through - } - case LOAD_FROM_CACHE: - { - // Load any existing data from the cache - if (mFileHandle == LLVFSThread::nullHandle()) - { - bool res = startVFSLoad(gVFS, LLAssetType::AT_TEXTURE); - if (!res) res = startVFSLoad(gStaticVFS, LLAssetType::AT_TEXTURE_TGA); - if (!res) res = startVFSLoad(gStaticVFS, LLAssetType::AT_TEXTURE); - if (!res) - { - // Didn't load from VFS - mFormattedImage = new LLImageJ2C; - mState = LOAD_FROM_SIMULATOR; - } - } - if (mFileHandle != LLVFSThread::nullHandle()) - { - if (!loadFromVFS()) - { - return false; // not done - } - if (!mLoaded) - { - llwarns << "Load from VFS failed on: " << mID << llendl; - return true; - } - bool res = mFormattedImage->setData(mBuffer, mBufferSize); - if (!res) - { - llwarns << "loadLocalImage() - setData() failed" << llendl; - mFormattedImage->deleteData(); - return true; - } - // Successfully loaded - if (mFormattedImage->getDiscardLevel() <= mRequestedDiscard) - { - // we have enough data, decode it - mState = DECODE_IMAGE; - mRequestedSize = mBufferSize; - } - else - { - // need more data - mState = LOAD_FROM_SIMULATOR; - mRequestedSize = mFormattedImage->calcDataSize(mRequestedDiscard); - } - } - return false; - } - case LOAD_FROM_SIMULATOR: - { - if (!mRequested) - { - lockQueue(); - sNetworkQueue.insert(this); - unlockQueue(); - mRequested = TRUE; - } - if (processSimulatorPackets()) - { - mState = WRITE_TO_VFS; - } - return false; - } - case WRITE_TO_VFS: - { - mState = DECODE_IMAGE; - // fall through - } - case DECODE_IMAGE: - { - startDecode(); - mState = DECODE_IMAGE_UPDATE; - // fall through - } - case DECODE_IMAGE_UPDATE: - { - if (decodeImage()) - { - mState = DONE; - } - return false; - } - case DONE: - { - // Do any cleanup here - // Destroy the formatted image, we don't need it any more (raw image is still valid) - mFormattedImage = NULL; - mIdleTimer.reset(); - return true; - } - default: - { - llerrs << "LLTextureFetchWorker::doWork() has illegal state" << llendl; - return true; - } + LLMutexLock lock(&mWorkMutex); + if (success) + { + llassert_always(imagesize > 0); + mFileSize = imagesize; + mFormattedImage = image; + mImageCodec = image->getCodec(); + mInLocalCache = islocal; + if (mFileSize != 0 && mFormattedImage->getDataSize() >= mFileSize) + { + mHaveAllData = TRUE; + } } + mLoaded = TRUE; + setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); } -// Called from MAIN thread -void LLTextureFetchWorker::startWork(S32 param) +void LLTextureFetchWorker::callbackCacheWrite(bool success) { + LLMutexLock lock(&mWorkMutex); + mWritten = TRUE; + setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); } -void LLTextureFetchWorker::endWork(S32 param, bool aborted) +////////////////////////////////////////////////////////////////////////////// + +void LLTextureFetchWorker::callbackDecoded(bool success) { +// llinfos << mID << " : DECODE COMPLETE " << llendl; + setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); } ////////////////////////////////////////////////////////////////////////////// -bool LLTextureFetchWorker::startVFSLoad(LLVFS* vfs, LLAssetType::EType asset_type) +void LLTextureFetchWorker::startDecode() { - // Start load from VFS if it's there - if (vfs->getExists(mID, asset_type)) + mRawImage = NULL; + mAuxImage = NULL; + llassert_always(mImageWorker == NULL); + llassert_always(mFormattedImage.notNull()); + S32 discard = mHaveAllData ? 0 : mLoadedDiscard; + U32 image_priority = LLWorkerThread::PRIORITY_NORMAL | mWorkPriority; +// llinfos << mID << " : DECODE STARTED : " << discard +// << " Pri: " << priority +// << " Components:" << (S32)mFormattedImage->getComponents() << llendl; + mImageWorker = new LLImageWorker(mFormattedImage, image_priority, discard, new DecodeResponder(mFetcher, mID, this)); +} + +bool LLTextureFetchWorker::decodeImage() +{ + llassert_always(mImageWorker); + bool res = true; + if (mRawImage.isNull()) { - mBufferSize = vfs->getSize(mID, asset_type); - mBuffer = new U8[mBufferSize]; - mFileHandle = LLVFSThread::sLocal->read(vfs, mID, asset_type, mBuffer, 0, mBufferSize); /* Flawfinder: ignore */ - if (mFileHandle == LLVFSThread::nullHandle()) + res = false; + if (mImageWorker->requestDecodedData(mRawImage, -1)) { - llwarns << "loadLocalImage() - vfs read failed in static VFS: " << mID << llendl; - delete mBuffer; - mBuffer = NULL; - return false; + res = true; +// llinfos << mID << " : BASE DECODE FINISHED" << llendl; } - if (asset_type == LLAssetType::AT_TEXTURE_TGA) + } + if (res && + (mRawImage.notNull() && mRawImage->getDataSize() > 0) && + (mNeedsAux && mAuxImage.isNull())) + { + res = false; + if (mImageWorker->requestDecodedAuxData(mAuxImage, 4, -1)) { - mFormattedImage = new LLImageTGA; + res = true; +// llinfos << mID << " : AUX DECODE FINISHED" << llendl; } - else if (asset_type == LLAssetType::AT_TEXTURE) + } + if (res) + { + if ((mRawImage.notNull() && mRawImage->getDataSize() > 0) && + (!mNeedsAux || (mAuxImage.notNull() && mAuxImage->getDataSize() > 0))) { - mFormattedImage = new LLImageJ2C; + mDecodedDiscard = mFormattedImage->getDiscardLevel(); +// llinfos << mID << " : DECODE FINISHED. DISCARD: " << mDecodedDiscard << llendl; } else { - llerrs << "LLTextureFetchWorker::startVFSLoad called with bad asset type: " << asset_type << llendl; + llwarns << "DECODE FAILED: " << mID << " Discard: " << (S32)mFormattedImage->getDiscardLevel() << llendl; + removeFromCache(); } - return true; + mImageWorker->scheduleDelete(); + mImageWorker = NULL; } - return false; + else + { + U32 image_priority = LLWorkerThread::PRIORITY_NORMAL | mWorkPriority; + mImageWorker->setPriority(image_priority); + //llinfos << worker->mID << " : DECODE PRIORITY : " << priority << llendl; + } + return res; } -bool LLTextureFetchWorker::loadFromVFS() +////////////////////////////////////////////////////////////////////////////// + +bool LLTextureFetchWorker::writeToCacheComplete() { - LLMemType mt1(LLMemType::MTYPE_APPFMTIMAGE); + // Complete write to cache + if (mCacheWriteHandle != LLTextureCache::nullHandle()) + { + if (!mWritten) + { + return false; + } + if (mFetcher->mTextureCache->writeComplete(mCacheWriteHandle)) + { + mCacheWriteHandle = LLTextureCache::nullHandle(); + } + else + { + return false; + } + } + return true; +} - llassert(mLoaded == FALSE); - - // Check loading status - LLVFSThread::status_t status = LLVFSThread::sLocal->getRequestStatus(mFileHandle); - if (status == LLVFSThread::STATUS_QUEUED || status == LLVFSThread::STATUS_INPROGRESS) + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +// public + +LLTextureFetch::LLTextureFetch(LLTextureCache* cache, bool threaded) + : LLWorkerThread("TextureFetch", threaded), + mDebugCount(0), + mDebugPause(0), + mTextureCache(cache), + mQueueMutex(getAPRPool()) +{ +} + +LLTextureFetch::~LLTextureFetch() +{ + // ~LLQueuedThread() called here +} + +bool LLTextureFetch::createRequest(const LLUUID& id, const LLHost& host, F32 priority, + S32 w, S32 h, S32 c, S32 discard, bool needs_aux) +{ + LLTextureFetchWorker* worker = NULL; + LLMutexLock lock(&mQueueMutex); + map_t::iterator iter = mRequestMap.find(id); + if (iter != mRequestMap.end()) { - return false; + worker = iter->second; + if (worker->mHost != host) + { + llwarns << "LLTextureFetch::createRequest " << id << " called with multiple hosts" << llendl; + removeRequest(worker, false); + worker = NULL; + } } - else if (status == LLVFSThread::STATUS_COMPLETE) + // If the requester knows the dimentions of the image, + // this will calculate how much data we need without having to parse the header + S32 desired_size; + if (w*h*c > 0) { - mLoaded = TRUE; - return true; + desired_size = LLImageJ2C::calcDataSizeJ2C(w, h, c, discard); } else { - llwarns << "loadLocalImage() - vfs read failed" << llendl; - LLVFSThread::Request* req = (LLVFSThread::Request*)LLVFSThread::sLocal->getRequest(mFileHandle); - if (req && mFormattedImage.notNull()) + desired_size = FIRST_PACKET_SIZE; + discard = MAX_DISCARD_LEVEL; + } + if (worker) + { + if (worker->wasAborted()) { - LLVFS* vfs = req->getVFS(); - LLAssetType::EType asset_type = mFormattedImage->getCodec() == IMG_CODEC_TGA ? LLAssetType::AT_TEXTURE_TGA : LLAssetType::AT_TEXTURE; - vfs->removeFile(mID, asset_type); + return false; // need to wait for previous aborted request to complete } - return true; + worker->lockWorkData(); + worker->setImagePriority(priority); + worker->setDesiredDiscard(discard, desired_size); + worker->unlockWorkData(); + } + else + { + worker = new LLTextureFetchWorker(this, id, host, priority, discard, desired_size); + mRequestMap[id] = worker; + } + worker->mActiveCount++; + worker->mNeedsAux = needs_aux; +// llinfos << "REQUESTED: " << id << " Discard: " << discard << llendl; + return true; +} + +void LLTextureFetch::deleteRequest(const LLUUID& id, bool cancel) +{ + LLMutexLock lock(&mQueueMutex); + LLTextureFetchWorker* worker = getWorker(id); + if (worker) + { + removeRequest(worker, cancel); } } +// protected -////////////////////////////////////////////////////////////////////////////// +// call lockQueue() first! +void LLTextureFetch::addToNetworkQueue(LLTextureFetchWorker* worker) +{ + if (mRequestMap.find(worker->mID) != mRequestMap.end()) + { + // only add to the queue if in the request map + // i.e. a delete has not been requested + mNetworkQueue.insert(worker->mID); + } +} -bool LLTextureFetchWorker::processSimulatorPackets() +// call lockQueue() first! +void LLTextureFetch::removeFromNetworkQueue(LLTextureFetchWorker* worker) +{ + mNetworkQueue.erase(worker->mID); +} + +// call lockQueue() first! +void LLTextureFetch::removeRequest(LLTextureFetchWorker* worker, bool cancel) +{ + mRequestMap.erase(worker->mID); + size_t erased = mNetworkQueue.erase(worker->mID); + if (cancel && erased > 0) + { + mCancelQueue[worker->mHost].insert(worker->mID); + } + worker->scheduleDelete(); +} + +// call lockQueue() first! +LLTextureFetchWorker* LLTextureFetch::getWorker(const LLUUID& id) +{ + LLTextureFetchWorker* res = NULL; + map_t::iterator iter = mRequestMap.find(id); + if (iter != mRequestMap.end()) + { + res = iter->second; + } + return res; +} + + +bool LLTextureFetch::getRequestFinished(const LLUUID& id, S32& discard_level, + LLPointer<LLImageRaw>& raw, LLPointer<LLImageRaw>& aux) { bool res = false; - lockWorkData(); - if (mLastPacket >= 0) + LLMutexLock lock(&mQueueMutex); + LLTextureFetchWorker* worker = getWorker(id); + if (worker) { - S32 data_size = 0; - for (S32 i = 0; i<=mLastPacket; i++) + if (worker->wasAborted()) { - data_size += mPackets[i]->mSize; + res = true; } - if (data_size >= mRequestedSize || mLastPacket == mTotalPackets) + else if (!worker->haveWork()) { - /// We have enough (or all) data, copy it into mBuffer - if (mBufferSize < data_size) + // Should only happen if we set mDebugPause... + if (!mDebugPause) { - delete mBuffer; - mBuffer = new U8[data_size]; - mBufferSize = data_size; + worker->addWork(0, LLWorkerThread::PRIORITY_HIGH | worker->mWorkPriority); } - S32 offset = 0; - for (S32 i = 0; i<=mLastPacket; i++) + } + else if (worker->checkWork()) + { + discard_level = worker->mDecodedDiscard; + raw = worker->mRawImage; worker->mRawImage = NULL; + aux = worker->mAuxImage; worker->mAuxImage = NULL; + res = true; + } + else + { + worker->lockWorkData(); + if ((worker->mDecodedDiscard >= 0) && + (worker->mDecodedDiscard < discard_level || discard_level < 0) && + (worker->mState >= LLTextureFetchWorker::WAIT_ON_WRITE)) { - if (mPackets[i]->mData != NULL) - { - memcpy(mBuffer + offset, mPackets[i]->mData, mPackets[i]->mSize); /* Flawfinder: ignore */ - offset += mPackets[i]->mSize; - } + // Not finished, but data is ready + discard_level = worker->mDecodedDiscard; + if (worker->mRawImage) raw = worker->mRawImage; + if (worker->mAuxImage) aux = worker->mAuxImage; } - res = true; + worker->unlockWorkData(); } } - unlockWorkData(); + else + { + res = true; + } + return res; +} + +bool LLTextureFetch::updateRequestPriority(const LLUUID& id, F32 priority) +{ + bool res = false; + LLMutexLock lock(&mQueueMutex); + LLTextureFetchWorker* worker = getWorker(id); + if (worker) + { + worker->lockWorkData(); + worker->setImagePriority(priority); + worker->unlockWorkData(); + res = true; + } return res; } ////////////////////////////////////////////////////////////////////////////// -void LLTextureFetchWorker::startDecode() +//virtual +S32 LLTextureFetch::update(U32 max_time_ms) { - mRawImage = NULL; - mAuxImage = NULL; + S32 res; + res = LLWorkerThread::update(max_time_ms); + + const F32 REQUEST_TIME = 1.f; + + // Periodically, gather the list of textures that need data from the network + // And send the requests out to the simulators + if (mNetworkTimer.getElapsedTimeF32() >= REQUEST_TIME) + { + mNetworkTimer.reset(); + sendRequestListToSimulators(); + } + +#if 0 // Currently this logic is handled in LLViewer + { + LLMutexLock lock(&mQueueMutex); + const F32 MIN_IDLE_TIME = 1.f * 60.f; // 1 minute + const F32 MAX_IDLE_TIME = 5.f * 60.f; // 5 minutes + const S32 MIN_IDLE_COUNT = 16; // always keep last 16 idle requests + const F32 MAX_IDLE_COUNT = 1024; // max number of idle requests + // Remove any old requests (releasing their raw data) + typedef std::pair<F32, LLTextureFetchWorker*> idle_pair; + typedef std::set<idle_pair, compare_pair_greater<F32,LLTextureFetchWorker*> > idle_set; + idle_set remove_set; + for (map_t::iterator iter = mRequestMap.begin(); iter != mRequestMap.end(); ++iter) + { + LLTextureFetchWorker* worker = iter->second; + if (worker->mActiveCount > 0) + continue; + if (worker->haveWork()) + continue; + F32 idletime = worker->mIdleTimer.getElapsedTimeF32(); + if (idletime < MIN_IDLE_TIME) + continue; + remove_set.insert(std::make_pair(idletime, worker)); + } + S32 num_left = remove_set.size(); + for (idle_set::iterator iter = remove_set.begin(); iter != remove_set.end(); ++iter) + { + if (num_left <= MIN_IDLE_COUNT) + break; + if (iter->first < MAX_IDLE_TIME && + num_left < MAX_IDLE_COUNT) + break; + num_left--; + } + } +#endif + + return res; } -bool LLTextureFetchWorker::decodeImage() +////////////////////////////////////////////////////////////////////////////// + +void LLTextureFetch::sendRequestListToSimulators() { - const F32 MAX_DECODE_TIME = .001f; // 1 ms - if (mRawImage->getDataSize() == 0) + const S32 IMAGES_PER_REQUEST = 50; + const F32 LAZY_FLUSH_TIMEOUT = 15.f; // 10.0f // temp + const F32 MIN_REQUEST_TIME = 1.0f; + const F32 MIN_DELTA_PRIORITY = 1000.f; + + LLMutexLock lock(&mQueueMutex); + + // Send requests + typedef std::set<LLTextureFetchWorker*,LLTextureFetchWorker::Compare> request_list_t; + typedef std::map< LLHost, request_list_t > work_request_map_t; + work_request_map_t requests; + for (queue_t::iterator iter = mNetworkQueue.begin(); iter != mNetworkQueue.end(); ++iter) { - if (!mFormattedImage->requestDecodedData(mRawImage, -1, MAX_DECODE_TIME)) + LLTextureFetchWorker* req = getWorker(*iter); + if (req->mID == mDebugID) { - return false; + mDebugCount++; // for setting breakpoints + } + if (req->mTotalPackets > 0 && req->mLastPacket >= req->mTotalPackets-1) + { + // We have all the packets... make sure this is high priority + req->setPriority(LLWorkerThread::PRIORITY_HIGH | req->mWorkPriority); + continue; + } + F32 elapsed = req->mRequestedTimer.getElapsedTimeF32(); + F32 delta_priority = llabs(req->mRequestedPriority - req->mImagePriority); + if ((req->mSimRequestedDiscard != req->mDesiredDiscard) || + (delta_priority > MIN_DELTA_PRIORITY && elapsed >= MIN_REQUEST_TIME) || + (elapsed >= LAZY_FLUSH_TIMEOUT)) + { + requests[req->mHost].insert(req); } - mFormattedImage->releaseDecodedData(); // so that we have the only ref to the raw image } - if (mNeedsAux && mAuxImage->getDataSize() == 0) + for (work_request_map_t::iterator iter1 = requests.begin(); + iter1 != requests.end(); ++iter1) { - if (!mFormattedImage->requestDecodedAuxData(mAuxImage, 4, -1, MAX_DECODE_TIME )) + LLHost host = iter1->first; + // invalid host = use agent host + if (host == LLHost::invalid) { - return false; + host = gAgent.getRegionHost(); + } + + S32 request_count = 0; + for (request_list_t::iterator iter2 = iter1->second.begin(); + iter2 != iter1->second.end(); ++iter2) + { + LLTextureFetchWorker* req = *iter2; + if (0 == request_count) + { + gMessageSystem->newMessageFast(_PREHASH_RequestImage); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + } + S32 packet = req->mLastPacket + 1; + gMessageSystem->nextBlockFast(_PREHASH_RequestImage); + gMessageSystem->addUUIDFast(_PREHASH_Image, req->mID); + gMessageSystem->addS8Fast(_PREHASH_DiscardLevel, (S8)req->mSimRequestedDiscard); + gMessageSystem->addF32Fast(_PREHASH_DownloadPriority, req->mImagePriority); + gMessageSystem->addU32Fast(_PREHASH_Packet, packet); + U8 type = host.isOk() ? LLImageBase::TYPE_AVATAR_BAKE : LLImageBase::TYPE_NORMAL; + gMessageSystem->addU8Fast(_PREHASH_Type, type); +// llinfos << "IMAGE REQUEST: " << req->mID << " Discard: " << req->mDesiredDiscard +// << " Packet: " << packet << " Priority: " << req->mImagePriority << llendl; + + req->lockWorkData(); + req->mSimRequestedDiscard = req->mDesiredDiscard; + req->mRequestedPriority = req->mImagePriority; + req->mRequestedTimer.reset(); + req->unlockWorkData(); + request_count++; + if (request_count >= IMAGES_PER_REQUEST) + { +// llinfos << "REQUESTING " << request_count << " IMAGES FROM HOST: " << host.getIPString() << llendl; + gMessageSystem->sendSemiReliable(host, NULL, NULL); + request_count = 0; + break; // only send the top requests + } + } + if (request_count > 0 && request_count < IMAGES_PER_REQUEST) + { +// llinfos << "REQUESTING " << request_count << " IMAGES FROM HOST: " << host.getIPString() << llendl; + gMessageSystem->sendSemiReliable(host, NULL, NULL); } - mFormattedImage->releaseDecodedData(); // so that we have the only ref to the raw image } - mDecodedDiscard = mFormattedImage->getDiscardLevel(); - return true; + + // Send cancelations + if (!mCancelQueue.empty()) + { + for (cancel_queue_t::iterator iter1 = mCancelQueue.begin(); + iter1 != mCancelQueue.end(); ++iter1) + { + LLHost host = iter1->first; + // invalid host = use agent host + if (host == LLHost::invalid) + { + host = gAgent.getRegionHost(); + } + S32 request_count = 0; + for (queue_t::iterator iter2 = iter1->second.begin(); + iter2 != iter1->second.end(); ++iter2) + { + if (0 == request_count) + { + gMessageSystem->newMessageFast(_PREHASH_RequestImage); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + } + gMessageSystem->nextBlockFast(_PREHASH_RequestImage); + gMessageSystem->addUUIDFast(_PREHASH_Image, *iter2); + gMessageSystem->addS8Fast(_PREHASH_DiscardLevel, -1); + gMessageSystem->addF32Fast(_PREHASH_DownloadPriority, 0); + gMessageSystem->addU32Fast(_PREHASH_Packet, 0); + gMessageSystem->addU8Fast(_PREHASH_Type, 0); +// llinfos << "CANCELING IMAGE REQUEST: " << (*iter2) << llendl; + + request_count++; + if (request_count >= IMAGES_PER_REQUEST) + { + gMessageSystem->sendSemiReliable(host, NULL, NULL); + request_count = 0; + } + } + if (request_count > 0 && request_count < IMAGES_PER_REQUEST) + { + gMessageSystem->sendSemiReliable(host, NULL, NULL); + } + } + mCancelQueue.clear(); + } } ////////////////////////////////////////////////////////////////////////////// -#if 0 -// static -void LLTextureFetchWorker::receiveImageHeader(LLMessageSystem *msg, void **user_data) +bool LLTextureFetchWorker::insertPacket(S32 index, U8* data, S32 size) { - LLFastTimer t(LLFastTimer::FTM_PROCESS_IMAGES); + mRequestedTimer.reset(); + if (index >= mTotalPackets) + { + llwarns << "Received Image Packet " << index << " > max: " << mTotalPackets << " Skipping. " << llendl; + return false; + } + if (index > 0 && index < mTotalPackets-1 && size != MAX_IMG_PACKET_SIZE) + { + llwarns << "Received bad sized packet: " << index << ", " << size << " != " << MAX_IMG_PACKET_SIZE << " Skipping. " << llendl; + return false; + } - // Receive image header, copy into image object and decompresses - // if this is a one-packet image. + if (index >= (S32)mPackets.size()) + { + mPackets.resize(index+1, (PacketData*)NULL); // initializes v to NULL pointers + } + else if (mPackets[index] != NULL) + { +// llwarns << "LLTextureFetchWorker::insertPacket called for duplicate packet: " << index << llendl; + return false; + } - gImageList.sTextureBits += msg->getReceiveBytes(); - gImageList.sTexturePackets++; + mPackets[index] = new PacketData(data, size); + while (mLastPacket+1 < (S32)mPackets.size() && mPackets[mLastPacket+1] != NULL) + { + ++mLastPacket; + } + return true; +} - LLUUID id; - msg->getUUIDFast(_PREHASH_ImageID, _PREHASH_ID, id); -// LLString ip_string(u32_to_ip_string(msg->getSenderIP())); - - LLTextureFetchWorker* worker = getActiveWorker(id); +bool LLTextureFetch::receiveImageHeader(const LLUUID& id, U8 codec, U16 packets, U32 totalbytes, + U16 data_size, U8* data) +{ + LLMutexLock lock(&mQueueMutex); + LLTextureFetchWorker* worker = getWorker(id); if (!worker) { - llwarns << "receiveImageHeader for non active worker: " << id << llendl; - return; +// llwarns << "receiveImageHeader for non active worker: " << id << llendl; + return false; } - worker->mRequestedTimer.reset(); - // check to see if we've gotten this packet before if (worker->mLastPacket != -1) { - llwarns << "Img: " << id << ":" << " Duplicate Image Header" << llendl; - return; +// llwarns << "Img: " << id << ":" << " Duplicate Image Header" << llendl; + return false; } - // Copy header data into image object worker->lockWorkData(); - msg->getU8Fast(_PREHASH_ImageID, _PREHASH_Codec, image->mDataCodec); - msg->getU16Fast(_PREHASH_ImageID, _PREHASH_Packets, image->mTotalPackets); - msg->getU32Fast(_PREHASH_ImageID, _PREHASH_Size, image->mTotalBytes); - if (0 == image->mTotalPackets) + + // Copy header data into image object + worker->mImageCodec = codec; + worker->mTotalPackets = packets; + worker->mFileSize = (S32)totalbytes; + llassert_always(totalbytes > 0); + bool res = false; + if (data_size) { - llwarns << "Img: " << id << ":" << " Number of packets is 0" << llendl; + llassert(data_size == FIRST_PACKET_SIZE || data_size == worker->mFileSize); + res = worker->insertPacket(0, data, data_size); + worker->setPriority(LLWorkerThread::PRIORITY_HIGH | worker->mWorkPriority); } worker->unlockWorkData(); + return res; +} - U16 data_size = msg->getSizeFast(_PREHASH_ImageData, _PREHASH_Data); +bool LLTextureFetch::receiveImagePacket(const LLUUID& id, U16 packet_num, U16 data_size, U8* data) +{ + LLMutexLock lock(&mQueueMutex); + LLTextureFetchWorker* worker = getWorker(id); + if (!worker) + { +// llwarns << "receiveImagePacket " << packet_num << " for non active worker: " << id << llendl; + return false; + } + if (worker->mLastPacket == -1) + { +// llwarns << "Img: " << id << ":" << " Image Packet " << packet_num << " received before header" << llendl; + return false; + } + + bool res = false; if (data_size) { - U8 *data = new U8[data_size]; - msg->getBinaryDataFast(_PREHASH_ImageData, _PREHASH_Data, data, data_size); - worker->insertPacket(0, data, data_size) + worker->lockWorkData(); + res = worker->insertPacket(packet_num, data, data_size); + worker->setPriority(LLWorkerThread::PRIORITY_HIGH | worker->mWorkPriority); + worker->unlockWorkData(); } + return res; } -/////////////////////////////////////////////////////////////////////////////// -// static -void LLTextureFetchWorker::receiveImagePacket(LLMessageSystem *msg, void **user_data) +////////////////////////////////////////////////////////////////////////////// + +S32 LLTextureFetch::getFetchState(const LLUUID& id, F32& data_progress_p, F32& requested_priority_p, + U32& fetch_priority_p, F32& fetch_dtime_p, F32& request_dtime_p) { - LLMemType mt1(LLMemType::MTYPE_APPFMTIMAGE); - LLFastTimer t(LLFastTimer::FTM_PROCESS_IMAGES); + S32 state = LLTextureFetchWorker::INVALID; + F32 data_progress = 0.0f; + F32 requested_priority = 0.0f; + F32 fetch_dtime = 999999.f; + F32 request_dtime = 999999.f; + U32 fetch_priority = 0; - gImageList.sTextureBits += msg->getReceiveBytes(); - gImageList.sTexturePackets++; - - LLUUID id; - msg->getUUIDFast(_PREHASH_ImageID, _PREHASH_ID, id); -// LLString ip_string(u32_to_ip_string(msg->getSenderIP())); - - U16 packet_num; - msg->getU16Fast(_PREHASH_ImageID, _PREHASH_Packet, packet_num); - - LLTextureFetchWorker* worker = getActiveWorker(id); - if (!worker) + LLMutexLock lock(&mQueueMutex); + LLTextureFetchWorker* worker = getWorker(id); + if (worker && worker->haveWork()) { - llwarns << "receiveImageHeader for non active worker: " << id << llendl; - return; + worker->lockWorkData(); + state = worker->mState; + fetch_dtime = worker->mFetchTimer.getElapsedTimeF32(); + request_dtime = worker->mRequestedTimer.getElapsedTimeF32(); + if (worker->mFileSize > 0) + { + if (state == LLTextureFetchWorker::LOAD_FROM_SIMULATOR) + { + S32 data_size = FIRST_PACKET_SIZE + (worker->mLastPacket-1) * MAX_IMG_PACKET_SIZE; + data_size = llmax(data_size, 0); + data_progress = (F32)data_size / (F32)worker->mFileSize; + } + else if (worker->mFormattedImage.notNull()) + { + data_progress = (F32)worker->mFormattedImage->getDataSize() / (F32)worker->mFileSize; + } + } + if (state >= LLTextureFetchWorker::LOAD_FROM_NETWORK && state <= LLTextureFetchWorker::LOAD_FROM_HTTP_GET_DATA) + { + requested_priority = worker->mRequestedPriority; + } + else + { + requested_priority = worker->mImagePriority; + } + fetch_priority = worker->getPriority(); + worker->unlockWorkData(); } - worker->mRequestedTimer.reset(); + data_progress_p = data_progress; + requested_priority_p = requested_priority; + fetch_priority_p = fetch_priority; + fetch_dtime_p = fetch_dtime; + request_dtime_p = request_dtime; + return state; +} - U16 data_size = msg->getSizeFast(_PREHASH_ImageData, _PREHASH_Data); - if (data_size) +void LLTextureFetch::dump() +{ + llinfos << "LLTextureFetch REQUESTS:" << llendl; + for (request_queue_t::iterator iter = mRequestQueue.begin(); + iter != mRequestQueue.end(); ++iter) { - U8 *data = new U8[data_size]; - msg->getBinaryDataFast(_PREHASH_ImageData, _PREHASH_Data, data, data_size); - worker->insertPacket(0, data, data_size) + LLQueuedThread::QueuedRequest* qreq = *iter; + LLWorkerThread::WorkRequest* wreq = (LLWorkerThread::WorkRequest*)qreq; + LLTextureFetchWorker* worker = (LLTextureFetchWorker*)wreq->getWorkerClass(); + llinfos << " ID: " << worker->mID + << " PRI: " << llformat("0x%08x",wreq->getPriority()) + << " STATE: " << worker->sStateDescs[worker->mState] + << llendl; } } -#endif - ////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////// diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h index 9d841ae23a..b3510d9e82 100644 --- a/indra/newview/lltexturefetch.h +++ b/indra/newview/lltexturefetch.h @@ -9,20 +9,77 @@ #ifndef LL_LLTEXTUREFETCH_H #define LL_LLTEXTUREFETCH_H +#include "lldir.h" +#include "llimage.h" +#include "lluuid.h" #include "llworkerthread.h" class LLViewerImage; +class LLTextureFetchWorker; +class LLTextureCache; +class LLHost; // Interface class -class LLTextureFetch +class LLTextureFetch : public LLWorkerThread { + friend class LLTextureFetchWorker; + public: - static void initClass(); - static void updateClass(); - static void cleanupClass(); + LLTextureFetch(LLTextureCache* cache, bool threaded); + ~LLTextureFetch(); - static LLWorkerClass::handle_t addRequest(LLImageFormatted* image, S32 discard); - static bool getRequestFinished(LLWorkerClass::handle_t handle); + /*virtual*/ S32 update(U32 max_time_ms); + + bool createRequest(const LLUUID& id, const LLHost& host, F32 priority, + S32 w, S32 h, S32 c, S32 discard, bool needs_aux); + void deleteRequest(const LLUUID& id, bool cancel); + bool getRequestFinished(const LLUUID& id, S32& discard_level, + LLPointer<LLImageRaw>& raw, LLPointer<LLImageRaw>& aux); + bool updateRequestPriority(const LLUUID& id, F32 priority); + + bool receiveImageHeader(const LLUUID& id, U8 codec, U16 packets, U32 totalbytes, U16 data_size, U8* data); + bool receiveImagePacket(const LLUUID& id, U16 packet_num, U16 data_size, U8* data); + + // Debug + S32 getFetchState(const LLUUID& id, F32& decode_progress_p, F32& requested_priority_p, + U32& fetch_priority_p, F32& fetch_dtime_p, F32& request_dtime_p); + void dump(); + S32 getNumRequests() { return mRequestMap.size(); } + + // Public for access by callbacks + void lockQueue() { mQueueMutex.lock(); } + void unlockQueue() { mQueueMutex.unlock(); } + LLTextureFetchWorker* getWorker(const LLUUID& id); + +protected: + void addToNetworkQueue(LLTextureFetchWorker* worker); + void removeFromNetworkQueue(LLTextureFetchWorker* worker); + void removeRequest(LLTextureFetchWorker* worker, bool cancel); + +private: + void sendRequestListToSimulators(); + +public: + LLUUID mDebugID; + S32 mDebugCount; + BOOL mDebugPause; + +private: + LLMutex mQueueMutex; + + LLTextureCache* mTextureCache; + + // Map of all requests by UUID + typedef std::map<LLUUID,LLTextureFetchWorker*> map_t; + map_t mRequestMap; + + // Set of requests that require network data + typedef std::set<LLUUID> queue_t; + queue_t mNetworkQueue; + typedef std::map<LLHost,std::set<LLUUID> > cancel_queue_t; + cancel_queue_t mCancelQueue; + + LLFrameTimer mNetworkTimer; }; #endif LL_LLTEXTUREFETCH_H diff --git a/indra/newview/lltextureview.cpp b/indra/newview/lltextureview.cpp index d115cf1158..f051236fba 100644 --- a/indra/newview/lltextureview.cpp +++ b/indra/newview/lltextureview.cpp @@ -14,46 +14,510 @@ #include "llrect.h" #include "llerror.h" - -#include "viewer.h" +#include "lllfsthread.h" #include "llui.h" +#include "llimageworker.h" -#include "llviewerimagelist.h" +#include "llhoverview.h" #include "llselectmgr.h" +#include "lltexlayer.h" +#include "lltexturecache.h" +#include "lltexturefetch.h" +#include "lltexturetable.h" #include "llviewerobject.h" #include "llviewerimage.h" -#include "llhoverview.h" +#include "llviewerimagelist.h" +#include "viewer.h" + +extern F32 texmem_lower_bound_scale; LLTextureView *gTextureView = NULL; //static std::set<LLViewerImage*> LLTextureView::sDebugImages; +//////////////////////////////////////////////////////////////////////////// + +static LLString title_string1a("Tex UUID Area DDis(Req) DecodePri(Fetch) [download] pk/max"); +static LLString title_string1b("Tex UUID Area DDis(Req) Fetch(DecodePri) [download] pk/max"); +static LLString title_string2("State"); +static LLString title_string3("Pkt Bnd"); +static LLString title_string4(" W x H (Dis) Mem"); + +static S32 title_x1 = 0; +static S32 title_x2 = 440; +static S32 title_x3 = title_x2 + 40; +static S32 title_x4 = title_x3 + 50; +static S32 texture_bar_height = 8; + +//////////////////////////////////////////////////////////////////////////// + +class LLTextureBar : public LLView +{ +public: + LLPointer<LLViewerImage> mImagep; + S32 mHilite; + +public: + LLTextureBar(const std::string& name, const LLRect& r, LLTextureView* texview) + : LLView(name, r, FALSE), + mHilite(0), + mTextureView(texview) + { + } + + virtual EWidgetType getWidgetType() const { return WIDGET_TYPE_TEXTURE_BAR; } + virtual LLString getWidgetTag() const { return LL_TEXTURE_BAR_TAG; } + + virtual void draw(); + virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); + virtual LLRect getRequiredRect(); // Return the height of this object, given the set options. + // Used for sorting -struct SortTextureBars + struct sort + { + bool operator()(const LLView* i1, const LLView* i2) + { + LLTextureBar* bar1p = (LLTextureBar*)i1; + LLTextureBar* bar2p = (LLTextureBar*)i2; + LLViewerImage *i1p = bar1p->mImagep; + LLViewerImage *i2p = bar2p->mImagep; + F32 pri1 = i1p->getDecodePriority(); // i1p->mRequestedDownloadPriority + F32 pri2 = i2p->getDecodePriority(); // i2p->mRequestedDownloadPriority + if (pri1 > pri2) + return true; + else if (pri2 > pri1) + return false; + else + return i1p->getID() < i2p->getID(); + } + }; + + struct sort_fetch + { + bool operator()(const LLView* i1, const LLView* i2) + { + LLTextureBar* bar1p = (LLTextureBar*)i1; + LLTextureBar* bar2p = (LLTextureBar*)i2; + LLViewerImage *i1p = bar1p->mImagep; + LLViewerImage *i2p = bar2p->mImagep; + U32 pri1 = i1p->mFetchPriority; + U32 pri2 = i2p->mFetchPriority; + if (pri1 > pri2) + return true; + else if (pri2 > pri1) + return false; + else + return i1p->getID() < i2p->getID(); + } + }; +private: + LLTextureView* mTextureView; +}; + +void LLTextureBar::draw() { - bool operator()(const LLView* i1, const LLView* i2) - { - LLTextureBar* bar1p = (LLTextureBar*)i1; - LLTextureBar* bar2p = (LLTextureBar*)i2; - LLViewerImage *i1p = bar1p->mImagep; - LLViewerImage *i2p = bar2p->mImagep; - F32 pri1 = i1p->getDecodePriority(); // i1p->mRequestedDownloadPriority - F32 pri2 = i2p->getDecodePriority(); // i2p->mRequestedDownloadPriority - if (pri1 > pri2) - return true; - else if (pri2 > pri1) - return false; + if (!mImagep) + { + return; + } + + LLColor4 color; + if (mImagep->getID() == gTextureFetch->mDebugID) + { + color = LLColor4::cyan2; + } + else if (mHilite) + { + S32 idx = llclamp(mHilite,1,4); + if (idx==1) color = LLColor4::yellow; + if (idx==2) color = LLColor4::cyan; + if (idx==3) color = LLColor4::magenta; + if (idx==4) color = LLColor4::blue; + } + else if (mImagep->getBoostLevel()) + { + color = LLColor4::magenta; + } + else if (mImagep->mDontDiscard) + { + color = LLColor4::pink2; + } + else if (!mImagep->getUseMipMaps()) + { + color = LLColor4::green4; + } + else if (mImagep->getDecodePriority() == 0.0f) + { + color = LLColor4::grey; color[VALPHA] = .7f; + } + else + { + color = LLColor4::white; color[VALPHA] = .7f; + } + + // We need to draw: + // The texture UUID or name + // The progress bar for the texture, highlighted if it's being download + // Various numerical stats. + char tex_str[256]; + S32 left, right; + S32 top = 0; + S32 bottom = top + 6; + LLColor4 clr; + + LLGLSUIDefault gls_ui; + + // Get the name or UUID of the image. + gTextureTable.getName(mImagep->mID); + + // Name, pixel_area, requested pixel area, decode priority + char uuid_str[255]; + mImagep->mID.toString(uuid_str); + uuid_str[8] = 0; + if (mTextureView->mOrderFetch) + { + sprintf(tex_str, "%s %7.0f %d(%d) 0x%08x(%8.0f)", + uuid_str, + mImagep->mMaxVirtualSize, + mImagep->mDesiredDiscardLevel, + mImagep->mRequestedDiscardLevel, + mImagep->mFetchPriority, + mImagep->getDecodePriority()); + } + else + { + sprintf(tex_str, "%s %7.0f %d(%d) %8.0f(0x%08x)", + uuid_str, + mImagep->mMaxVirtualSize, + mImagep->mDesiredDiscardLevel, + mImagep->mRequestedDiscardLevel, + mImagep->getDecodePriority(), + mImagep->mFetchPriority); + } + + LLFontGL::sMonospace->renderUTF8(tex_str, 0, title_x1, mRect.getHeight(), + color, LLFontGL::LEFT, LLFontGL::TOP); + + // State + // Hack: mirrored from lltexturefetch.cpp + struct { const char* desc; LLColor4 color; } fetch_state_desc[] = { + { "---", LLColor4::red }, // INVALID + { "INI", LLColor4::white }, // INIT + { "DSK", LLColor4::cyan }, // LOAD_FROM_TEXTURE_CACHE + { "DSK", LLColor4::blue }, // CACHE_POST + { "NET", LLColor4::green }, // LOAD_FROM_NETWORK + { "SIM", LLColor4::green }, // LOAD_FROM_SIMULATOR + { "URL", LLColor4::green2 },// LOAD_FROM_HTTP_GET_URL + { "HTP", LLColor4::green }, // LOAD_FROM_HTTP_GET_DATA + { "DEC", LLColor4::yellow },// DECODE_IMAGE + { "DEC", LLColor4::yellow },// DECODE_IMAGE_UPDATE + { "WRT", LLColor4::purple },// WRITE_TO_CACHE + { "WRT", LLColor4::orange },// WAIT_ON_WRITE + { "END", LLColor4::red }, // DONE +#define LAST_STATE 12 + { "CRE", LLColor4::magenta }, // LAST_STATE+1 + { "FUL", LLColor4::green }, // LAST_STATE+2 + { "BAD", LLColor4::red }, // LAST_STATE+3 + { "MIS", LLColor4::red }, // LAST_STATE+4 + { "---", LLColor4::white }, // LAST_STATE+5 + }; + const S32 fetch_state_desc_size = (S32)(sizeof(fetch_state_desc)/sizeof(fetch_state_desc[0])); + S32 state = + mImagep->mNeedsCreateTexture ? LAST_STATE+1 : + mImagep->mFullyLoaded ? LAST_STATE+2 : + mImagep->mMinDiscardLevel > 0 ? LAST_STATE+3 : + mImagep->mIsMissingAsset ? LAST_STATE+4 : + !mImagep->mIsFetching ? LAST_STATE+5 : + mImagep->mFetchState; + state = llclamp(state,0,fetch_state_desc_size-1); + + LLFontGL::sMonospace->renderUTF8(fetch_state_desc[state].desc, 0, title_x2, mRect.getHeight(), + fetch_state_desc[state].color, + LLFontGL::LEFT, LLFontGL::TOP); + LLGLSNoTexture gls_no_texture; + + // Draw the progress bar. + S32 bar_width = 100; + S32 bar_left = 280; + left = bar_left; + right = left + bar_width; + + glColor4f(0.f, 0.f, 0.f, 0.75f); + gl_rect_2d(left, top, right, bottom); + + F32 data_progress = mImagep->mDownloadProgress; + + if (data_progress > 0.0f) + { + // Downloaded bytes + right = left + llfloor(data_progress * (F32)bar_width); + if (right > left) + { + glColor4f(0.f, 0.f, 1.f, 0.75f); + gl_rect_2d(left, top, right, bottom); + } + } + + S32 pip_width = 6; + S32 pip_space = 14; + S32 pip_x = title_x3 + pip_space/2; + + // Draw the packet pip + F32 last_event = mImagep->mLastPacketTimer.getElapsedTimeF32(); + if (last_event < 1.f) + { + clr = LLColor4::white; + } + else + { + last_event = mImagep->mRequestDeltaTime; + if (last_event < 1.f) + { + clr = LLColor4::green; + } else - return i1p->getID() < i2p->getID(); + { + last_event = mImagep->mFetchDeltaTime; + if (last_event < 1.f) + { + clr = LLColor4::yellow; + } + } + } + if (last_event < 1.f) + { + clr.setAlpha(1.f - last_event); + glColor4fv(clr.mV); + gl_rect_2d(pip_x, top, pip_x + pip_width, bottom); + } + pip_x += pip_width + pip_space; + + // we don't want to show bind/resident pips for textures using the default texture + if (mImagep->getHasGLTexture()) + { + // Draw the bound pip + last_event = mImagep->sLastFrameTime - mImagep->mLastBindTime; + if (last_event < 1.f) + { + clr = mImagep->getMissed() ? LLColor4::red : LLColor4::magenta1; + clr.setAlpha(1.f - last_event); + glColor4fv(clr.mV); + gl_rect_2d(pip_x, top, pip_x + pip_width, bottom); + } + } + pip_x += pip_width + pip_space; + + + { + LLGLSUIDefault gls_ui; + // draw the packet data +// { +// LLString num_str = llformat("%3d/%3d", mImagep->mLastPacket+1, mImagep->mPackets); +// LLFontGL::sMonospace->renderUTF8(num_str, 0, bar_left + 100, mRect.getHeight(), color, +// LLFontGL::LEFT, LLFontGL::TOP); +// } + + // draw the image size at the end + { + LLString num_str = llformat("%3dx%3d (%d) %7d", mImagep->getWidth(), mImagep->getHeight(), + mImagep->getDiscardLevel(), mImagep->mTextureMemory); + LLFontGL::sMonospace->renderUTF8(num_str, 0, title_x4, mRect.getHeight(), color, + LLFontGL::LEFT, LLFontGL::TOP); + } + } + +} + +BOOL LLTextureBar::handleMouseDown(S32 x, S32 y, MASK mask) +{ + if (mask & MASK_ALT) + { + gTextureFetch->mDebugID = mImagep->getID(); + return TRUE; + } + return LLView::handleMouseDown(x,y,mask); +} + +LLRect LLTextureBar::getRequiredRect() +{ + LLRect rect; + + rect.mTop = texture_bar_height; + + return rect; +} + +//////////////////////////////////////////////////////////////////////////// + +class LLGLTexMemBar : public LLView +{ +public: + LLGLTexMemBar(const std::string& name, LLTextureView* texview) + : LLView(name, FALSE), + mTextureView(texview) + { + S32 line_height = (S32)(LLFontGL::sMonospace->getLineHeight() + .5f); + setRect(LLRect(0,0,100,line_height * 4)); + updateRect(); } + + virtual EWidgetType getWidgetType() const { return WIDGET_TYPE_TEX_MEM_BAR; }; + virtual LLString getWidgetTag() const { return LL_GL_TEX_MEM_BAR_TAG; }; + + virtual void draw(); + virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); + virtual LLRect getRequiredRect(); // Return the height of this object, given the set options. + +private: + LLTextureView* mTextureView; }; +void LLGLTexMemBar::draw() +{ + S32 bound_mem = LLViewerImage::sBoundTextureMemory; + S32 max_bound_mem = LLViewerImage::sMaxBoundTextureMem; + S32 total_mem = LLViewerImage::sTotalTextureMemory; + S32 max_total_mem = LLViewerImage::sMaxTotalTextureMem; + F32 discard_bias = LLViewerImage::sDesiredDiscardBias; + S32 line_height = (S32)(LLFontGL::sMonospace->getLineHeight() + .5f); + + //---------------------------------------------------------------------------- + LLGLSUIDefault gls_ui; + F32 text_color[] = {1.f, 1.f, 1.f, 0.75f}; + + std::string text; + text = llformat("GL Tot: %d/%d MB Bound: %d/%d MB Discard Bias: %.2f", + total_mem/(1024*1024), + max_total_mem/(1024*1024), + bound_mem/(1024*1024), + max_bound_mem/(1024*1024), + discard_bias); + + LLFontGL::sMonospace->renderUTF8(text, 0, 0, line_height*3, + text_color, LLFontGL::LEFT, LLFontGL::TOP); + + //---------------------------------------------------------------------------- + S32 bar_left = 380; + S32 bar_width = 200; + S32 top = line_height*3 - 2; + S32 bottom = top - 6; + S32 left = bar_left; + S32 right = left + bar_width; + + F32 bar_scale = (F32)bar_width / (max_bound_mem * 1.5f); + + LLGLSNoTexture gls_no_texture; + + glColor4f(0.5f, 0.5f, 0.5f, 0.75f); + gl_rect_2d(left, top, right, bottom); + + + left = bar_left; + right = left + llfloor(bound_mem * bar_scale); + if (bound_mem < llfloor(max_bound_mem * texmem_lower_bound_scale)) + { + glColor4f(0.f, 1.f, 0.f, 0.75f); + } + else if (bound_mem < max_bound_mem) + { + glColor4f(1.f, 1.f, 0.f, 0.75f); + } + else + { + glColor4f(1.f, 0.f, 0.f, 0.75f); + } + gl_rect_2d(left, top, right, bottom); + + bar_scale = (F32)bar_width / (max_total_mem * 1.5f); + + top = bottom - 2; + bottom = top - 6; + left = bar_left; + right = left + llfloor(total_mem * bar_scale); + if (total_mem < llfloor(max_total_mem * texmem_lower_bound_scale)) + { + glColor4f(0.f, 1.f, 0.f, 0.75f); + } + else if (total_mem < max_total_mem) + { + glColor4f(1.f, 1.f, 0.f, 0.75f); + } + else + { + glColor4f(1.f, 0.f, 0.f, 0.75f); + } + gl_rect_2d(left, top, right, bottom); + + //---------------------------------------------------------------------------- + + LLGLEnable tex(GL_TEXTURE_2D); + + text = llformat("Textures: Count: %d Fetch: %d(%d) Cache R/W: %d/%d LFS:%d IW:%d(%d) RAW:%d", + gImageList.getNumImages(), + gTextureFetch->getNumRequests(), gTextureFetch->getNumDeletes(), + gTextureCache->getNumReads(), gTextureCache->getNumWrites(), + LLLFSThread::sLocal->getPending(), + LLImageWorker::sCount, LLImageWorker::getWorkerThread()->getNumDeletes(), + LLImageRaw::sRawImageCount); + + LLFontGL::sMonospace->renderUTF8(text, 0, 0, line_height*2, + text_color, LLFontGL::LEFT, LLFontGL::TOP); + + S32 dx1 = 0; + if (gTextureFetch->mDebugPause) + { + LLFontGL::sMonospace->renderUTF8("!", 0, title_x1, line_height, + text_color, LLFontGL::LEFT, LLFontGL::TOP); + dx1 += 8; + } + if (mTextureView->mFreezeView) + { + LLFontGL::sMonospace->renderUTF8("*", 0, title_x1, line_height, + text_color, LLFontGL::LEFT, LLFontGL::TOP); + dx1 += 8; + } + if (mTextureView->mOrderFetch) + { + LLFontGL::sMonospace->renderUTF8(title_string1b, 0, title_x1+dx1, line_height, + text_color, LLFontGL::LEFT, LLFontGL::TOP); + } + else + { + LLFontGL::sMonospace->renderUTF8(title_string1a, 0, title_x1+dx1, line_height, + text_color, LLFontGL::LEFT, LLFontGL::TOP); + } + + LLFontGL::sMonospace->renderUTF8(title_string2, 0, title_x2, line_height, + text_color, LLFontGL::LEFT, LLFontGL::TOP); + + LLFontGL::sMonospace->renderUTF8(title_string3, 0, title_x3, line_height, + text_color, LLFontGL::LEFT, LLFontGL::TOP); + + LLFontGL::sMonospace->renderUTF8(title_string4, 0, title_x4, line_height, + text_color, LLFontGL::LEFT, LLFontGL::TOP); +} + +BOOL LLGLTexMemBar::handleMouseDown(S32 x, S32 y, MASK mask) +{ + return FALSE; +} + +LLRect LLGLTexMemBar::getRequiredRect() +{ + LLRect rect; + rect.mTop = 8; + return rect; +} + +//////////////////////////////////////////////////////////////////////////// + LLTextureView::LLTextureView(const std::string& name, const LLRect& rect) : LLContainerView(name, rect) { setVisible(FALSE); mFreezeView = FALSE; + mOrderFetch = FALSE; mNumTextureBars = 0; setDisplayChildren(TRUE); @@ -103,29 +567,40 @@ void LLTextureView::draw() typedef std::multiset<decode_pair_t, compare_decode_pair > display_list_t; display_list_t display_image_list; - for (LLViewerImageList::image_list_t::iterator iter = gImageList.mImageList.begin(); + for (LLViewerImageList::image_priority_list_t::iterator iter = gImageList.mImageList.begin(); iter != gImageList.mImageList.end(); ) { LLPointer<LLViewerImage> imagep = *iter++; -#if 1 +#if 0 if (imagep->getDontDiscard()) { continue; } -#endif + if (imagep->isMissingAsset()) { continue; } - -#define HIGH_PRIORITY 100000000.f - F32 pri = imagep->getDecodePriority(); +#endif +#define HIGH_PRIORITY 100000000.f + F32 pri; + if (mOrderFetch) + { + pri = ((F32)imagep->mFetchPriority)/256.f; + } + else + { + pri = imagep->getDecodePriority(); + } + if (sDebugImages.find(imagep) != sDebugImages.end()) { pri += 3*HIGH_PRIORITY; } - + + if (!mOrderFetch) + { #if 1 if (pri < HIGH_PRIORITY && gSelectMgr) { @@ -173,13 +648,15 @@ void LLTextureView::draw() if (pri > 0.f && pri < HIGH_PRIORITY) { if (imagep->mLastPacketTimer.getElapsedTimeF32() < 1.f || - imagep->mLastDecodeTime.getElapsedTimeF32() < 1.f) + imagep->mFetchDeltaTime < 0.25f) { pri += 1*HIGH_PRIORITY; } } #endif -// if (pri > 0.0f) + } + + if (pri > 0.0f) { display_image_list.insert(std::make_pair(pri, imagep)); } @@ -206,9 +683,12 @@ void LLTextureView::draw() } } - sortChildren(SortTextureBars()); + if (mOrderFetch) + sortChildren(LLTextureBar::sort_fetch()); + else + sortChildren(LLTextureBar::sort()); - mGLTexMemBar = new LLGLTexMemBar("gl texmem bar"); + mGLTexMemBar = new LLGLTexMemBar("gl texmem bar", this); addChild(mGLTexMemBar); reshape(mRect.getWidth(), mRect.getHeight(), TRUE); @@ -238,54 +718,41 @@ void LLTextureView::draw() BOOL LLTextureView::addBar(LLViewerImage *imagep, S32 hilite) { - if (!imagep) - { - return FALSE; - } - + llassert(imagep); + LLTextureBar *barp; LLRect r; mNumTextureBars++; - for (std::vector<LLTextureBar*>::iterator iter = mTextureBars.begin(); - iter != mTextureBars.end(); iter++) - { - LLTextureBar* barp = *iter; - if (barp->mImagep == imagep) - { - barp->mHilite = hilite; - return FALSE; - } - } - - barp = new LLTextureBar("texture bar", r); + barp = new LLTextureBar("texture bar", r, this); barp->mImagep = imagep; barp->mHilite = hilite; addChild(barp); mTextureBars.push_back(barp); - // Rearrange all child bars. - reshape(mRect.getWidth(), mRect.getHeight()); return TRUE; } BOOL LLTextureView::handleMouseDown(S32 x, S32 y, MASK mask) { - if (mask & MASK_SHIFT) + if ((mask & MASK_CONTROL) && (mask & MASK_SHIFT)) { - mFreezeView = !mFreezeView; + gTextureFetch->mDebugPause = !gTextureFetch->mDebugPause; return TRUE; } - else if (mask & MASK_CONTROL) + if (mask & MASK_SHIFT) { - return FALSE; + mFreezeView = !mFreezeView; + return TRUE; } - else + if (mask & MASK_CONTROL) { - return FALSE; + mOrderFetch = !mOrderFetch; + return TRUE; } + return LLView::handleMouseDown(x,y,mask); } BOOL LLTextureView::handleMouseUp(S32 x, S32 y, MASK mask) @@ -295,11 +762,6 @@ BOOL LLTextureView::handleMouseUp(S32 x, S32 y, MASK mask) BOOL LLTextureView::handleKey(KEY key, MASK mask, BOOL called_from_parent) { - if (key == ' ') - { - mFreezeView = !mFreezeView; - return TRUE; - } return FALSE; } diff --git a/indra/newview/lltextureview.h b/indra/newview/lltextureview.h index e832a55211..691438c64e 100644 --- a/indra/newview/lltextureview.h +++ b/indra/newview/lltextureview.h @@ -9,11 +9,12 @@ #ifndef LL_LLTEXTUREVIEW_H #define LL_LLTEXTUREVIEW_H -#include "lltexturebar.h" #include "llcontainerview.h" #include "linked_lists.h" class LLViewerImage; +class LLTextureBar; +class LLGLTexMemBar; class LLTextureView : public LLContainerView { @@ -36,6 +37,10 @@ public: private: BOOL addBar(LLViewerImage *image, BOOL hilight = FALSE); void removeAllBars(); + +public: + BOOL mFreezeView; + BOOL mOrderFetch; private: LLTextBox *mInfoTextp; @@ -44,8 +49,6 @@ private: U32 mNumTextureBars; LLGLTexMemBar* mGLTexMemBar; - - BOOL mFreezeView; public: static std::set<LLViewerImage*> sDebugImages; diff --git a/indra/newview/lltoolcomp.cpp b/indra/newview/lltoolcomp.cpp index 3f111583b5..1947459c6a 100644 --- a/indra/newview/lltoolcomp.cpp +++ b/indra/newview/lltoolcomp.cpp @@ -204,7 +204,7 @@ BOOL LLToolCompTranslate::handleHover(S32 x, S32 y, MASK mask) BOOL LLToolCompTranslate::handleMouseDown(S32 x, S32 y, MASK mask) { mMouseDown = TRUE; - gViewerWindow->hitObjectOrLandGlobalAsync(x, y, mask, pickCallback); + gViewerWindow->hitObjectOrLandGlobalAsync(x, y, mask, pickCallback, TRUE); return TRUE; } diff --git a/indra/newview/lltoolfocus.cpp b/indra/newview/lltoolfocus.cpp index c439797c47..cdfc6c2ebf 100644 --- a/indra/newview/lltoolfocus.cpp +++ b/indra/newview/lltoolfocus.cpp @@ -69,13 +69,19 @@ LLToolCamera::~LLToolCamera() // virtual void LLToolCamera::handleSelect() { - if (gFloaterTools) gFloaterTools->setStatusText("Click and drag to change view"); + if (gFloaterTools) + { + gFloaterTools->setStatusText("Click and drag to change view"); + } } // virtual void LLToolCamera::handleDeselect() { - if (gFloaterTools) gFloaterTools->setStatusText(""); + if (gFloaterTools) + { + gFloaterTools->setStatusText(""); + } // gAgent.setLookingAtAvatar(FALSE); } diff --git a/indra/newview/lltoolmorph.cpp b/indra/newview/lltoolmorph.cpp index 87e6496588..49f21909a5 100644 --- a/indra/newview/lltoolmorph.cpp +++ b/indra/newview/lltoolmorph.cpp @@ -215,10 +215,7 @@ BOOL LLVisualParamHint::render() { LLDrawPoolAvatar *avatarPoolp = (LLDrawPoolAvatar *)avatarp->mDrawable->getFace(0)->getPool(); LLGLDepthTest gls_depth(GL_TRUE, GL_TRUE); - gPipeline.unbindAGP(); - avatarPoolp->syncAGP(); - gPipeline.bindAGP(); - avatarPoolp->renderAvatars(avatarp, TRUE); // renders only one avatar (no shaders) + avatarPoolp->renderAvatars(avatarp); // renders only one avatar } avatarp->setVisualParamWeight(mVisualParam, mLastParamWeight); diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp index e0b4483224..68d9ddbd54 100644 --- a/indra/newview/lltoolpie.cpp +++ b/indra/newview/lltoolpie.cpp @@ -61,10 +61,9 @@ LLToolPie::LLToolPie() BOOL LLToolPie::handleMouseDown(S32 x, S32 y, MASK mask) { - // if buttons swapped, don't pick transparent so users can't "pay" - // transparent objects + //left mouse down always picks transparent gViewerWindow->hitObjectOrLandGlobalAsync(x, y, mask, leftMouseCallback, - FALSE, TRUE); + TRUE, TRUE); mGrabMouseButtonDown = TRUE; return TRUE; } diff --git a/indra/newview/lltoolplacer.cpp b/indra/newview/lltoolplacer.cpp index 20677fea98..66ed7cd1fe 100644 --- a/indra/newview/lltoolplacer.cpp +++ b/indra/newview/lltoolplacer.cpp @@ -152,7 +152,6 @@ LLPCode LLToolPlacerPanel::sSphere = LL_PCODE_SPHERE; LLPCode LLToolPlacerPanel::sSphereHemi = LL_PCODE_SPHERE_HEMI; LLPCode LLToolPlacerPanel::sTree = LL_PCODE_LEGACY_TREE; LLPCode LLToolPlacerPanel::sGrass = LL_PCODE_LEGACY_GRASS; -LLPCode LLToolPlacerPanel::sTreeNew = LL_PCODE_TREE_NEW; S32 LLToolPlacerPanel::sButtonsAdded = 0; LLButton* LLToolPlacerPanel::sButtons[ TOOL_PLACER_NUM_BUTTONS ]; diff --git a/indra/newview/lltoolplacer.h b/indra/newview/lltoolplacer.h index 650fc03b01..b38272cfa9 100644 --- a/indra/newview/lltoolplacer.h +++ b/indra/newview/lltoolplacer.h @@ -66,7 +66,6 @@ public: static LLPCode sSphereHemi; static LLPCode sTree; static LLPCode sGrass; - static LLPCode sTreeNew; private: void addButton( const LLString& up_state, const LLString& down_state, LLPCode* pcode ); diff --git a/indra/newview/llviewercamera.cpp b/indra/newview/llviewercamera.cpp index c4c25b33f4..2c7c892807 100644 --- a/indra/newview/llviewercamera.cpp +++ b/indra/newview/llviewercamera.cpp @@ -119,7 +119,8 @@ void LLViewerCamera::calcProjection(const F32 far_distance) const LLMatrix4 gProjectionMat; -void LLViewerCamera::updateFrustumPlanes() +//static +void LLViewerCamera::updateFrustumPlanes(LLCamera& camera, BOOL ortho) { GLint viewport[4]; GLdouble model[16]; @@ -140,23 +141,26 @@ void LLViewerCamera::updateFrustumPlanes() frust[2].setVec((F32)objX,(F32)objY,(F32)objZ); gluUnProject(viewport[0],viewport[1]+viewport[3],0,model,proj,viewport,&objX,&objY,&objZ); frust[3].setVec((F32)objX,(F32)objY,(F32)objZ); - /*gluUnProject(viewport[0],viewport[1],1,model,proj,viewport,&objX,&objY,&objZ); - frust[4].setVec((F32)objX,(F32)objY,(F32)objZ); - gluUnProject(viewport[0]+viewport[2],viewport[1],1,model,proj,viewport,&objX,&objY,&objZ); - frust[5].setVec((F32)objX,(F32)objY,(F32)objZ); - gluUnProject(viewport[0]+viewport[2],viewport[1]+viewport[3],1,model,proj,viewport,&objX,&objY,&objZ); - frust[6].setVec((F32)objX,(F32)objY,(F32)objZ); - gluUnProject(viewport[0],viewport[1]+viewport[3],1,model,proj,viewport,&objX,&objY,&objZ); - frust[7].setVec((F32)objX,(F32)objY,(F32)objZ);*/ - for (U32 i = 0; i < 4; i++) + if (ortho) { - LLVector3 vec = frust[i] - getOrigin(); - vec.normVec(); - frust[i+4] = getOrigin() + vec*getFar()*2.0; + LLVector3 far_shift = LLVector3(camera.getFar()*2.0f,0,0); + for (U32 i = 0; i < 4; i++) + { + frust[i+4] = frust[i] + far_shift; + } + } + else + { + for (U32 i = 0; i < 4; i++) + { + LLVector3 vec = frust[i] - camera.getOrigin(); + vec.normVec(); + frust[i+4] = camera.getOrigin() + vec*camera.getFar()*2.0f; + } } - calcAgentFrustumPlanes(frust); + camera.calcAgentFrustumPlanes(frust); } void LLViewerCamera::setPerspective(BOOL for_selection, @@ -255,7 +259,7 @@ void LLViewerCamera::setPerspective(BOOL for_selection, glGetIntegerv(GL_VIEWPORT, (GLint*)gGLViewport); } - updateFrustumPlanes(); + updateFrustumPlanes(*this); if (gSavedSettings.getBOOL("CameraOffset")) { @@ -583,22 +587,34 @@ BOOL LLViewerCamera::areVertsVisible(LLViewerObject* volumep, BOOL all_verts) return FALSE; } - num_faces = drawablep->getNumFaces(); + LLVolume* volume = volumep->getVolume(); + if (!volume) + { + return FALSE; + } + + LLVOVolume* vo_volume = (LLVOVolume*) volumep; + + vo_volume->updateRelativeXform(); + LLMatrix4 mat = vo_volume->getRelativeXform(); + + LLMatrix4 render_mat(vo_volume->getRenderRotation(), LLVector4(vo_volume->getRenderPosition())); + + num_faces = volume->getNumFaces(); for (i = 0; i < num_faces; i++) { - LLStrider<LLVector3> vertices; - LLFace* face = drawablep->getFace(i); - face->getVertices(vertices); - - for (S32 v = 0; v < (S32)drawablep->getFace(i)->getGeomCount(); v++) + const LLVolumeFace& face = volume->getVolumeFace(i); + + for (U32 v = 0; v < face.mVertices.size(); v++) { - LLVector3 vec = vertices[v]; - if (!face->isState(LLFace::GLOBAL)) + LLVector4 vec = LLVector4(face.mVertices[v].mPosition) * mat; + + if (drawablep->isActive()) { - vec = vec*face->getRenderMatrix(); + vec = vec * render_mat; } - - BOOL in_frustum = pointInFrustum(vec) > 0; + + BOOL in_frustum = pointInFrustum(LLVector3(vec)) > 0; if ( !in_frustum && all_verts || in_frustum && !all_verts) diff --git a/indra/newview/llviewercamera.h b/indra/newview/llviewercamera.h index 6797103997..6ce1dcc046 100644 --- a/indra/newview/llviewercamera.h +++ b/indra/newview/llviewercamera.h @@ -36,7 +36,7 @@ public: const LLVector3 &up_direction, const LLVector3 &point_of_interest); - void updateFrustumPlanes(); + static void updateFrustumPlanes(LLCamera& camera, BOOL ortho = FALSE); void setPerspective(BOOL for_selection, S32 x, S32 y_from_bot, S32 width, S32 height, BOOL limit_select_distance, F32 z_near = 0, F32 z_far = 0); const LLMatrix4 &getProjection() const; diff --git a/indra/newview/llviewercontrol.h b/indra/newview/llviewercontrol.h index 55d92c2d7a..389f0e8bc6 100644 --- a/indra/newview/llviewercontrol.h +++ b/indra/newview/llviewercontrol.h @@ -36,6 +36,7 @@ protected: //setting variables are declared in this function void declare_settings(); +void settings_version_fixup(); // saved at end of session extern LLControlGroup gSavedSettings; diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index 9c3643128b..837eaa90e9 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -44,6 +44,9 @@ #include "llfloatertools.h" #include "llviewerimagelist.h" #include "llfocusmgr.h" +#include "llcubemap.h" +#include "llviewerregion.h" +#include "lldrawpoolwater.h" extern U32 gFrameCount; extern LLPointer<LLImageGL> gStartImageGL; @@ -84,8 +87,12 @@ void display_startup() return; } - LLDynamicTexture::updateAllInstances(); - + // Required for HTML update in login screen + static S32 frame_count = 0; + if (frame_count++ > 1) // make sure we have rendered a frame first + { + LLDynamicTexture::updateAllInstances(); + } glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); LLGLSDefault gls_default; LLGLSUIDefault gls_ui; @@ -364,6 +371,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield) // gCamera->setZoomParameters(zoom_factor, subfield); + gCamera->setNear(MIN_NEAR_PLANE); ////////////////////////// // @@ -379,6 +387,8 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield) else if (!gViewerWindow->isPickPending()) { glClear( GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT ); + //DEBUG TEMPORARY + glClear(GL_COLOR_BUFFER_BIT); } gViewerWindow->setupViewport(); @@ -399,7 +409,13 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield) glClearColor(0.5f, 0.5f, 0.5f, 0.f); glClear(GL_COLOR_BUFFER_BIT); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + LLPipeline::sUseOcclusion = FALSE; } + else + { + LLPipeline::sUseOcclusion = gSavedSettings.getBOOL("UseOcclusion") && gGLManager.mHasOcclusionQuery; + } + stop_glerror(); /////////////////////////////////////// @@ -412,7 +428,8 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield) glLightModelfv (GL_LIGHT_MODEL_AMBIENT,one); stop_glerror(); - //LLGLState::verify(); + //Increment drawable frame counter + LLDrawable::incrementVisible(); ///////////////////////////////////// // @@ -422,6 +439,11 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield) // if (!gDisconnected) { + if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD)) + { //don't draw hud objects in this frame + gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD); + } + LLFastTimer t(LLFastTimer::FTM_WORLD_UPDATE); stop_glerror(); display_update_camera(); @@ -437,34 +459,41 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield) gPipeline.updateGeom(max_geom_update_time); stop_glerror(); + LLSpatialPartition* part = gPipeline.getSpatialPartition(LLPipeline::PARTITION_VOLUME); + part->processImagery(gCamera); + + display_update_camera(); + gFrameStats.start(LLFrameStats::UPDATE_CULL); - gPipeline.updateCull(); + gPipeline.updateCull(*gCamera); stop_glerror(); - if (rebuild) + /////////////////////////////////// + // + // StateSort + // + // Responsible for taking visible objects, and adding them to the appropriate draw orders. + // In the case of alpha objects, z-sorts them first. + // Also creates special lists for outlines and selected face rendering. + // { LLFastTimer t(LLFastTimer::FTM_REBUILD); - - /////////////////////////////////// - // - // StateSort - // - // Responsible for taking visible objects, and adding them to the appropriate draw orders. - // In the case of alpha objects, z-sorts them first. - // Also creates special lists for outlines and selected face rendering. - // - gFrameStats.start(LLFrameStats::STATE_SORT); - gPipeline.stateSort(); - stop_glerror(); - ////////////////////////////////////// - // - // rebuildPools - // - // - gFrameStats.start(LLFrameStats::REBUILD); - gPipeline.rebuildPools(); + gFrameStats.start(LLFrameStats::STATE_SORT); + gPipeline.stateSort(*gCamera); stop_glerror(); + + if (rebuild) + { + ////////////////////////////////////// + // + // rebuildPools + // + // + gFrameStats.start(LLFrameStats::REBUILD); + gPipeline.rebuildPools(); + stop_glerror(); + } } } @@ -509,10 +538,65 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield) && !gRestoreGL && !gDisconnected) { - gPipeline.renderGeom(); + gPipeline.renderGeom(*gCamera); stop_glerror(); } + //render hud attachments + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + if (LLPipeline::sShowHUDAttachments && !gDisconnected && setup_hud_matrices(FALSE)) + { + LLCamera hud_cam = *gCamera; + glClear(GL_DEPTH_BUFFER_BIT); + LLVector3 origin = hud_cam.getOrigin(); + hud_cam.setOrigin(-1.f,0,0); + hud_cam.setAxes(LLVector3(1,0,0), LLVector3(0,1,0), LLVector3(0,0,1)); + LLViewerCamera::updateFrustumPlanes(hud_cam, TRUE); + //only render hud objects + U32 mask = gPipeline.getRenderTypeMask(); + gPipeline.setRenderTypeMask(0); + gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD); + + BOOL has_ui = gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI); + if (has_ui) + { + gPipeline.toggleRenderDebugFeature((void*) LLPipeline::RENDER_DEBUG_FEATURE_UI); + } + + BOOL use_occlusion = gSavedSettings.getBOOL("UseOcclusion"); + gSavedSettings.setBOOL("UseOcclusion", FALSE); + + //cull, sort, and render hud objects + gPipeline.updateCull(hud_cam); + + gPipeline.toggleRenderType(LLDrawPool::POOL_ALPHA_POST_WATER); + gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_BUMP); + gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_SIMPLE); + gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_VOLUME); + + { + LLFastTimer ftm(LLFastTimer::FTM_REBUILD); + gPipeline.stateSort(hud_cam); + } + + gPipeline.renderGeom(hud_cam); + + //restore type mask + gPipeline.setRenderTypeMask(mask); + if (has_ui) + { + gPipeline.toggleRenderDebugFeature((void*) LLPipeline::RENDER_DEBUG_FEATURE_UI); + } + gSavedSettings.setBOOL("UseOcclusion", use_occlusion); + } + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + gFrameStats.start(LLFrameStats::RENDER_UI); if (gHandleKeysAsync) @@ -535,6 +619,64 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield) } +BOOL setup_hud_matrices(BOOL for_select) +{ + LLVOAvatar* my_avatarp = gAgent.getAvatarObject(); + if (my_avatarp && my_avatarp->hasHUDAttachment()) + { + if (!for_select) + { + // clamp target zoom level to reasonable values + my_avatarp->mHUDTargetZoom = llclamp(my_avatarp->mHUDTargetZoom, 0.1f, 1.f); + // smoothly interpolate current zoom level + my_avatarp->mHUDCurZoom = lerp(my_avatarp->mHUDCurZoom, my_avatarp->mHUDTargetZoom, LLCriticalDamp::getInterpolant(0.03f)); + } + + F32 zoom_level = my_avatarp->mHUDCurZoom; + // clear z buffer and set up transform for hud + if (!for_select) + { + glClear(GL_DEPTH_BUFFER_BIT); + } + LLBBox hud_bbox = my_avatarp->getHUDBBox(); + + // set up transform to encompass bounding box of HUD + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + F32 hud_depth = llmax(1.f, hud_bbox.getExtentLocal().mV[VX] * 1.1f); + if (for_select) + { + //RN: reset viewport to window extents so ortho screen is calculated with proper reference frame + gViewerWindow->setupViewport(); + } + glOrtho(-0.5f * gCamera->getAspect(), 0.5f * gCamera->getAspect(), -0.5f, 0.5f, 0.f, hud_depth); + + // apply camera zoom transform (for high res screenshots) + F32 zoom_factor = gCamera->getZoomFactor(); + S16 sub_region = gCamera->getZoomSubRegion(); + if (zoom_factor > 1.f) + { + float offset = zoom_factor - 1.f; + int pos_y = sub_region / llceil(zoom_factor); + int pos_x = sub_region - (pos_y*llceil(zoom_factor)); + glTranslatef(gCamera->getAspect() * 0.5f * (offset - (F32)pos_x * 2.f), 0.5f * (offset - (F32)pos_y * 2.f), 0.f); + glScalef(zoom_factor, zoom_factor, 1.f); + } + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glLoadMatrixf(OGL_TO_CFR_ROTATION); // Load Cory's favorite reference frame + glTranslatef(-hud_bbox.getCenterLocal().mV[VX] + (hud_depth * 0.5f), 0.f, 0.f); + glScalef(zoom_level, zoom_level, zoom_level); + + return TRUE; + } + else + { + return FALSE; + } +} + void render_ui_and_swap() { @@ -546,7 +688,7 @@ void render_ui_and_swap() { LLGLSUIDefault gls_ui; gPipeline.disableLights(); - + LLVertexBuffer::startRender(); if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) { LLFastTimer t(LLFastTimer::FTM_RENDER_UI); @@ -563,6 +705,8 @@ void render_ui_and_swap() LLGLState::checkStates(); #endif } + LLVertexBuffer::stopRender(); + glFlush(); // now do the swap buffer if (gDisplaySwapBuffers) @@ -570,6 +714,11 @@ void render_ui_and_swap() LLFastTimer t(LLFastTimer::FTM_SWAP); gViewerWindow->mWindow->swapBuffers(); } + + { +// LLFastTimer ftm(LLFastTimer::FTM_TEMP6); + LLVertexBuffer::clientCopy(); + } } } @@ -585,8 +734,6 @@ void render_ui_3d() // // Render selections - - glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); @@ -643,7 +790,6 @@ void render_ui_2d() LLFontGL::sCurOrigin.mY -= llround((F32)gViewerWindow->getWindowHeight() * (F32)pos_y / zoom_factor); } - stop_glerror(); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); diff --git a/indra/newview/llviewerjoint.cpp b/indra/newview/llviewerjoint.cpp index cfd23e7120..0ab1fd1cbf 100644 --- a/indra/newview/llviewerjoint.cpp +++ b/indra/newview/llviewerjoint.cpp @@ -82,10 +82,10 @@ void LLViewerJoint::setValid( BOOL valid, BOOL recursive ) //---------------------------------------------------------------- if (recursive) { - for ( LLViewerJoint *joint = (LLViewerJoint*)mChildren.getFirstData(); - joint != NULL; - joint = (LLViewerJoint*)mChildren.getNextData() ) + for (child_list_t::iterator iter = mChildren.begin(); + iter != mChildren.end(); ++iter) { + LLViewerJoint* joint = (LLViewerJoint*)(*iter); joint->setValid(valid, TRUE); } } @@ -198,10 +198,10 @@ void LLViewerJoint::renderSkeleton(BOOL recursive) //---------------------------------------------------------------- if (recursive) { - for ( LLViewerJoint *joint = (LLViewerJoint*)mChildren.getFirstData(); - joint != NULL; - joint = (LLViewerJoint*)mChildren.getNextData() ) + for (child_list_t::iterator iter = mChildren.begin(); + iter != mChildren.end(); ++iter) { + LLViewerJoint* joint = (LLViewerJoint*)(*iter); joint->renderSkeleton(); } } @@ -216,7 +216,7 @@ void LLViewerJoint::renderSkeleton(BOOL recursive) //-------------------------------------------------------------------- // render() //-------------------------------------------------------------------- -U32 LLViewerJoint::render( F32 pixelArea ) +U32 LLViewerJoint::render( F32 pixelArea, BOOL first_pass ) { U32 triangle_count = 0; @@ -226,73 +226,68 @@ U32 LLViewerJoint::render( F32 pixelArea ) if ( mValid ) { + //---------------------------------------------------------------- // if object is transparent, defer it, otherwise // give the joint subclass a chance to draw itself //---------------------------------------------------------------- if ( gRenderForSelect ) { - triangle_count += drawShape( pixelArea ); + triangle_count += drawShape( pixelArea, first_pass ); } else if ( isTransparent() ) { - LLGLEnable blend(GL_BLEND); // Hair and Skirt if ((pixelArea > MIN_PIXEL_AREA_3PASS_HAIR)) { // render all three passes - LLGLEnable alpha_test(GL_ALPHA_TEST); LLGLDisable cull(GL_CULL_FACE); // first pass renders without writing to the z buffer { LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE); - triangle_count += drawShape( pixelArea ); + triangle_count += drawShape( pixelArea, first_pass); } // second pass writes to z buffer only glColorMask(FALSE, FALSE, FALSE, FALSE); { - triangle_count += drawShape( pixelArea ); + triangle_count += drawShape( pixelArea, FALSE ); } // third past respects z buffer and writes color glColorMask(TRUE, TRUE, TRUE, TRUE); { LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE); - triangle_count += drawShape( pixelArea ); + triangle_count += drawShape( pixelArea, FALSE ); } } else { - LLGLEnable alpha_test(GL_ALPHA_TEST); // Render Inside (no Z buffer write) glCullFace(GL_FRONT); { LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE); - triangle_count += drawShape( pixelArea ); + triangle_count += drawShape( pixelArea, first_pass ); } // Render Outside (write to the Z buffer) glCullFace(GL_BACK); { - triangle_count += drawShape( pixelArea ); + triangle_count += drawShape( pixelArea, FALSE ); } } } else { // set up render state - LLGLDisable blend(GL_BLEND); - LLGLSPipelineAvatar gls_pipeline_avatar; - triangle_count += drawShape( pixelArea ); + triangle_count += drawShape( pixelArea, first_pass ); } } //---------------------------------------------------------------- // render children //---------------------------------------------------------------- - LLViewerJoint *joint; - for ( joint = (LLViewerJoint *)mChildren.getFirstData(); - joint != NULL; - joint = (LLViewerJoint *)mChildren.getNextData() ) + for (child_list_t::iterator iter = mChildren.begin(); + iter != mChildren.end(); ++iter) { + LLViewerJoint* joint = (LLViewerJoint*)(*iter); F32 jointLOD = joint->getLOD(); if (pixelArea >= jointLOD || sDisableLOD) { @@ -305,7 +300,6 @@ U32 LLViewerJoint::render( F32 pixelArea ) } } - glColorMask(TRUE, TRUE, TRUE, TRUE); return triangle_count; } @@ -377,7 +371,7 @@ BOOL LLViewerJoint::isTransparent() //-------------------------------------------------------------------- // drawShape() //-------------------------------------------------------------------- -U32 LLViewerJoint::drawShape( F32 pixelArea ) +U32 LLViewerJoint::drawShape( F32 pixelArea, BOOL first_pass ) { return 0; } @@ -390,65 +384,75 @@ void LLViewerJoint::setSkeletonComponents( U32 comp, BOOL recursive ) mComponents = comp; if (recursive) { - for ( LLViewerJoint *joint = (LLViewerJoint *)mChildren.getFirstData(); - joint != NULL; - joint = (LLViewerJoint *)mChildren.getNextData() ) + for (child_list_t::iterator iter = mChildren.begin(); + iter != mChildren.end(); ++iter) { + LLViewerJoint* joint = (LLViewerJoint*)(*iter); joint->setSkeletonComponents(comp, recursive); } } } -void LLViewerJoint::updateFaceSizes(U32 &num_vertices, F32 pixel_area) +void LLViewerJoint::updateFaceSizes(U32 &num_vertices, U32& num_indices, F32 pixel_area) { - for ( LLViewerJoint *joint = (LLViewerJoint*)mChildren.getFirstData(); - joint != NULL; - joint = (LLViewerJoint*)mChildren.getNextData() ) + for (child_list_t::iterator iter = mChildren.begin(); + iter != mChildren.end(); ++iter) { - F32 jointLOD = joint->getLOD(); - if (pixel_area >= jointLOD || sDisableLOD) + LLViewerJoint* joint = (LLViewerJoint*)(*iter); + //F32 jointLOD = joint->getLOD(); + //if (pixel_area >= jointLOD || sDisableLOD) { - joint->updateFaceSizes(num_vertices, pixel_area); + joint->updateFaceSizes(num_vertices, num_indices, pixel_area); - if (jointLOD != DEFAULT_LOD) - { - break; - } + // if (jointLOD != DEFAULT_LOD) + // { + // break; + // } } } } void LLViewerJoint::updateFaceData(LLFace *face, F32 pixel_area, BOOL damp_wind) { - for ( LLViewerJoint *joint = (LLViewerJoint*)mChildren.getFirstData(); - joint != NULL; - joint = (LLViewerJoint*)mChildren.getNextData() ) + for (child_list_t::iterator iter = mChildren.begin(); + iter != mChildren.end(); ++iter) { - F32 jointLOD = joint->getLOD(); - if (pixel_area >= jointLOD || sDisableLOD) + LLViewerJoint* joint = (LLViewerJoint*)(*iter); + //F32 jointLOD = joint->getLOD(); + //if (pixel_area >= jointLOD || sDisableLOD) { joint->updateFaceData(face, pixel_area, damp_wind); - if (jointLOD != DEFAULT_LOD) - { - break; - } + // if (jointLOD != DEFAULT_LOD) + // { + // break; + // } } } } +void LLViewerJoint::updateGeometry() +{ + for (child_list_t::iterator iter = mChildren.begin(); + iter != mChildren.end(); ++iter) + { + LLViewerJoint* joint = (LLViewerJoint*)(*iter); + joint->updateGeometry(); + } +} + BOOL LLViewerJoint::updateLOD(F32 pixel_area, BOOL activate) { BOOL lod_changed = FALSE; BOOL found_lod = FALSE; - for ( LLViewerJoint *joint = (LLViewerJoint*)mChildren.getFirstData(); - joint != NULL; - joint = (LLViewerJoint*)mChildren.getNextData() ) + for (child_list_t::iterator iter = mChildren.begin(); + iter != mChildren.end(); ++iter) { + LLViewerJoint* joint = (LLViewerJoint*)(*iter); F32 jointLOD = joint->getLOD(); - + if (found_lod || jointLOD == DEFAULT_LOD) { // we've already found a joint to enable, so enable the rest as alternatives @@ -472,12 +476,12 @@ BOOL LLViewerJoint::updateLOD(F32 pixel_area, BOOL activate) void LLViewerJoint::dump() { - for ( LLViewerJoint *joint = (LLViewerJoint*)mChildren.getFirstData(); - joint != NULL; - joint = (LLViewerJoint*)mChildren.getNextData() ) - { - joint->dump(); - } + for (child_list_t::iterator iter = mChildren.begin(); + iter != mChildren.end(); ++iter) + { + LLViewerJoint* joint = (LLViewerJoint*)(*iter); + joint->dump(); + } } void LLViewerJoint::setVisible(BOOL visible, BOOL recursive) @@ -486,12 +490,12 @@ void LLViewerJoint::setVisible(BOOL visible, BOOL recursive) if (recursive) { - for ( LLViewerJoint *joint = (LLViewerJoint*)mChildren.getFirstData(); - joint != NULL; - joint = (LLViewerJoint*)mChildren.getNextData() ) - { - joint->setVisible(visible, recursive); - } + for (child_list_t::iterator iter = mChildren.begin(); + iter != mChildren.end(); ++iter) + { + LLViewerJoint* joint = (LLViewerJoint*)(*iter); + joint->setVisible(visible, recursive); + } } } @@ -511,10 +515,10 @@ void LLViewerJoint::writeCAL3D(apr_file_t* fp) LLQuaternion bone_rot; S32 num_children = 0; - for (LLViewerJoint *joint = (LLViewerJoint*)mChildren.getFirstData(); - joint != NULL; - joint = (LLViewerJoint*)mChildren.getNextData() ) + for (child_list_t::iterator iter = mChildren.begin(); + iter != mChildren.end(); ++iter) { + LLViewerJoint* joint = (LLViewerJoint*)(*iter); if (joint->mJointNum != -1) { num_children++; @@ -541,10 +545,10 @@ void LLViewerJoint::writeCAL3D(apr_file_t* fp) apr_file_printf(fp, " <LOCALROTATION>0 0 0 1</LOCALROTATION>\n"); apr_file_printf(fp, " <PARENTID>%d</PARENTID>\n", mParent ? mParent->mJointNum + 1 : -1); - for (LLViewerJoint *joint = (LLViewerJoint*)mChildren.getFirstData(); - joint != NULL; - joint = (LLViewerJoint*)mChildren.getNextData() ) + for (child_list_t::iterator iter = mChildren.begin(); + iter != mChildren.end(); ++iter) { + LLViewerJoint* joint = (LLViewerJoint*)(*iter); if (joint->mJointNum != -1) { apr_file_printf(fp, " <CHILDID>%d</CHILDID>\n", joint->mJointNum + 1); @@ -553,10 +557,10 @@ void LLViewerJoint::writeCAL3D(apr_file_t* fp) apr_file_printf(fp, " </BONE>\n"); // recurse - for (LLViewerJoint *joint = (LLViewerJoint*)mChildren.getFirstData(); - joint != NULL; - joint = (LLViewerJoint*)mChildren.getNextData() ) + for (child_list_t::iterator iter = mChildren.begin(); + iter != mChildren.end(); ++iter) { + LLViewerJoint* joint = (LLViewerJoint*)(*iter); if (joint->mJointNum != -1) { joint->writeCAL3D(fp); diff --git a/indra/newview/llviewerjoint.h b/indra/newview/llviewerjoint.h index e38c1c8e7d..9b5185267f 100644 --- a/indra/newview/llviewerjoint.h +++ b/indra/newview/llviewerjoint.h @@ -43,7 +43,7 @@ public: // Traverses the entire joint hierarchy, setting up // transforms and calling the drawShape(). // Derived classes may add text/graphic output. - virtual U32 render( F32 pixelArea ); // Returns triangle count + virtual U32 render( F32 pixelArea, BOOL first_pass = TRUE ); // Returns triangle count // Draws a bone graphic to the parent joint. // Derived classes may add text/graphic output. @@ -59,7 +59,7 @@ public: // Draws the shape attached to a joint. // Called by render(). - virtual U32 drawShape( F32 pixelArea ); + virtual U32 drawShape( F32 pixelArea, BOOL first_pass = TRUE ); virtual void drawNormals() {} enum Components @@ -78,9 +78,9 @@ public: // Sets the level of detail for this node as a minimum // pixel area threshold. If the current pixel area for this // object is less than the specified threshold, the node is - // not traversed. In additin, if a value is specified (not + // not traversed. In addition, if a value is specified (not // default of 0.0), and the pixel area is larger than the - // specified miniumn, the node is rendered, but no other siblings + // specified minimum, the node is rendered, but no other siblings // of this node under the same parent will be. F32 getLOD() { return mMinPixelArea; } void setLOD( F32 pixelArea ) { mMinPixelArea = pixelArea; } @@ -101,9 +101,10 @@ public: void setPickName(PickName name) { mPickName = name; } PickName getPickName() { return mPickName; } - virtual void updateFaceSizes(U32 &num_vertices, F32 pixel_area); + virtual void updateFaceSizes(U32 &num_vertices, U32& num_indices, F32 pixel_area); virtual void updateFaceData(LLFace *face, F32 pixel_area, BOOL damp_wind = FALSE); virtual BOOL updateLOD(F32 pixel_area, BOOL activate); + virtual void updateGeometry(); virtual void dump(); void setVisible( BOOL visible, BOOL recursive ); @@ -135,3 +136,4 @@ public: #endif // LL_LLVIEWERJOINT_H + diff --git a/indra/newview/llviewerjointattachment.cpp b/indra/newview/llviewerjointattachment.cpp index 4ae527eee5..090276ef51 100644 --- a/indra/newview/llviewerjointattachment.cpp +++ b/indra/newview/llviewerjointattachment.cpp @@ -60,7 +60,7 @@ BOOL LLViewerJointAttachment::isTransparent() //----------------------------------------------------------------------------- // drawShape() //----------------------------------------------------------------------------- -U32 LLViewerJointAttachment::drawShape( F32 pixelArea ) +U32 LLViewerJointAttachment::drawShape( F32 pixelArea, BOOL first_pass ) { if (LLVOAvatar::sShowAttachmentPoints) { @@ -277,47 +277,20 @@ void LLViewerJointAttachment::removeObject(LLViewerObject *object) //----------------------------------------------------------------------------- void LLViewerJointAttachment::setAttachmentVisibility(BOOL visible) { - if (!mAttachedObject || mAttachedObject->mDrawable.isNull()) + if (!mAttachedObject || mAttachedObject->mDrawable.isNull() || + !(mAttachedObject->mDrawable->getSpatialBridge())) return; if (visible) { // Hack to make attachments not visible by disabling their type mask! // This will break if you can ever attach non-volumes! - djs 02/14/03 - mAttachedObject->mDrawable->setRenderType(LLPipeline::RENDER_TYPE_VOLUME); - for (LLViewerObject::child_list_t::iterator iter = mAttachedObject->mChildList.begin(); - iter != mAttachedObject->mChildList.end(); ++iter) - { - LLViewerObject* childp = *iter; - if (childp && childp->mDrawable.notNull()) - { - childp->mDrawable->setRenderType(LLPipeline::RENDER_TYPE_VOLUME); - } - } + mAttachedObject->mDrawable->getSpatialBridge()->mDrawableType = + mAttachedObject->isHUDAttachment() ? LLPipeline::RENDER_TYPE_HUD : LLPipeline::RENDER_TYPE_VOLUME; } else { - //RN: sometimes we call this on objects that are already invisible, so check for that case - if (!mAttachedObject->mDrawable->isRenderType(LLPipeline::RENDER_TYPE_VOLUME) && - !mAttachedObject->mDrawable->isRenderType(0)) - { - llerrs << "Tried to attach non-volume to a joint, visibility hack dangerous!" << llendl; - } - mAttachedObject->mDrawable->setRenderType(0); - for (LLViewerObject::child_list_t::iterator iter = mAttachedObject->mChildList.begin(); - iter != mAttachedObject->mChildList.end(); ++iter) - { - LLViewerObject* childp = *iter; - if (childp && childp->mDrawable.notNull()) - { - if (!childp->mDrawable->isRenderType(LLPipeline::RENDER_TYPE_VOLUME) && - !mAttachedObject->mDrawable->isRenderType(0)) - { - llerrs << "Tried to attach non-volume to a joint, visibility hack dangerous!" << llendl; - } - childp->mDrawable->setRenderType(0); - } - } + mAttachedObject->mDrawable->getSpatialBridge()->mDrawableType = 0; } } diff --git a/indra/newview/llviewerjointattachment.h b/indra/newview/llviewerjointattachment.h index b3a6ccb89c..e0354a8c10 100644 --- a/indra/newview/llviewerjointattachment.h +++ b/indra/newview/llviewerjointattachment.h @@ -37,7 +37,7 @@ public: // Draws the shape attached to a joint. // Called by render(). - /*virtual*/ U32 drawShape( F32 pixelArea ); + /*virtual*/ U32 drawShape( F32 pixelArea, BOOL first_pass ); /*virtual*/ BOOL updateLOD(F32 pixel_area, BOOL activate); @@ -60,7 +60,7 @@ public: S32 getGroup() { return mGroup; } S32 getPieSlice() { return mPieSlice; } BOOL getAttachmentDirty() { return mAttachmentDirty && mAttachedObject; } - LLViewerObject *getObject(S32 i) { return mAttachedObject; } + LLViewerObject *getObject() { return mAttachedObject; } S32 getNumObjects() { return (mAttachedObject ? 1 : 0); } const LLUUID& getItemID() { return mItemID; } diff --git a/indra/newview/llviewerjointmesh.cpp b/indra/newview/llviewerjointmesh.cpp index aec15a8d6c..512ddc8565 100644 --- a/indra/newview/llviewerjointmesh.cpp +++ b/indra/newview/llviewerjointmesh.cpp @@ -19,7 +19,6 @@ #include "llfasttimer.h" #include "llagent.h" -#include "llagparray.h" #include "llbox.h" #include "lldrawable.h" #include "lldrawpoolavatar.h" @@ -43,6 +42,10 @@ extern PFNGLVERTEXBLENDARBPROC glVertexBlendARB; #endif extern BOOL gRenderForSelect; +static LLPointer<LLVertexBuffer> sRenderBuffer = NULL; +static const U32 sRenderMask = LLVertexBuffer::MAP_VERTEX | + LLVertexBuffer::MAP_NORMAL | + LLVertexBuffer::MAP_TEXCOORD; LLMatrix4 gBlendMat; //----------------------------------------------------------------------------- @@ -375,11 +378,11 @@ void LLViewerJointMesh::setupJoint(LLViewerJoint* current_joint) } // depth-first traversal - for (LLJoint *child_joint = current_joint->mChildren.getFirstData(); - child_joint; - child_joint = current_joint->mChildren.getNextData()) + for (LLJoint::child_list_t::iterator iter = current_joint->mChildren.begin(); + iter != current_joint->mChildren.end(); ++iter) { - setupJoint((LLViewerJoint*)child_joint); + LLViewerJoint* child_joint = (LLViewerJoint*)(*iter); + setupJoint(child_joint); } } @@ -412,7 +415,7 @@ void LLViewerJointMesh::uploadJointMatrices() if (hardware_skinning) { - joint_mat *= gCamera->getModelview(); + joint_mat *= LLDrawPoolAvatar::getModelView(); } gJointMat[joint_num] = joint_mat; gJointRot[joint_num] = joint_mat.getMat3(); @@ -513,620 +516,39 @@ int compare_int(const void *a, const void *b) else return 0; } -#if LL_WINDOWS || (LL_DARWIN && __i386__) // SSE optimizations in avatar code - -#if LL_DARWIN -#include <xmmintrin.h> - - // On Windows, this class is defined in fvec.h. I've only reproduced the parts of it we use here for now. - #pragma pack(push,16) /* Must ensure class & union 16-B aligned */ - class F32vec4 - { - protected: - __m128 vec; - public: - - /* Constructors: __m128, 4 floats, 1 float */ - F32vec4() {} - - /* initialize 4 SP FP with __m128 data type */ - F32vec4(__m128 m) { vec = m;} - - /* Explicitly initialize each of 4 SP FPs with same float */ - explicit F32vec4(float f) { vec = _mm_set_ps1(f); } - }; - #pragma pack(pop) /* 16-B aligned */ - - -#endif - -void blend_SSE_32_32_batch(const int vert_offset, const int vert_count, float* output, - LLStrider<LLVector3>& vertices, LLStrider<LLVector2>& texcoords, LLStrider<LLVector3>& normals, LLStrider<F32>& weights) +void llDrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices) { - F32 last_weight = F32_MAX; - LLMatrix4 *blend_mat = &gBlendMat; - - for (S32 index = vert_offset; index < vert_offset + vert_count; index++) + if (end-start+1 > (U32) gGLManager.mGLMaxVertexRange || + count > gGLManager.mGLMaxIndexRange) { - F32 w = weights [index]; // register copy of weight - F32 *vin = &vertices[index].mV[0]; // pointer to input vertex data, assumed to be V3+T2+N3+whatever - F32 *vout = output + index * (AVATAR_VERTEX_BYTES/sizeof(F32)); // pointer to the output vertex data, assumed to be 16 byte aligned - - if (w == last_weight) - { - // load input and output vertices, and last blended matrix - __asm { - mov esi, vin - mov edi, vout - - mov edx, blend_mat - movaps xmm4, [edx] - movaps xmm5, [edx+0x10] - movaps xmm6, [edx+0x20] - movaps xmm7, [edx+0x30] - } - } - else - { - last_weight = w; - S32 joint = llfloor(w); - w -= joint; - - LLMatrix4 *m0 = &(gJointMat[joint+1]); - LLMatrix4 *m1 = &(gJointMat[joint+0]); - - // some initial code to load Matrix 0 into SSE registers - __asm { - mov esi, vin - mov edi, vout - - //matrix2 - mov edx, m0 - movaps xmm4, [edx] - movaps xmm5, [edx+0x10] - movaps xmm6, [edx+0x20] - movaps xmm7, [edx+0x30] - }; - - // if w == 1.0f, we don't need to blend. - // but since we do the trick of blending the matrices, here, if w != 1.0, - // we load Matrix 1 into the other 4 SSE registers and blend both matrices - // based on the weight (which we load ingo a 16-byte aligned vector: w,w,w,w) - - if (w != 1.0f) - { - F32vec4 weight(w); - - __asm { // do blending of matrices instead of verts and normals -- faster - mov edx, m1 - movaps xmm0, [edx] - movaps xmm1, [edx+0x10] - movaps xmm2, [edx+0x20] - movaps xmm3, [edx+0x30] - - subps xmm4, xmm0 // do blend for each matrix column - subps xmm5, xmm1 // diff, then multiply weight and re-add - subps xmm6, xmm2 - subps xmm7, xmm3 - - mulps xmm4, weight - mulps xmm5, weight - mulps xmm6, weight - mulps xmm7, weight - - addps xmm4, xmm0 - addps xmm5, xmm1 - addps xmm6, xmm2 - addps xmm7, xmm3 - }; - } - - __asm { - // save off blended matrix - mov edx, blend_mat; - movaps [edx], xmm4; - movaps [edx+0x10], xmm5; - movaps [edx+0x20], xmm6; - movaps [edx+0x30], xmm7; - } - } - - // now, we have either a blended matrix in xmm4-7 or the original Matrix 0 - // we then multiply each vertex and normal by this one matrix. - - // For SSE2, we would try to keep the original two matrices in other registers - // and avoid reloading them. However, they should ramain in L1 cache in the - // current case. - - // One possible optimization would be to sort the vertices by weight instead - // of just index (we still want to uniqify). If we note when two or more vertices - // share the same weight, we can avoid doing the middle SSE code above and just - // re-use the blended matrix for those vertices - - - // now, we do the actual vertex blending - __asm { - // load Vertex into xmm0. - movaps xmm0, [esi] // change aps to ups when input is no longer 16-baligned - movaps xmm1, xmm0 // copy vector into xmm0 through xmm2 (x,y,z) - movaps xmm2, xmm0 - shufps xmm0, xmm0, _MM_SHUFFLE(0,0,0,0); // clone vertex (x) across vector - shufps xmm1, xmm1, _MM_SHUFFLE(1,1,1,1); // clone vertex (y) across vector - shufps xmm2, xmm2, _MM_SHUFFLE(2,2,2,2); // same for Z - mulps xmm0, xmm4 // do the actual matrix multipication for r0 - mulps xmm1, xmm5 // for r1 - mulps xmm2, xmm6 // for r2 - addps xmm0, xmm1 // accumulate - addps xmm0, xmm2 // accumulate - addps xmm0, xmm7 // add in the row 4 which holds the x,y,z translation. assumes w=1 (vertex-w, not weight) - - movaps [edi], xmm0 // store aligned in output array - - // load Normal into xmm0. - movaps xmm0, [esi + 0x10] // change aps to ups when input no longer 16-byte aligned - movaps xmm1, xmm0 // - movaps xmm2, xmm0 - shufps xmm0, xmm0, _MM_SHUFFLE(0,0,0,0); // since UV sits between vertex and normal, normal starts at element 1, not 0 - shufps xmm1, xmm1, _MM_SHUFFLE(1,1,1,1); - shufps xmm2, xmm2, _MM_SHUFFLE(2,2,2,2); - mulps xmm0, xmm4 // multiply by matrix - mulps xmm1, xmm5 // multiply - mulps xmm2, xmm6 // multiply - addps xmm0, xmm1 // accumulate - addps xmm0, xmm2 // accumulate. note: do not add translation component to normals, save time too - movaps [edi + 0x10], xmm0 // store aligned - } - - *(LLVector2*)(vout + (AVATAR_OFFSET_TEX0/sizeof(F32))) = texcoords[index]; // write texcoord into appropriate spot. - } -} - -#elif LL_LINUX - -void blend_SSE_32_32_batch(const int vert_offset, const int vert_count, float* output, - LLStrider<LLVector3>& vertices, LLStrider<LLVector2>& texcoords, LLStrider<LLVector3>& normals, LLStrider<F32>& weights) -{ - assert(0); -} - -#elif LL_DARWIN -// AltiVec versions of the same... - -static inline vector float loadAlign(int offset, vector float *addr) -{ - vector float in0 = vec_ld(offset, addr); - vector float in1 = vec_ld(offset + 16, addr); - vector unsigned char perm = vec_lvsl(0, (unsigned char*)addr); - - return(vec_perm(in0, in1, perm)); -} - -static inline void storeAlign(vector float v, int offset, vector float *addr) -{ - vector float in0 = vec_ld(offset, addr); - vector float in1 = vec_ld(offset + 16, addr); - vector unsigned char perm = vec_lvsr(0, (unsigned char *)addr); - vector float temp = vec_perm(v, v, perm); - vector unsigned char mask = (vector unsigned char)vec_cmpgt(perm, vec_splat_u8(15)); - - in0 = vec_sel(in0, temp, (vector unsigned int)mask); - in1 = vec_sel(temp, in1, (vector unsigned int)mask); - - vec_st(in0, offset, addr); - vec_st(in1, offset + 16, addr); -} - -void blend_SSE_32_32_batch(const int vert_offset, const int vert_count, float* output, - LLStrider<LLVector3>& vertices, LLStrider<LLVector2>& texcoords, LLStrider<LLVector3>& normals, LLStrider<F32>& weights) -{ - F32 last_weight = F32_MAX; -// LLMatrix4 &blend_mat = gBlendMat; - - vector float matrix0_0, matrix0_1, matrix0_2, matrix0_3; - vector unsigned char out0perm = (vector unsigned char) ( 0x10,0x11,0x12,0x13, 0x14,0x15,0x16,0x17, 0x18,0x19,0x1A,0x1B, 0x0C,0x0D,0x0E,0x0F ); -// vector unsigned char out1perm = (vector unsigned char) ( 0x00,0x01,0x02,0x03, 0x10,0x11,0x12,0x13, 0x14,0x15,0x16,0x17, 0x18,0x19,0x1A,0x1B ); - vector unsigned char out1perm = (vector unsigned char) ( 0x10,0x11,0x12,0x13, 0x14,0x15,0x16,0x17, 0x18,0x19,0x1A,0x1B, 0x0C,0x0D,0x0E,0x0F ); - - vector float zero = (vector float)vec_splat_u32(0); - - for (U32 index = vert_offset; index < vert_offset + vert_count; index++) - { - F32 w = weights [index]; // register copy of weight - F32 *vin = &vertices[index].mV[0]; // pointer to input vertex data, assumed to be V3+T2+N3+whatever - F32 *vout = output + index * (AVATAR_VERTEX_BYTES/sizeof(F32)); // pointer to the output vertex data, assumed to be 16 byte aligned - - // MBW -- XXX -- If this isn't the case, this code gets more complicated. - if(0x0000000F & (U32)vin) - { - llerrs << "blend_SSE_batch: input not 16-byte aligned!" << llendl; - } - if(0x0000000F & (U32)vout) - { - llerrs << "blend_SSE_batch: output not 16-byte aligned!" << llendl; - } -// if(0x0000000F & (U32)&(blend_mat.mMatrix)) -// { -// llerrs << "blend_SSE_batch: blend_mat not 16-byte aligned!" << llendl; -// } - - if (w == last_weight) - { - // load last blended matrix - // Still loaded from last time through the loop. -// matrix0_0 = vec_ld(0x00, (vector float*)&(blend_mat.mMatrix)); -// matrix0_1 = vec_ld(0x10, (vector float*)&(blend_mat.mMatrix)); -// matrix0_2 = vec_ld(0x20, (vector float*)&(blend_mat.mMatrix)); -// matrix0_3 = vec_ld(0x30, (vector float*)&(blend_mat.mMatrix)); - } - else - { - last_weight = w; - S32 joint = llfloor(w); - w -= joint; - - LLMatrix4 &m0 = gJointMat[joint+1]; - LLMatrix4 &m1 = gJointMat[joint+0]; - - // load Matrix 0 into vector registers - matrix0_0 = vec_ld(0x00, (vector float*)&(m0.mMatrix)); - matrix0_1 = vec_ld(0x10, (vector float*)&(m0.mMatrix)); - matrix0_2 = vec_ld(0x20, (vector float*)&(m0.mMatrix)); - matrix0_3 = vec_ld(0x30, (vector float*)&(m0.mMatrix)); - - // if w == 1.0f, we don't need to blend. - // but since we do the trick of blending the matrices, here, if w != 1.0, - // we load Matrix 1 into the other 4 SSE registers and blend both matrices - // based on the weight (which we load ingo a 16-byte aligned vector: w,w,w,w) - - if (w != 1.0f) - { - vector float matrix1_0, matrix1_1, matrix1_2, matrix1_3; - - // This loads the weight somewhere in the vector register - vector float weight = vec_lde(0, &(w)); - // and this splats it to all elements. - weight = vec_splat(vec_perm(weight, weight, vec_lvsl(0, &(w))), 0); - - // do blending of matrices instead of verts and normals -- faster - matrix1_0 = vec_ld(0x00, (vector float*)&(m1.mMatrix)); - matrix1_1 = vec_ld(0x10, (vector float*)&(m1.mMatrix)); - matrix1_2 = vec_ld(0x20, (vector float*)&(m1.mMatrix)); - matrix1_3 = vec_ld(0x30, (vector float*)&(m1.mMatrix)); - - // m0[col] = ((m0[col] - m1[col]) * weight) + m1[col]; - matrix0_0 = vec_madd(vec_sub(matrix0_0, matrix1_0), weight, matrix1_0); - matrix0_1 = vec_madd(vec_sub(matrix0_1, matrix1_1), weight, matrix1_1); - matrix0_2 = vec_madd(vec_sub(matrix0_2, matrix1_2), weight, matrix1_2); - matrix0_3 = vec_madd(vec_sub(matrix0_3, matrix1_3), weight, matrix1_3); - } - - // save off blended matrix -// vec_st(matrix0_0, 0x00, (vector float*)&(blend_mat.mMatrix)); -// vec_st(matrix0_1, 0x10, (vector float*)&(blend_mat.mMatrix)); -// vec_st(matrix0_2, 0x20, (vector float*)&(blend_mat.mMatrix)); -// vec_st(matrix0_3, 0x30, (vector float*)&(blend_mat.mMatrix)); - } - - // now, we have either a blended matrix in matrix0_0-3 or the original Matrix 0 - // we then multiply each vertex and normal by this one matrix. - - // For SSE2, we would try to keep the original two matrices in other registers - // and avoid reloading them. However, they should ramain in L1 cache in the - // current case. - - // One possible optimization would be to sort the vertices by weight instead - // of just index (we still want to uniqify). If we note when two or more vertices - // share the same weight, we can avoid doing the middle SSE code above and just - // re-use the blended matrix for those vertices - - - // now, we do the actual vertex blending - - vector float in0 = vec_ld(AVATAR_OFFSET_POS, (vector float*)vin); - vector float in1 = vec_ld(AVATAR_OFFSET_NORMAL, (vector float*)vin); - - // Matrix multiply vertex - vector float out0 = vec_madd - ( - vec_splat(in0, 0), - matrix0_0, - vec_madd - ( - vec_splat(in0, 1), - matrix0_1, - vec_madd - ( - vec_splat(in0, 2), - matrix0_2, - matrix0_3 - ) - ) - ); - - // Matrix multiply normal - vector float out1 = vec_madd - ( - vec_splat(in1, 0), - matrix0_0, - vec_madd - ( - vec_splat(in1, 1), - matrix0_1, - vec_madd - ( - vec_splat(in1, 2), - matrix0_2, - // no translation for normals - (vector float)vec_splat_u32(0) - ) - ) - ); - - // indexed store - vec_stl(vec_perm(in0, out0, out0perm), AVATAR_OFFSET_POS, (vector float*)vout); // Pos - vec_stl(vec_perm(in1, out1, out1perm), AVATAR_OFFSET_NORMAL, (vector float*)vout); // Norm - *(LLVector2*)(vout + (AVATAR_OFFSET_TEX0/sizeof(F32))) = texcoords[index]; // write texcoord into appropriate spot. - } -} - -#endif - - -void llDrawElementsBatchBlend(const U32 vert_offset, const U32 vert_count, LLFace *face, const S32 index_count, const U32 *indices) -{ - U8* gAGPVertices = gPipeline.bufferGetScratchMemory(); - - if (gAGPVertices) - { - LLStrider<LLVector3> vertices; - LLStrider<LLVector3> normals; - LLStrider<LLVector2> tcoords0; - LLStrider<F32> weights; - - LLStrider<LLVector3> o_vertices; - LLStrider<LLVector3> o_normals; - LLStrider<LLVector2> o_texcoords0; - - - LLStrider<LLVector3> binormals; - LLStrider<LLVector2> o_texcoords1; - // get the source vertices from the draw pool. We index these ourselves, as there was - // no guarantee the indices for a single jointmesh were contigious - - LLDrawPool *pool = face->getPool(); - pool->getVertexStrider (vertices, 0); - pool->getTexCoordStrider (tcoords0, 0, 0); - pool->getNormalStrider (normals, 0); - pool->getBinormalStrider (binormals, 0); - pool->getVertexWeightStrider(weights, 0); - - // load the addresses of the output striders - o_vertices = (LLVector3*)(gAGPVertices + AVATAR_OFFSET_POS); o_vertices.setStride( AVATAR_VERTEX_BYTES); - o_normals = (LLVector3*)(gAGPVertices + AVATAR_OFFSET_NORMAL); o_normals.setStride( AVATAR_VERTEX_BYTES); - o_texcoords0= (LLVector2*)(gAGPVertices + AVATAR_OFFSET_TEX0); o_texcoords0.setStride(AVATAR_VERTEX_BYTES); - o_texcoords1= (LLVector2*)(gAGPVertices + AVATAR_OFFSET_TEX1); o_texcoords1.setStride(AVATAR_VERTEX_BYTES); - -#if !LL_LINUX // !!! *TODO: do the linux implementation - if (gGLManager.mSoftwareBlendSSE) - { - // do SSE blend without binormals or extra texcoords - blend_SSE_32_32_batch(vert_offset, vert_count, (float*)gAGPVertices, - vertices, tcoords0, normals, weights); - } - else // fully backwards compatible software blending, no SSE -#endif - { - LLVector4 tpos0, tnorm0, tpos1, tnorm1, tbinorm0, tbinorm1; - F32 last_weight = F32_MAX; - LLMatrix3 gBlendRotMat; - - { - for (U32 index=vert_offset; index < vert_offset + vert_count; index++) - { - // blend by first matrix - F32 w = weights [index]; - - if (w != last_weight) - { - last_weight = w; - - S32 joint = llfloor(w); - w -= joint; - - LLMatrix4 &m0 = gJointMat[joint+1]; - LLMatrix4 &m1 = gJointMat[joint+0]; - LLMatrix3 &n0 = gJointRot[joint+1]; - LLMatrix3 &n1 = gJointRot[joint+0]; - - if (w == 1.0f) - { - gBlendMat = m0; - gBlendRotMat = n0; - } - else - { - gBlendMat.mMatrix[VX][VX] = lerp(m1.mMatrix[VX][VX], m0.mMatrix[VX][VX], w); - gBlendMat.mMatrix[VX][VY] = lerp(m1.mMatrix[VX][VY], m0.mMatrix[VX][VY], w); - gBlendMat.mMatrix[VX][VZ] = lerp(m1.mMatrix[VX][VZ], m0.mMatrix[VX][VZ], w); - - gBlendMat.mMatrix[VY][VX] = lerp(m1.mMatrix[VY][VX], m0.mMatrix[VY][VX], w); - gBlendMat.mMatrix[VY][VY] = lerp(m1.mMatrix[VY][VY], m0.mMatrix[VY][VY], w); - gBlendMat.mMatrix[VY][VZ] = lerp(m1.mMatrix[VY][VZ], m0.mMatrix[VY][VZ], w); - - gBlendMat.mMatrix[VZ][VX] = lerp(m1.mMatrix[VZ][VX], m0.mMatrix[VZ][VX], w); - gBlendMat.mMatrix[VZ][VY] = lerp(m1.mMatrix[VZ][VY], m0.mMatrix[VZ][VY], w); - gBlendMat.mMatrix[VZ][VZ] = lerp(m1.mMatrix[VZ][VZ], m0.mMatrix[VZ][VZ], w); - - gBlendMat.mMatrix[VW][VX] = lerp(m1.mMatrix[VW][VX], m0.mMatrix[VW][VX], w); - gBlendMat.mMatrix[VW][VY] = lerp(m1.mMatrix[VW][VY], m0.mMatrix[VW][VY], w); - gBlendMat.mMatrix[VW][VZ] = lerp(m1.mMatrix[VW][VZ], m0.mMatrix[VW][VZ], w); - - gBlendRotMat.mMatrix[VX][VX] = lerp(n1.mMatrix[VX][VX], n0.mMatrix[VX][VX], w); - gBlendRotMat.mMatrix[VX][VY] = lerp(n1.mMatrix[VX][VY], n0.mMatrix[VX][VY], w); - gBlendRotMat.mMatrix[VX][VZ] = lerp(n1.mMatrix[VX][VZ], n0.mMatrix[VX][VZ], w); - - gBlendRotMat.mMatrix[VY][VX] = lerp(n1.mMatrix[VY][VX], n0.mMatrix[VY][VX], w); - gBlendRotMat.mMatrix[VY][VY] = lerp(n1.mMatrix[VY][VY], n0.mMatrix[VY][VY], w); - gBlendRotMat.mMatrix[VY][VZ] = lerp(n1.mMatrix[VY][VZ], n0.mMatrix[VY][VZ], w); - - gBlendRotMat.mMatrix[VZ][VX] = lerp(n1.mMatrix[VZ][VX], n0.mMatrix[VZ][VX], w); - gBlendRotMat.mMatrix[VZ][VY] = lerp(n1.mMatrix[VZ][VY], n0.mMatrix[VZ][VY], w); - gBlendRotMat.mMatrix[VZ][VZ] = lerp(n1.mMatrix[VZ][VZ], n0.mMatrix[VZ][VZ], w); - } - } - - // write result - o_vertices [index] = vertices[index] * gBlendMat; - o_normals [index] = normals [index] * gBlendRotMat; - o_texcoords0[index] = tcoords0[index]; - - /* - // Verification code. Leave this here. It's useful for keeping the SSE and non-SSE versions in sync. - LLVector3 temp; - temp = tpos0; - if( (o_vertices[index] - temp).magVecSquared() > 0.001f ) - { - llerrs << "V SSE: " << o_vertices[index] << " v. " << temp << llendl; - } - - temp = tnorm0; - if( (o_normals[index] - temp).magVecSquared() > 0.001f ) - { - llerrs << "N SSE: " << o_normals[index] << " v. " << temp << llendl; - } - - if( (o_texcoords0[index] - tcoords0[index]).magVecSquared() > 0.001f ) - { - llerrs << "T0 SSE: " << o_texcoords0[index] << " v. " << tcoords0[index] << llendl; - } - */ - } - } - } - -#if LL_DARWIN - // *HACK* *CHOKE* *PUKE* - // No way does this belong here. - glFlushVertexArrayRangeAPPLE(AVATAR_VERTEX_BYTES * vert_count, gAGPVertices + (AVATAR_VERTEX_BYTES * vert_offset)); -#endif - glDrawElements(GL_TRIANGLES, index_count, GL_UNSIGNED_INT, indices); // draw it! + glDrawElements(mode,count,type,indices); } else { - glDrawElements(GL_TRIANGLES, index_count, GL_UNSIGNED_INT, indices); + glDrawRangeElements(mode,start,end,count,type,indices); } } - - -//-------------------------------------------------------------------- -// DrawElements - -// works just like glDrawElements, except it assumes GL_TRIANGLES and GL_UNSIGNED_INT indices - -// why? because the destination buffer may not be the AGP buffer and the eyes do not use blending -// separate the eyes into their own drawpools and this code goes away. - -//-------------------------------------------------------------------- - -void llDrawElements(const S32 count, const U32 *indices, LLFace *face) -{ - U8* gAGPVertices = gPipeline.bufferGetScratchMemory(); - - if (gAGPVertices) - { -#if LL_DARWIN - U32 minIndex = indices[0]; - U32 maxIndex = indices[0]; -#endif - { - LLStrider<LLVector3> vertices; - LLStrider<LLVector3> normals; - LLStrider<LLVector2> tcoords; - LLStrider<F32> weights; - - LLStrider<LLVector3> o_vertices; - LLStrider<LLVector3> o_normals; - LLStrider<LLVector2> o_texcoords0; - - LLDrawPool *pool = face->getPool(); - pool->getVertexStrider (vertices,0); - pool->getNormalStrider (normals, 0); - pool->getTexCoordStrider (tcoords, 0); - - o_vertices = (LLVector3*)(gAGPVertices + AVATAR_OFFSET_POS); o_vertices.setStride( AVATAR_VERTEX_BYTES); - o_normals = (LLVector3*)(gAGPVertices + AVATAR_OFFSET_NORMAL); o_normals.setStride( AVATAR_VERTEX_BYTES); - o_texcoords0= (LLVector2*)(gAGPVertices + AVATAR_OFFSET_TEX0); o_texcoords0.setStride(AVATAR_VERTEX_BYTES); - - for (S32 i=0; i < count; i++) - { - U32 index = indices[i]; - - o_vertices [index] = vertices[index]; - o_normals [index] = normals [index]; - o_texcoords0[index] = tcoords [index]; - -#if LL_DARWIN - maxIndex = llmax(index, maxIndex); - minIndex = llmin(index, minIndex); -#endif - } - } - -#if LL_DARWIN - // *HACK* *CHOKE* *PUKE* - // No way does this belong here. - glFlushVertexArrayRangeAPPLE(AVATAR_VERTEX_BYTES * (maxIndex + 1 - minIndex), gAGPVertices + (AVATAR_VERTEX_BYTES * minIndex)); -#endif - - glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, indices); - } - else - { - glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, indices); - } -} - - //-------------------------------------------------------------------- // LLViewerJointMesh::drawShape() //-------------------------------------------------------------------- -U32 LLViewerJointMesh::drawShape( F32 pixelArea ) +U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass) { - if (!mValid || !mVisible) return 0; - - U32 triangle_count = 0; - - //---------------------------------------------------------------- - // if no mesh bail out now - //---------------------------------------------------------------- - if ( !mMesh || !mFace) + if (!mValid || !mMesh || !mFace || !mVisible || + mFace->mVertexBuffer.isNull() || + mMesh->getNumFaces() == 0) { return 0; } - //---------------------------------------------------------------- - // if we have no faces, bail out now - //---------------------------------------------------------------- - if ( mMesh->getNumFaces() == 0 ) - { - return 0; - } + U32 triangle_count = 0; stop_glerror(); //---------------------------------------------------------------- // setup current color //---------------------------------------------------------------- - if (gRenderForSelect) - { - S32 name = mFace->getDrawable() ? mFace->getDrawable()->getVObj()->mGLName : 0; - LLColor4U color((U8)(name >> 16), (U8)(name >> 8), (U8)name, 0xff); - LLColor4 color_float(color); - - glColor4f(color_float.mV[0], color_float.mV[1], color_float.mV[2], 1.f); - } - else + if (!gRenderForSelect) { if ((mFace->getPool()->getVertexShaderLevel() > 0)) { @@ -1150,7 +572,6 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea ) stop_glerror(); -// LLGLSSpecular specular(mSpecular, gRenderForSelect ? 0.0f : mShiny); LLGLSSpecular specular(LLColor4(1.f,1.f,1.f,1.f), gRenderForSelect ? 0.0f : mShiny && !(mFace->getPool()->getVertexShaderLevel() > 0)); LLGLEnable texture_2d((gRenderForSelect && isTransparent()) ? GL_TEXTURE_2D : 0); @@ -1160,11 +581,6 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea ) //---------------------------------------------------------------- llassert( !(mTexture.notNull() && mLayerSet) ); // mutually exclusive - //GLuint test_image_name = 0; - - // - LLGLState force_alpha_test(GL_ALPHA_TEST, isTransparent()); - if (mTestImageName) { LLImageGL::bindExternalTexture( mTestImageName, 0, GL_TEXTURE_2D ); @@ -1217,11 +633,12 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea ) gImageList.getImage(IMG_DEFAULT_AVATAR)->bind(); } + LLGLDisable tex(gRenderForSelect && !isTransparent() ? GL_TEXTURE_2D : 0); + if (gRenderForSelect) { if (isTransparent()) { - //gGLSObjectSelectDepthAlpha.set(); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE); @@ -1232,19 +649,14 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea ) glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE); // GL_TEXTURE_ENV_COLOR is set in renderPass1 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA); } - else - { - //gGLSObjectSelectDepth.set(); - } } else { //---------------------------------------------------------------- // by default, backface culling is enabled //---------------------------------------------------------------- - if (sRenderPass == AVATAR_RENDER_PASS_CLOTHING_INNER) + /*if (sRenderPass == AVATAR_RENDER_PASS_CLOTHING_INNER) { - //LLGLSPipelineAvatar gls_pipeline_avatar; LLImageGL::bindExternalTexture( sClothingMaskImageName, 1, GL_TEXTURE_2D ); glClientActiveTextureARB(GL_TEXTURE0_ARB); @@ -1284,7 +696,6 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea ) } else if (sRenderPass == AVATAR_RENDER_PASS_CLOTHING_OUTER) { - //gGLSPipelineAvatarAlphaPass1.set(); glAlphaFunc(GL_GREATER, 0.1f); LLImageGL::bindExternalTexture( sClothingMaskImageName, 1, GL_TEXTURE_2D ); @@ -1315,81 +726,48 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea ) glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA); - } - else if ( isTransparent()) - { - //gGLSNoCullFaces.set(); - } - else - { - //gGLSCullFaces.set(); - } + }*/ } - if (mMesh->hasWeights()) - { - uploadJointMatrices(); + mFace->mVertexBuffer->setBuffer(sRenderMask); + U32 start = mMesh->mFaceVertexOffset; + U32 end = start + mMesh->mFaceVertexCount - 1; + U32 count = mMesh->mFaceIndexCount; + U32* indicesp = ((U32*) mFace->mVertexBuffer->getIndicesPointer()) + mMesh->mFaceIndexOffset; + if (mMesh->hasWeights()) + { if ((mFace->getPool()->getVertexShaderLevel() > 0)) { - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - - glDrawElements(GL_TRIANGLES, mMesh->mFaceIndexCount, GL_UNSIGNED_INT, mMesh->getIndices()); - - glPopMatrix(); + if (first_pass) + { + uploadJointMatrices(); + } + llDrawRangeElements(GL_TRIANGLES, start, end, count, GL_UNSIGNED_INT, indicesp); } else { - if (mFace->getGeomIndex() < 0) - { - llerrs << "Invalid geometry index in LLViewerJointMesh::drawShape() " << mFace->getGeomIndex() << llendl; - } - - if ((S32)(mMesh->mFaceVertexOffset + mMesh->mFaceVertexCount) > mFace->getGeomCount()) - { - ((LLVOAvatar*)mFace->getDrawable()->getVObj())->mRoot.dump(); - llerrs << "Rendering outside of vertex bounds with mesh " << mName << " at pixel area " << pixelArea << llendl; - } - llDrawElementsBatchBlend(mMesh->mFaceVertexOffset, mMesh->mFaceVertexCount, - mFace, mMesh->mFaceIndexCount, mMesh->getIndices()); + llDrawRangeElements(GL_TRIANGLES, start, end, count, GL_UNSIGNED_INT, indicesp); } - } else { glPushMatrix(); LLMatrix4 jointToWorld = getWorldMatrix(); - jointToWorld *= gCamera->getModelview(); - glLoadMatrixf((GLfloat*)jointToWorld.mMatrix); - - if ((mFace->getPool()->getVertexShaderLevel() > 0)) - { - glDrawElements(GL_TRIANGLES, mMesh->mFaceIndexCount, GL_UNSIGNED_INT, mMesh->getIndices()); - } - else // this else clause handles non-weighted vertices. llDrawElements just copies and draws - { - llDrawElements(mMesh->mFaceIndexCount, mMesh->getIndices(), mFace); - } - + glMultMatrixf((GLfloat*)jointToWorld.mMatrix); + llDrawRangeElements(GL_TRIANGLES, start, end, count, GL_UNSIGNED_INT, indicesp); glPopMatrix(); } triangle_count += mMesh->mFaceIndexCount; - - if (gRenderForSelect) - { - glColor4fv(mColor.mV); - } - + if (mTestImageName) { glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); } - if (sRenderPass != AVATAR_RENDER_PASS_SINGLE) + /*if (sRenderPass != AVATAR_RENDER_PASS_SINGLE) { LLImageGL::unbindTexture(1, GL_TEXTURE_2D); glActiveTextureARB(GL_TEXTURE1_ARB); @@ -1402,7 +780,7 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea ) glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE); glAlphaFunc(GL_GREATER, 0.01f); - } + }*/ if (mTexture.notNull()) { if (!mTexture->getClampS()) { @@ -1419,19 +797,20 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea ) //----------------------------------------------------------------------------- // updateFaceSizes() //----------------------------------------------------------------------------- -void LLViewerJointMesh::updateFaceSizes(U32 &num_vertices, F32 pixel_area) +void LLViewerJointMesh::updateFaceSizes(U32 &num_vertices, U32& num_indices, F32 pixel_area) { // Do a pre-alloc pass to determine sizes of data. if (mMesh && mValid) { mMesh->mFaceVertexOffset = num_vertices; mMesh->mFaceVertexCount = mMesh->getNumVertices(); + mMesh->mFaceIndexOffset = num_indices; + mMesh->mFaceIndexCount = mMesh->getSharedData()->mNumTriangleIndices; + mMesh->getReferenceMesh()->mCurVertexCount = mMesh->mFaceVertexCount; - num_vertices += mMesh->getNumVertices(); - mMesh->mFaceIndexCount = mMesh->getSharedData()->mNumTriangleIndices; - - mMesh->getSharedData()->genIndices(mMesh->mFaceVertexOffset); + num_vertices += mMesh->getNumVertices(); + num_indices += mMesh->mFaceIndexCount; } } @@ -1441,9 +820,7 @@ void LLViewerJointMesh::updateFaceSizes(U32 &num_vertices, F32 pixel_area) void LLViewerJointMesh::updateFaceData(LLFace *face, F32 pixel_area, BOOL damp_wind) { U32 i; - - if (!mValid) return; - + mFace = face; LLStrider<LLVector3> verticesp; @@ -1452,13 +829,15 @@ void LLViewerJointMesh::updateFaceData(LLFace *face, F32 pixel_area, BOOL damp_w LLStrider<LLVector2> tex_coordsp; LLStrider<F32> vertex_weightsp; LLStrider<LLVector4> clothing_weightsp; + LLStrider<U32> indicesp; // Copy data into the faces from the polymesh data. - if (mMesh) + if (mMesh && mValid) { if (mMesh->getNumVertices()) { S32 index = face->getGeometryAvatar(verticesp, normalsp, binormalsp, tex_coordsp, vertex_weightsp, clothing_weightsp); + face->mVertexBuffer->getIndexStrider(indicesp); if (-1 == index) { @@ -1474,11 +853,20 @@ void LLViewerJointMesh::updateFaceData(LLFace *face, F32 pixel_area, BOOL damp_w vertex_weightsp[mMesh->mFaceVertexOffset + i] = *(mMesh->getWeights() + i); if (damp_wind) { - clothing_weightsp[mMesh->mFaceVertexOffset + i].setVec(0,0,0,0); + clothing_weightsp[mMesh->mFaceVertexOffset + i] = LLVector4(0,0,0,0); } else { - clothing_weightsp[mMesh->mFaceVertexOffset + i].setVec(*(mMesh->getClothingWeights() + i)); + clothing_weightsp[mMesh->mFaceVertexOffset + i] = (*(mMesh->getClothingWeights() + i)); + } + } + + for (S32 i = 0; i < mMesh->getNumFaces(); i++) + { + for (U32 j = 0; j < 3; j++) + { + U32 k = i*3+j+mMesh->mFaceIndexOffset; + indicesp[k] = mMesh->getFaces()[i][j] + mMesh->mFaceVertexOffset; } } } @@ -1495,6 +883,92 @@ BOOL LLViewerJointMesh::updateLOD(F32 pixel_area, BOOL activate) return (valid != activate); } +void LLViewerJointMesh::updateGeometry() +{ + if (mValid && mMesh && mFace && + mMesh->hasWeights() && + mFace->mVertexBuffer.notNull() && + gPipeline.getVertexShaderLevel(LLPipeline::SHADER_AVATAR) == 0) + { + uploadJointMatrices(); + LLStrider<LLVector3> o_vertices; + LLStrider<LLVector3> o_normals; + + //get vertex and normal striders + LLVertexBuffer *buffer = mFace->mVertexBuffer; + buffer->getVertexStrider(o_vertices, 0); + buffer->getNormalStrider(o_normals, 0); + + { + LLVector4 tpos0, tnorm0, tpos1, tnorm1, tbinorm0, tbinorm1; + F32 last_weight = F32_MAX; + LLMatrix3 gBlendRotMat; + + + for (U32 index= 0; index < mMesh->getNumVertices(); index++) + { + // blend by first matrix + F32 w = mMesh->getWeights()[index]; + + if (w != last_weight) + { + last_weight = w; + + S32 joint = llfloor(w); + w -= joint; + + LLMatrix4 &m0 = gJointMat[joint+1]; + LLMatrix4 &m1 = gJointMat[joint+0]; + LLMatrix3 &n0 = gJointRot[joint+1]; + LLMatrix3 &n1 = gJointRot[joint+0]; + + if (w == 1.0f) + { + gBlendMat = m0; + gBlendRotMat = n0; + } + else + { + gBlendMat.mMatrix[VX][VX] = lerp(m1.mMatrix[VX][VX], m0.mMatrix[VX][VX], w); + gBlendMat.mMatrix[VX][VY] = lerp(m1.mMatrix[VX][VY], m0.mMatrix[VX][VY], w); + gBlendMat.mMatrix[VX][VZ] = lerp(m1.mMatrix[VX][VZ], m0.mMatrix[VX][VZ], w); + + gBlendMat.mMatrix[VY][VX] = lerp(m1.mMatrix[VY][VX], m0.mMatrix[VY][VX], w); + gBlendMat.mMatrix[VY][VY] = lerp(m1.mMatrix[VY][VY], m0.mMatrix[VY][VY], w); + gBlendMat.mMatrix[VY][VZ] = lerp(m1.mMatrix[VY][VZ], m0.mMatrix[VY][VZ], w); + + gBlendMat.mMatrix[VZ][VX] = lerp(m1.mMatrix[VZ][VX], m0.mMatrix[VZ][VX], w); + gBlendMat.mMatrix[VZ][VY] = lerp(m1.mMatrix[VZ][VY], m0.mMatrix[VZ][VY], w); + gBlendMat.mMatrix[VZ][VZ] = lerp(m1.mMatrix[VZ][VZ], m0.mMatrix[VZ][VZ], w); + + gBlendMat.mMatrix[VW][VX] = lerp(m1.mMatrix[VW][VX], m0.mMatrix[VW][VX], w); + gBlendMat.mMatrix[VW][VY] = lerp(m1.mMatrix[VW][VY], m0.mMatrix[VW][VY], w); + gBlendMat.mMatrix[VW][VZ] = lerp(m1.mMatrix[VW][VZ], m0.mMatrix[VW][VZ], w); + + gBlendRotMat.mMatrix[VX][VX] = lerp(n1.mMatrix[VX][VX], n0.mMatrix[VX][VX], w); + gBlendRotMat.mMatrix[VX][VY] = lerp(n1.mMatrix[VX][VY], n0.mMatrix[VX][VY], w); + gBlendRotMat.mMatrix[VX][VZ] = lerp(n1.mMatrix[VX][VZ], n0.mMatrix[VX][VZ], w); + + gBlendRotMat.mMatrix[VY][VX] = lerp(n1.mMatrix[VY][VX], n0.mMatrix[VY][VX], w); + gBlendRotMat.mMatrix[VY][VY] = lerp(n1.mMatrix[VY][VY], n0.mMatrix[VY][VY], w); + gBlendRotMat.mMatrix[VY][VZ] = lerp(n1.mMatrix[VY][VZ], n0.mMatrix[VY][VZ], w); + + gBlendRotMat.mMatrix[VZ][VX] = lerp(n1.mMatrix[VZ][VX], n0.mMatrix[VZ][VX], w); + gBlendRotMat.mMatrix[VZ][VY] = lerp(n1.mMatrix[VZ][VY], n0.mMatrix[VZ][VY], w); + gBlendRotMat.mMatrix[VZ][VZ] = lerp(n1.mMatrix[VZ][VZ], n0.mMatrix[VZ][VZ], w); + } + } + + // write result + U32 bidx = index + mMesh->mFaceVertexOffset; + + o_vertices[bidx] = mMesh->getCoords()[index] * gBlendMat; + o_normals[bidx] = mMesh->getNormals()[index] * gBlendRotMat; + } + } + } +} + void LLViewerJointMesh::dump() { if (mValid) diff --git a/indra/newview/llviewerjointmesh.h b/indra/newview/llviewerjointmesh.h index 963ad05595..b6fd8afcdb 100644 --- a/indra/newview/llviewerjointmesh.h +++ b/indra/newview/llviewerjointmesh.h @@ -114,11 +114,12 @@ public: // overloaded from base class /*virtual*/ void drawBone(); /*virtual*/ BOOL isTransparent(); - /*virtual*/ U32 drawShape( F32 pixelArea ); + /*virtual*/ U32 drawShape( F32 pixelArea, BOOL first_pass ); - /*virtual*/ void updateFaceSizes(U32 &num_vertices, F32 pixel_area); + /*virtual*/ void updateFaceSizes(U32 &num_vertices, U32& num_indices, F32 pixel_area); /*virtual*/ void updateFaceData(LLFace *face, F32 pixel_area, BOOL damp_wind = FALSE); /*virtual*/ BOOL updateLOD(F32 pixel_area, BOOL activate); + /*virtual*/ void updateGeometry(); /*virtual*/ void dump(); void setIsTransparent(BOOL is_transparent) { mIsTransparent = is_transparent; } diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index f6873c61b8..e9e98a4916 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -57,7 +57,6 @@ #include "lldir.h" #include "lldrawable.h" #include "lldrawpoolalpha.h" -#include "lldrawpoolhud.h" #include "lldrawpooltree.h" #include "llface.h" #include "llfirstuse.h" @@ -263,7 +262,6 @@ typedef LLMemberListener<LLView> view_listener_t; // // Local prototypes // -BOOL enable_attach(void*); void handle_leave_group(void *); // File Menu @@ -335,9 +333,6 @@ BOOL check_toggle_hacked_godmode(void*); void toggle_glow(void *); BOOL check_glow(void *); -void toggle_vbo(void *); -BOOL check_vbo(void *); - void toggle_vertex_shaders(void *); BOOL check_vertex_shaders(void *); @@ -758,6 +753,12 @@ void init_client_menu(LLMenuGL* menu) menu->append(new LLMenuItemToggleGL("Quiet Snapshots to Disk", &gQuietSnapshot)); + menu->append(new LLMenuItemCheckGL( "Compress Snapshots to Disk", + &menu_toggle_control, + NULL, + &menu_check_control, + (void*)"CompressSnapshotsToDisk")); + menu->append(new LLMenuItemCheckGL("Show Mouselook Crosshairs", &menu_toggle_control, NULL, @@ -880,6 +881,11 @@ void init_client_menu(LLMenuGL* menu) menu->append(new LLMenuItemToggleGL("Disable Camera Constraints", &LLViewerCamera::sDisableCameraConstraints)); + menu->append(new LLMenuItemCheckGL("Mouse Smoothing", + &menu_toggle_control, + NULL, + &menu_check_control, + (void*) "MouseSmooth")); menu->appendSeparator(); menu->append(new LLMenuItemCheckGL( "Console Window", @@ -1008,56 +1014,56 @@ void init_debug_rendering_menu(LLMenuGL* menu) menu->appendMenu(sub_menu); sub_menu->append(new LLMenuItemCheckGL("Simple", - &LLPipeline::toggleRenderType, NULL, - &LLPipeline::toggleRenderTypeControl, + &LLPipeline::toggleRenderTypeControl, NULL, + &LLPipeline::hasRenderTypeControl, (void*)LLPipeline::RENDER_TYPE_SIMPLE, '1', MASK_CONTROL|MASK_ALT|MASK_SHIFT)); sub_menu->append(new LLMenuItemCheckGL("Alpha", - &LLPipeline::toggleRenderType, NULL, - &LLPipeline::toggleRenderTypeControl, + &LLPipeline::toggleRenderTypeControl, NULL, + &LLPipeline::hasRenderTypeControl, (void*)LLPipeline::RENDER_TYPE_ALPHA, '2', MASK_CONTROL|MASK_ALT|MASK_SHIFT)); sub_menu->append(new LLMenuItemCheckGL("Tree", - &LLPipeline::toggleRenderType, NULL, - &LLPipeline::toggleRenderTypeControl, + &LLPipeline::toggleRenderTypeControl, NULL, + &LLPipeline::hasRenderTypeControl, (void*)LLPipeline::RENDER_TYPE_TREE, '3', MASK_CONTROL|MASK_ALT|MASK_SHIFT)); sub_menu->append(new LLMenuItemCheckGL("Character", - &LLPipeline::toggleRenderType, NULL, - &LLPipeline::toggleRenderTypeControl, + &LLPipeline::toggleRenderTypeControl, NULL, + &LLPipeline::hasRenderTypeControl, (void*)LLPipeline::RENDER_TYPE_AVATAR, '4', MASK_CONTROL|MASK_ALT|MASK_SHIFT)); sub_menu->append(new LLMenuItemCheckGL("SurfacePatch", - &LLPipeline::toggleRenderType, NULL, - &LLPipeline::toggleRenderTypeControl, + &LLPipeline::toggleRenderTypeControl, NULL, + &LLPipeline::hasRenderTypeControl, (void*)LLPipeline::RENDER_TYPE_TERRAIN, '5', MASK_CONTROL|MASK_ALT|MASK_SHIFT)); sub_menu->append(new LLMenuItemCheckGL("Sky", - &LLPipeline::toggleRenderType, NULL, - &LLPipeline::toggleRenderTypeControl, + &LLPipeline::toggleRenderTypeControl, NULL, + &LLPipeline::hasRenderTypeControl, (void*)LLPipeline::RENDER_TYPE_SKY, '6', MASK_CONTROL|MASK_ALT|MASK_SHIFT)); sub_menu->append(new LLMenuItemCheckGL("Water", - &LLPipeline::toggleRenderType, NULL, - &LLPipeline::toggleRenderTypeControl, + &LLPipeline::toggleRenderTypeControl, NULL, + &LLPipeline::hasRenderTypeControl, (void*)LLPipeline::RENDER_TYPE_WATER, '7', MASK_CONTROL|MASK_ALT|MASK_SHIFT)); sub_menu->append(new LLMenuItemCheckGL("Ground", - &LLPipeline::toggleRenderType, NULL, - &LLPipeline::toggleRenderTypeControl, + &LLPipeline::toggleRenderTypeControl, NULL, + &LLPipeline::hasRenderTypeControl, (void*)LLPipeline::RENDER_TYPE_GROUND, '8', MASK_CONTROL|MASK_ALT|MASK_SHIFT)); sub_menu->append(new LLMenuItemCheckGL("Volume", - &LLPipeline::toggleRenderType, NULL, - &LLPipeline::toggleRenderTypeControl, + &LLPipeline::toggleRenderTypeControl, NULL, + &LLPipeline::hasRenderTypeControl, (void*)LLPipeline::RENDER_TYPE_VOLUME, '9', MASK_CONTROL|MASK_ALT|MASK_SHIFT)); sub_menu->append(new LLMenuItemCheckGL("Grass", - &LLPipeline::toggleRenderType, NULL, - &LLPipeline::toggleRenderTypeControl, + &LLPipeline::toggleRenderTypeControl, NULL, + &LLPipeline::hasRenderTypeControl, (void*)LLPipeline::RENDER_TYPE_GRASS, '0', MASK_CONTROL|MASK_ALT|MASK_SHIFT)); sub_menu->append(new LLMenuItemCheckGL("Clouds", - &LLPipeline::toggleRenderType, NULL, - &LLPipeline::toggleRenderTypeControl, + &LLPipeline::toggleRenderTypeControl, NULL, + &LLPipeline::hasRenderTypeControl, (void*)LLPipeline::RENDER_TYPE_CLOUDS, '-', MASK_CONTROL|MASK_ALT| MASK_SHIFT)); sub_menu->append(new LLMenuItemCheckGL("Particles", - &LLPipeline::toggleRenderType, NULL, - &LLPipeline::toggleRenderTypeControl, + &LLPipeline::toggleRenderTypeControl, NULL, + &LLPipeline::hasRenderTypeControl, (void*)LLPipeline::RENDER_TYPE_PARTICLES, '=', MASK_CONTROL|MASK_ALT|MASK_SHIFT)); sub_menu->append(new LLMenuItemCheckGL("Bump", - &LLPipeline::toggleRenderType, NULL, - &LLPipeline::toggleRenderTypeControl, + &LLPipeline::toggleRenderTypeControl, NULL, + &LLPipeline::hasRenderTypeControl, (void*)LLPipeline::RENDER_TYPE_BUMP, '\\', MASK_CONTROL|MASK_ALT|MASK_SHIFT)); sub_menu->createJumpKeys(); sub_menu = new LLMenuGL("Features"); @@ -1078,6 +1084,10 @@ void init_debug_rendering_menu(LLMenuGL* menu) &LLPipeline::toggleRenderDebugFeature, NULL, &LLPipeline::toggleRenderDebugFeatureControl, (void*)LLPipeline::RENDER_DEBUG_FEATURE_DYNAMIC_TEXTURES, '4', MASK_ALT|MASK_CONTROL)); + sub_menu->append(new LLMenuItemCheckGL( "Foot Shadows", + &LLPipeline::toggleRenderDebugFeature, NULL, + &LLPipeline::toggleRenderDebugFeatureControl, + (void*)LLPipeline::RENDER_DEBUG_FEATURE_FOOT_SHADOWS, '5', MASK_ALT|MASK_CONTROL)); sub_menu->append(new LLMenuItemCheckGL("Fog", &LLPipeline::toggleRenderDebugFeature, NULL, &LLPipeline::toggleRenderDebugFeatureControl, @@ -1091,13 +1101,9 @@ void init_debug_rendering_menu(LLMenuGL* menu) &LLPipeline::toggleRenderDebugFeatureControl, (void*)LLPipeline::RENDER_DEBUG_FEATURE_FR_INFO, '8', MASK_ALT|MASK_CONTROL)); sub_menu->append(new LLMenuItemCheckGL( "Flexible Objects", - &LLPipeline::toggleRenderDebugFeature, NULL, + &LLPipeline::toggleRenderDebugFeature, NULL, &LLPipeline::toggleRenderDebugFeatureControl, (void*)LLPipeline::RENDER_DEBUG_FEATURE_FLEXIBLE, '9', MASK_ALT|MASK_CONTROL)); - sub_menu->append(new LLMenuItemCheckGL( "Chain Faces", - &LLPipeline::toggleRenderDebugFeature, NULL, - &LLPipeline::toggleRenderDebugFeatureControl, - (void*)LLPipeline::RENDER_DEBUG_FEATURE_CHAIN_FACES, '0', MASK_ALT|MASK_CONTROL)); sub_menu->createJumpKeys(); ///////////////////////////// @@ -1110,9 +1116,6 @@ void init_debug_rendering_menu(LLMenuGL* menu) sub_menu->append(new LLMenuItemCheckGL("Verify", &LLPipeline::toggleRenderDebug, NULL, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_VERIFY)); - sub_menu->append(new LLMenuItemCheckGL("AGP Map", &LLPipeline::toggleRenderDebug, NULL, - &LLPipeline::toggleRenderDebugControl, - (void*)LLPipeline::RENDER_DEBUG_AGP_MEM)); sub_menu->append(new LLMenuItemCheckGL("BBoxes", &LLPipeline::toggleRenderDebug, NULL, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_BBOXES)); @@ -1125,12 +1128,18 @@ void init_debug_rendering_menu(LLMenuGL* menu) sub_menu->append(new LLMenuItemCheckGL("Occlusion", &LLPipeline::toggleRenderDebug, NULL, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_OCCLUSION)); - sub_menu->append(new LLMenuItemCheckGL("Face Chains", &LLPipeline::toggleRenderDebug, NULL, - &LLPipeline::toggleRenderDebugControl, - (void*)LLPipeline::RENDER_DEBUG_FACE_CHAINS)); sub_menu->append(new LLMenuItemCheckGL("Texture Priority", &LLPipeline::toggleRenderDebug, NULL, &LLPipeline::toggleRenderDebugControl, - (void*)LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY)); + (void*)LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY)); + sub_menu->append(new LLMenuItemCheckGL("Texture Area (sqrt(A))",&LLPipeline::toggleRenderDebug, NULL, + &LLPipeline::toggleRenderDebugControl, + (void*)LLPipeline::RENDER_DEBUG_TEXTURE_AREA)); + sub_menu->append(new LLMenuItemCheckGL("Pick Render", &LLPipeline::toggleRenderDebug, NULL, + &LLPipeline::toggleRenderDebugControl, + (void*)LLPipeline::RENDER_DEBUG_PICKING)); + sub_menu->append(new LLMenuItemCheckGL("Particles", &LLPipeline::toggleRenderDebug, NULL, + &LLPipeline::toggleRenderDebugControl, + (void*)LLPipeline::RENDER_DEBUG_PARTICLES)); sub_menu->append(new LLMenuItemCheckGL("Composition", &LLPipeline::toggleRenderDebug, NULL, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_COMPOSITION)); @@ -1140,16 +1149,7 @@ void init_debug_rendering_menu(LLMenuGL* menu) sub_menu->append(new LLMenuItemCheckGL("LightTrace",&LLPipeline::toggleRenderDebug, NULL, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_LIGHT_TRACE)); - sub_menu->append(new LLMenuItemCheckGL("Pools", &LLPipeline::toggleRenderDebug, NULL, - &LLPipeline::toggleRenderDebugControl, - (void*)LLPipeline::RENDER_DEBUG_POOLS)); - sub_menu->append(new LLMenuItemCheckGL("Queues", &LLPipeline::toggleRenderDebug, NULL, - &LLPipeline::toggleRenderDebugControl, - (void*)LLPipeline::RENDER_DEBUG_QUEUES)); - sub_menu->append(new LLMenuItemCheckGL("Map", &LLPipeline::toggleRenderDebug, NULL, - LLPipeline::toggleRenderDebugControl, - (void*)LLPipeline::RENDER_DEBUG_MAP)); - + sub_menu->append(new LLMenuItemCheckGL("Show Depth Buffer", &menu_toggle_control, NULL, @@ -1174,8 +1174,6 @@ void init_debug_rendering_menu(LLMenuGL* menu) menu->appendSeparator(); menu->append(new LLMenuItemCheckGL("Axes", menu_toggle_control, NULL, menu_check_control, (void*)"ShowAxes")); - menu->append(new LLMenuItemCheckGL("Use VBO", toggle_vbo, NULL, check_vbo, NULL)); - menu->append(new LLMenuItemCheckGL("Light Glows", toggle_glow, NULL, check_glow, NULL)); // menu->append(new LLMenuItemCheckGL("Cull Small Objects", toggle_cull_small, NULL, menu_check_control, (void*)"RenderCullBySize")); menu->appendSeparator(); @@ -1200,6 +1198,19 @@ void init_debug_rendering_menu(LLMenuGL* menu) item = new LLMenuItemCheckGL("Disable Textures", menu_toggle_variable, NULL, menu_check_variable, (void*)&LLViewerImage::sDontLoadVolumeTextures); menu->append(item); +#ifndef LL_RELEASE_FOR_DOWNLOAD + item = new LLMenuItemCheckGL("HTTP Get Textures", menu_toggle_control, NULL, menu_check_control, (void*)"ImagePipelineUseHTTP"); + menu->append(item); +#endif + + item = new LLMenuItemCheckGL("Run Multiple Threads", menu_toggle_control, NULL, menu_check_control, (void*)"RunMultipleThreads"); + menu->append(item); + +#ifndef LL_RELEASE_FOR_DOWNLOAD + item = new LLMenuItemCheckGL("Dynamic Reflections", menu_toggle_control, NULL, menu_check_control, (void*)"RenderDynamicReflections"); + menu->append(item); +#endif + item = new LLMenuItemCheckGL("Cheesy Beacon", menu_toggle_control, NULL, menu_check_control, (void*)"CheesyBeacon"); menu->append(item); @@ -1256,10 +1267,6 @@ void init_debug_avatar_menu(LLMenuGL* menu) //menu->append(new LLMenuItemToggleGL("Show Attachment Points", &LLVOAvatar::sShowAttachmentPoints)); menu->append(new LLMenuItemToggleGL("Show Collision Plane", &LLVOAvatar::sShowFootPlane)); menu->append(new LLMenuItemToggleGL("Show Collision Skeleton", &LLVOAvatar::sShowCollisionVolumes)); - menu->append(new LLMenuItemToggleGL("Software Blending SSE", &gGLManager.mSoftwareBlendSSE)); -#if 0 // Removed since this feature doesn't actually work as of 1.9.1 --TomY - menu->append(new LLMenuItemToggleGL("Character Load Test", &LLVOAvatar::sAvatarLoadTest)); -#endif menu->append(new LLMenuItemToggleGL( "Display Agent Target", &LLAgent::sDebugDisplayTarget)); menu->append(new LLMenuItemToggleGL( "Debug Rotation", &gDebugAvatarRotation)); menu->append(new LLMenuItemCallGL("Dump Attachments", handle_dump_attachments)); @@ -1319,7 +1326,8 @@ void init_server_menu(LLMenuGL* menu) menu->appendMenu(sub); sub->append(new LLMenuItemCallGL( "Take Copy", - &force_take_copy, &enable_god_customer_service, NULL)); + &force_take_copy, &enable_god_customer_service, NULL, + 'O', MASK_SHIFT | MASK_ALT | MASK_CONTROL)); #ifdef _CORY_TESTING sub->append(new LLMenuItemCallGL( "Export Copy", &force_export_copy, NULL, NULL)); @@ -1509,37 +1517,6 @@ class LLObjectEnableReportAbuse : public view_listener_t } }; - -BOOL enable_attach(void*) -{ - // All root objects must be owned by agent. - LLObjectSelectionHandle selection = gSelectMgr->getSelection(); - BOOL rv = FALSE; - LLViewerObject* obj = selection->getFirstRootObject(); - if(obj) - { - rv = TRUE; - for(obj = selection->getFirstRootObject() ; obj != NULL; obj = selection->getNextRootObject()) - { - for (U32 child_num = 0; child_num < obj->mChildList.size(); child_num++ ) - { - LLViewerObject *child = obj->mChildList[child_num]; - if (child->isAvatar()) - { - return FALSE; - } - } - if(!obj->permMove()) - { - rv = FALSE; - break; - } - } - } - return rv; -} - - class LLObjectTouch : public view_listener_t { bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata) @@ -1886,7 +1863,7 @@ class LLSelfEnableRemoveAllAttachments : public view_listener_t attachmentp; attachmentp = avatarp->mAttachmentPoints.getNextData()) { - if (attachmentp->getObject(0)) + if (attachmentp->getObject()) { new_value = true; break; @@ -6096,15 +6073,6 @@ class LLToolsLookAtSelection : public view_listener_t } }; -/* -void handle_reset_rotation(void*) -{ - gSelectMgr->selectionResetRotation(); - - dialog_refresh_all(); -} -*/ - class LLAvatarAddFriend : public view_listener_t { bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata) @@ -6789,7 +6757,10 @@ private: LLViewerObject* selectedObject = sObjectSelection->getFirstRootObject(); if (selectedObject) { - LLViewerJointAttachment* attachment_point = gAgent.getAvatarObject()->mAttachmentPoints[userdata.asInteger()]; + S32 index = userdata.asInteger(); + LLViewerJointAttachment* attachment_point = index > 0 ? + gAgent.getAvatarObject()->mAttachmentPoints[index] : + NULL; confirm_replace_attachment(0, attachment_point); } return true; @@ -6830,7 +6801,7 @@ void handle_attach_to_avatar(void* user_data) { LLViewerJointAttachment *attachment = (LLViewerJointAttachment *)user_data; - if (attachment && attachment->getObject(0)) + if (attachment && attachment->getObject()) { gViewerWindow->alertXml("ReplaceAttachment", confirm_replace_attachment, user_data); } @@ -6921,7 +6892,7 @@ void handle_detach_from_avatar(void* user_data) { LLViewerJointAttachment *attachment = (LLViewerJointAttachment *)user_data; - LLViewerObject* attached_object = attachment->getObject(0); + LLViewerObject* attached_object = attachment->getObject(); if (attached_object) { @@ -6942,7 +6913,7 @@ void attach_label(LLString& label, void* user_data) if (attachmentp) { label = attachmentp->getName(); - if (attachmentp->getObject(0)) + if (attachmentp->getObject()) { LLViewerInventoryItem* itemp = gInventory.getItem(attachmentp->getItemID()); if (itemp) @@ -6959,7 +6930,7 @@ void detach_label(LLString& label, void* user_data) if (attachmentp) { label = attachmentp->getName(); - if (attachmentp->getObject(0)) + if (attachmentp->getObject()) { LLViewerInventoryItem* itemp = gInventory.getItem(attachmentp->getItemID()); if (itemp) @@ -7159,23 +7130,7 @@ class LLObjectEnableWear : public view_listener_t { bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata) { - bool new_value = false; - if (gSelectMgr) - { - LLObjectSelectionHandle selection = gSelectMgr->getSelection(); - LLViewerObject* first_root = selection->getFirstRootObject(); - if (first_root) - { - new_value = selection->getRootObjectCount() == 1 - && first_root->getPCode() == LL_PCODE_VOLUME - && first_root->permYouOwner() - && !((LLViewerObject*)selection->getFirstRootObject()->getRoot())->isAvatar() - && (first_root->getNVPair("AssetContainer") == NULL); - } - } - - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); - return true; + return object_selected_and_point_valid(NULL); } }; @@ -7184,7 +7139,7 @@ BOOL object_attached(void *user_data) { LLViewerJointAttachment *attachment = (LLViewerJointAttachment *)user_data; - return attachment->getObject(0) != NULL; + return attachment->getObject() != NULL; } class LLAvatarSendIM : public view_listener_t @@ -7481,16 +7436,16 @@ void handle_dump_attachments(void*) attachment = avatar->mAttachmentPoints.getNextData() ) { S32 key = avatar->mAttachmentPoints.getCurrentKeyWithoutIncrement(); - BOOL visible = (attachment->getObject(0) != NULL && - attachment->getObject(0)->mDrawable.notNull() && - !attachment->getObject(0)->mDrawable->isRenderType(0)); + BOOL visible = (attachment->getObject() != NULL && + attachment->getObject()->mDrawable.notNull() && + !attachment->getObject()->mDrawable->isRenderType(0)); LLVector3 pos; - if (visible) pos = attachment->getObject(0)->mDrawable->getPosition(); + if (visible) pos = attachment->getObject()->mDrawable->getPosition(); llinfos << "ATTACHMENT " << key << ": item_id=" << attachment->getItemID() - << (attachment->getObject(0) ? " present " : " absent ") + << (attachment->getObject() ? " present " : " absent ") << (visible ? "visible " : "invisible ") << " at " << pos - << " and " << (visible ? attachment->getObject(0)->getPosition() : LLVector3::zero) + << " and " << (visible ? attachment->getObject()->getPosition() : LLVector3::zero) << llendl; } } @@ -7873,26 +7828,6 @@ BOOL enable_god_basic(void*) return gAgent.getGodLevel() > GOD_NOT; } -void toggle_vbo(void *) -{ - gPipeline.mUseVBO = !gPipeline.mUseVBO; - - if (!gPipeline.usingAGP()) - { - return; - } - - gPipeline.setUseAGP(FALSE); - gPipeline.setUseAGP(TRUE); - - gSavedSettings.setBOOL("RenderUseVBO", gPipeline.mUseVBO); -} - -BOOL check_vbo(void *) -{ - return gPipeline.mUseVBO; -} - #if 0 // 1.9.2 void toggle_vertex_shaders(void *) { @@ -7906,19 +7841,6 @@ BOOL check_vertex_shaders(void *) } #endif -void toggle_glow(void *) -{ - gRenderLightGlows = !gRenderLightGlows; - - gSavedSettings.setBOOL("RenderLightGlows", gRenderLightGlows); -} - -BOOL check_glow(void *) -{ - return gRenderLightGlows; -} - - void toggle_show_xui_names(void *) { BOOL showXUINames = gSavedSettings.getBOOL("ShowXUINames"); @@ -8428,7 +8350,7 @@ class LLViewToggleRenderType : public view_listener_t LLString type = userdata.asString(); if (type == "particles") { - LLPipeline::toggleRenderType((void *)(S32)LLPipeline::RENDER_TYPE_PARTICLES); + LLPipeline::toggleRenderType(LLPipeline::RENDER_TYPE_PARTICLES); } return true; } @@ -8449,12 +8371,11 @@ class LLViewCheckRenderType : public view_listener_t } }; -// TomY TODO: Get rid of these? class LLViewShowHUDAttachments : public view_listener_t { bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata) { - LLDrawPoolHUD::sShowHUDAttachments = !LLDrawPoolHUD::sShowHUDAttachments; + LLPipeline::sShowHUDAttachments = !LLPipeline::sShowHUDAttachments; return true; } }; @@ -8463,7 +8384,7 @@ class LLViewCheckHUDAttachments : public view_listener_t { bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata) { - bool new_value = LLDrawPoolHUD::sShowHUDAttachments; + bool new_value = LLPipeline::sShowHUDAttachments; gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); return true; } diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index e1f51586f4..8ed5406e85 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -2893,7 +2893,8 @@ void send_agent_update(BOOL force_send, BOOL send_reliable) extern U32 gObjectBits; void process_object_update(LLMessageSystem *mesgsys, void **user_data) -{ +{ + LLMemType mt(LLMemType::MTYPE_OBJECT); // Update the data counters if (mesgsys->getReceiveCompressedSize()) { @@ -2911,6 +2912,7 @@ void process_object_update(LLMessageSystem *mesgsys, void **user_data) void process_compressed_object_update(LLMessageSystem *mesgsys, void **user_data) { + LLMemType mt(LLMemType::MTYPE_OBJECT); // Update the data counters if (mesgsys->getReceiveCompressedSize()) { @@ -2928,6 +2930,7 @@ void process_compressed_object_update(LLMessageSystem *mesgsys, void **user_data void process_cached_object_update(LLMessageSystem *mesgsys, void **user_data) { + LLMemType mt(LLMemType::MTYPE_OBJECT); // Update the data counters if (mesgsys->getReceiveCompressedSize()) { @@ -2946,6 +2949,7 @@ void process_cached_object_update(LLMessageSystem *mesgsys, void **user_data) void process_terse_object_update_improved(LLMessageSystem *mesgsys, void **user_data) { + LLMemType mt(LLMemType::MTYPE_OBJECT); if (mesgsys->getReceiveCompressedSize()) { gObjectBits += mesgsys->getReceiveCompressedSize() * 8; diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 1ff2d81b0c..615bc1bf4f 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -68,7 +68,6 @@ #include "llvosurfacepatch.h" #include "llvotextbubble.h" #include "llvotree.h" -#include "llvotreenew.h" #include "llvovolume.h" #include "llvowater.h" #include "llworld.h" @@ -112,7 +111,6 @@ LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pco case LL_PCODE_TREE_NEW: llwarns << "Creating new tree!" << llendl; // res = new LLVOTree(id, pcode, regionp); break; -// res = new LLVOTreeNew(id, pcode, regionp); break; res = NULL; break; case LL_PCODE_LEGACY_TEXT_BUBBLE: res = new LLVOTextBubble(id, pcode, regionp); break; @@ -154,10 +152,11 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe mText(), mLastInterpUpdateSecs(0.f), mLastMessageUpdateSecs(0.f), + mLatestRecvPacketID(0), mData(NULL), mAudioSourcep(NULL), mAppAngle(0.f), - mPixelArea(0.f), + mPixelArea(1024.f), mInventory(NULL), mInventorySerialNum(0), mRegionp( regionp ), @@ -169,7 +168,6 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe mOnActiveList(FALSE), mOnMap(FALSE), mStatic(FALSE), - mFaceIndexOffset(0), mNumFaces(0), mLastUpdateFrame(0), mTimeDilation(1.f), @@ -349,10 +347,12 @@ void LLViewerObject::dump() const llinfos << "Velocity: " << getVelocity() << llendl; if (mDrawable.notNull() && mDrawable->getNumFaces()) { - LLDrawPool *poolp = mDrawable->getFace(0)->getPool(); - llinfos << "Pool: " << poolp << llendl; - llinfos << "Pool reference count: " << poolp->mReferences.size() << llendl; - llinfos << "Pool vertex count: " << poolp->getVertexCount() << llendl; + LLFacePool *poolp = mDrawable->getFace(0)->getPool(); + if (poolp) + { + llinfos << "Pool: " << poolp << llendl; + llinfos << "Pool reference count: " << poolp->mReferences.size() << llendl; + } } //llinfos << "BoxTree Min: " << mDrawable->getBox()->getMin() << llendl; //llinfos << "BoxTree Max: " << mDrawable->getBox()->getMin() << llendl; @@ -596,11 +596,24 @@ BOOL LLViewerObject::setDrawableParent(LLDrawable* parentp) return FALSE; } + LLDrawable* old_parent = mDrawable->mParent; + mDrawable->mParent = parentp; BOOL ret = mDrawable->mXform.setParent(parentp ? &parentp->mXform : NULL); gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE); - gPipeline.markMoved(mDrawable, FALSE); + if (old_parent || (parentp && parentp->isActive())) + { + gPipeline.markMoved(mDrawable, FALSE); + } + else + { + mDrawable->updateXform(TRUE); + if (!mDrawable->getSpatialGroup()) + { + mDrawable->movePartition(); + } + } return ret; } @@ -655,7 +668,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, LLVector3 new_acc; LLVector3 new_angv; LLQuaternion new_rot; - LLVector3 new_scale; + LLVector3 new_scale = getScale(); U32 parent_id = 0; U8 material = 0; @@ -881,13 +894,6 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, // ...new objects that should come in selected need to be added to the selected list mCreateSelected = ((flags & FLAGS_CREATE_SELECTED) != 0); - // Set the change flags for scale - if (new_scale != getScale()) - { - setChanged(SCALED | SILHOUETTE); - setScale(new_scale); // Must follow setting permYouOwner() - } - // Set all name value pairs S32 nv_size = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_NameValue); if (nv_size > 0) @@ -1465,14 +1471,6 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, // ...new objects that should come in selected need to be added to the selected list mCreateSelected = ((flags & FLAGS_CREATE_SELECTED) != 0); - - // Set the change flags for scale - if (new_scale != getScale()) - { - setChanged(SCALED | SILHOUETTE); - setScale(new_scale); // Must follow setting permYouOwner() - } - } break; @@ -1744,6 +1742,23 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, // // + U32 packet_id = mesgsys->getCurrentRecvPacketID(); + if (packet_id < mLatestRecvPacketID && + mLatestRecvPacketID - packet_id < 65536) + { + //skip application of this message, it's old + return retval; + } + + mLatestRecvPacketID = packet_id; + + // Set the change flags for scale + if (new_scale != getScale()) + { + setChanged(SCALED | SILHOUETTE); + setScale(new_scale); // Must follow setting permYouOwner() + } + // first, let's see if the new position is actually a change //static S32 counter = 0; @@ -1771,14 +1786,10 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, if (new_rot != mLastRot) { - // if (getAngularVelocity().isExactlyZero() || - // new_angv != getAngularVelocity()) - { - mLastRot = new_rot; - setChanged(ROTATED | SILHOUETTE); - setRotation(new_rot); - resetRot(); - } + mLastRot = new_rot; + setChanged(ROTATED | SILHOUETTE); + setRotation(new_rot); + resetRot(); } @@ -2625,6 +2636,11 @@ BOOL LLViewerObject::updateGeometry(LLDrawable *drawable) return TRUE; } +void LLViewerObject::updateFaceSize(S32 idx) +{ + +} + LLDrawable* LLViewerObject::createDrawable(LLPipeline *pipeline) { return NULL; @@ -2665,13 +2681,23 @@ void LLViewerObject::setScale(const LLVector3 &scale, BOOL damped) void LLViewerObject::updateSpatialExtents(LLVector3& newMin, LLVector3 &newMax) { LLVector3 center = getRenderPosition(); - F32 sz = llmin(mDrawable->getRadius(), 256.f); - LLVector3 size = LLVector3(sz,sz,sz); + LLVector3 size = getScale(); newMin.setVec(center-size); newMax.setVec(center+size); mDrawable->setPositionGroup((newMin + newMax) * 0.5f); } +F32 LLViewerObject::getBinRadius() +{ + if (mDrawable.notNull()) + { + const LLVector3* ext = mDrawable->getSpatialExtents(); + return (ext[1]-ext[0]).magVec(); + } + + return getScale().magVec(); +} + F32 LLViewerObject::getMaxScale() const { return llmax(getScale().mV[VX],getScale().mV[VY], getScale().mV[VZ]); @@ -3574,11 +3600,6 @@ S32 LLViewerObject::setTETexGen(const U8 te, const U8 texgen) { retval = LLPrimitive::setTETexGen(te, texgen); setChanged(TEXTURE); - if (mDrawable.notNull() && retval) - { - gPipeline.markTextured(mDrawable); - gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE); - } } return retval; } @@ -3595,11 +3616,6 @@ S32 LLViewerObject::setTEShiny(const U8 te, const U8 shiny) { retval = LLPrimitive::setTEShiny(te, shiny); setChanged(TEXTURE); - if (mDrawable.notNull() && retval) - { - gPipeline.markTextured(mDrawable); - gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, TRUE); - } } return retval; } @@ -3744,7 +3760,7 @@ LLViewerImage *LLViewerObject::getTEImage(const U8 face) const } } - llerrs << "Requested invalid face!" << llendl; + llerrs << llformat("Requested Image from invalid face: %d/%d",face,getNumTEs()) << llendl; return NULL; } @@ -3838,6 +3854,11 @@ void LLViewerObject::setCanSelect(BOOL canSelect) void LLViewerObject::setDebugText(const std::string &utf8text) { + if (utf8text.empty() && !mText) + { + return; + } + if (!mText) { mText = (LLHUDText *)LLHUDObject::addHUDObject(LLHUDObject::LL_HUD_TEXT); @@ -4558,6 +4579,7 @@ void LLViewerObject::markForUpdate(BOOL priority) void LLViewerObject::setRegion(LLViewerRegion *regionp) { llassert(regionp); + mLatestRecvPacketID = 0; mRegionp = regionp; setChanged(MOVED | SILHOUETTE); updateDrawable(FALSE); @@ -4646,3 +4668,30 @@ void LLViewerObject::resetRot() { mRotTime = 0.0f; } + +U32 LLViewerObject::getPartitionType() const +{ + return LLPipeline::PARTITION_NONE; +} + +BOOL LLAlphaObject::isParticle() +{ + return FALSE; +} + +F32 LLAlphaObject::getPartSize(S32 idx) +{ + return 0.f; +} + +// virtual +void LLStaticViewerObject::updateDrawable(BOOL force_damped) +{ + // Force an immediate rebuild on any update + if (mDrawable.notNull()) + { + mDrawable->updateXform(TRUE); + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE); + } + clearChanged(SHIFTED); +} diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index 285d684dc6..d8b5a14897 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -18,6 +18,7 @@ #include "llhudicon.h" #include "llinventory.h" #include "llmemory.h" +#include "llmemtype.h" #include "llprimitive.h" #include "lluuid.h" #include "llvoinventorylistener.h" @@ -25,6 +26,7 @@ #include "llquaternion.h" #include "v3dmath.h" #include "v3math.h" +#include "llvertexbuffer.h" class LLAgent; // TODO: Get rid of this. class LLAudioSource; @@ -168,6 +170,7 @@ public: virtual LLDrawable* createDrawable(LLPipeline *pipeline); virtual BOOL updateGeometry(LLDrawable *drawable); + virtual void updateFaceSize(S32 idx); virtual BOOL updateLOD(); virtual BOOL setDrawableParent(LLDrawable* parentp); virtual BOOL updateLighting(BOOL do_lighting) { return TRUE; }; @@ -184,7 +187,7 @@ public: LLViewerRegion* getRegion() const { return mRegionp; } BOOL isSelected() const { return mUserSelected; } - void setSelected(BOOL sel) { mUserSelected = sel; mRotTime = 0.f;} + virtual void setSelected(BOOL sel) { mUserSelected = sel; mRotTime = 0.f;} const LLUUID &getID() const { return mID; } U32 getLocalID() const { return mLocalID; } @@ -274,8 +277,6 @@ public: /*virtual*/ BOOL setMaterial(const U8 material); virtual void setTEImage(const U8 te, LLViewerImage *imagep); // Not derived from LLPrimitive LLViewerImage *getTEImage(const U8 te) const; - - S32 getFaceIndexOffset() { return mFaceIndexOffset; } void fitFaceTexture(const U8 face); void sendTEUpdate() const; // Sends packed representation of all texture entry information @@ -288,6 +289,8 @@ public: U8 getState() { return mState; } F32 getAppAngle() const { return mAppAngle; } + F32 getPixelArea() const { return mPixelArea; } + void setPixelArea(F32 area) { mPixelArea = area; } F32 getMaxScale() const; F32 getMidScale() const; F32 getMinScale() const; @@ -320,6 +323,7 @@ public: void markForUpdate(BOOL priority); void updateVolume(const LLVolumeParams& volume_params); virtual void updateSpatialExtents(LLVector3& min, LLVector3& max); + virtual F32 getBinRadius(); LLBBox getBoundingBoxAgent() const; @@ -417,6 +421,7 @@ public: void printNameValuePairs() const; virtual S32 getLOD() const { return 3; } + virtual U32 getPartitionType() const; virtual LLNetworkData* getParameterEntry(U16 param_type) const; virtual bool setParameterEntry(U16 param_type, const LLNetworkData& new_value, bool local_origin); @@ -528,7 +533,7 @@ protected: F64 mLastInterpUpdateSecs; // Last update for purposes of interpolation F64 mLastMessageUpdateSecs; // Last update from a message from the simulator - + TPACKETID mLatestRecvPacketID; // Latest time stamp on message from simulator // extra data sent from the sim...currently only used for tree species info U8* mData; @@ -559,7 +564,6 @@ protected: BOOL mOnActiveList; BOOL mOnMap; // On the map. BOOL mStatic; // Object doesn't move. - S32 mFaceIndexOffset; // offset into drawable's faces, zero except in special cases S32 mNumFaces; S32 mLastUpdateFrame; // frames in which an object had last moved for smart coalescing of drawables @@ -592,7 +596,6 @@ private: static S32 sNumObjects; }; - /////////////////// // // Inlines @@ -623,4 +626,34 @@ public: U8 mMediaType; // see LLTextureEntry::WEB_PAGE, etc. }; +// subclass of viewer object that can be added to particle partitions +class LLAlphaObject : public LLViewerObject +{ +public: + LLAlphaObject(const LLUUID &id, const LLPCode type, LLViewerRegion *regionp) + : LLViewerObject(id,type,regionp) + { mDepth = 0.f; } + + virtual BOOL isParticle(); + virtual F32 getPartSize(S32 idx); + virtual void getGeometry(S32 idx, + LLStrider<LLVector3>& verticesp, + LLStrider<LLVector3>& normalsp, + LLStrider<LLVector2>& texcoordsp, + LLStrider<LLColor4U>& colorsp, + LLStrider<U32>& indicesp) = 0; + + F32 mDepth; +}; + +class LLStaticViewerObject : public LLViewerObject +{ +public: + LLStaticViewerObject(const LLUUID& id, const LLPCode type, LLViewerRegion* regionp) + : LLViewerObject(id,type,regionp) + { } + + virtual void updateDrawable(BOOL force_damped); +}; + #endif diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index f4c733299f..68193604bb 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -731,6 +731,15 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world) mNumVisCulledStat.addValue(mNumVisCulled); } +void LLViewerObjectList::clearDebugText() +{ + for (S32 i = 0; i < mObjects.count(); i++) + { + mObjects[i]->setDebugText(""); + } +} + + void LLViewerObjectList::cleanupReferences(LLViewerObject *objectp) { LLMemType mt(LLMemType::MTYPE_OBJECT); @@ -1052,7 +1061,15 @@ U32 LLViewerObjectList::renderObjectsForSelect(LLCamera &camera, BOOL pick_parce mSelectPickList.clear(); std::vector<LLDrawable*> pick_drawables; - gPipeline.mObjectPartition->cull(camera, &pick_drawables, TRUE); + + for (i = 0; i < LLPipeline::NUM_PARTITIONS-1; i++) + { + LLSpatialPartition* part = gPipeline.getSpatialPartition(i); + if (part) + { + part->cull(camera, &pick_drawables, TRUE); + } + } for (std::vector<LLDrawable*>::iterator iter = pick_drawables.begin(); iter != pick_drawables.end(); iter++) @@ -1074,10 +1091,10 @@ U32 LLViewerObjectList::renderObjectsForSelect(LLCamera &camera, BOOL pick_parce LLHUDText::addPickable(mSelectPickList); - for (objectp = (LLVOAvatar*)LLCharacter::sInstances.getFirstData(); - objectp; - objectp = (LLVOAvatar*)LLCharacter::sInstances.getNextData()) + for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin(); + iter != LLCharacter::sInstances.end(); ++iter) { + objectp = (LLVOAvatar*) *iter; if (!objectp->isDead()) { if (objectp->mDrawable.notNull() && objectp->mDrawable->isVisible()) @@ -1098,7 +1115,7 @@ U32 LLViewerObjectList::renderObjectsForSelect(LLCamera &camera, BOOL pick_parce { if (attachmentp->getIsHUDAttachment()) { - LLViewerObject* objectp = attachmentp->getObject(0); + LLViewerObject* objectp = attachmentp->getObject(); if (objectp) { mSelectPickList.insert(objectp); @@ -1114,32 +1131,36 @@ U32 LLViewerObjectList::renderObjectsForSelect(LLCamera &camera, BOOL pick_parce } } } - + S32 num_pickables = (S32)mSelectPickList.size() + LLHUDIcon::getNumInstances(); - S32 step = (0x000fffff - GL_NAME_INDEX_OFFSET) / num_pickables; - - std::set<LLViewerObject*>::iterator pick_it; - i = 0; - for (pick_it = mSelectPickList.begin(); pick_it != mSelectPickList.end();) + if (num_pickables != 0) { - LLViewerObject* objp = (*pick_it); - if (!objp || objp->isDead() || !objp->mbCanSelect) + S32 step = (0x000fffff - GL_NAME_INDEX_OFFSET) / num_pickables; + + std::set<LLViewerObject*>::iterator pick_it; + i = 0; + for (pick_it = mSelectPickList.begin(); pick_it != mSelectPickList.end();) { - mSelectPickList.erase(pick_it++); - continue; + LLViewerObject* objp = (*pick_it); + if (!objp || objp->isDead() || !objp->mbCanSelect) + { + mSelectPickList.erase(pick_it++); + continue; + } + + objp->mGLName = (i * step) + GL_NAME_INDEX_OFFSET; + i++; + ++pick_it; } - objp->mGLName = (i * step) + GL_NAME_INDEX_OFFSET; - i++; - ++pick_it; + LLHUDIcon::generatePickIDs(i * step, step); + + // At this point, we should only have live drawables/viewer objects + gPipeline.renderForSelect(mSelectPickList); } - - LLHUDIcon::generatePickIDs(i * step, step); } - // At this point, we should only have live drawables/viewer objects - gPipeline.renderForSelect(); // // Render pass for selected objects // @@ -1432,6 +1453,7 @@ void LLViewerObjectList::findOrphans(LLViewerObject* objectp, U32 ip, U32 port) } } +//////////////////////////////////////////////////////////////////////////// LLViewerObjectList::OrphanInfo::OrphanInfo() { diff --git a/indra/newview/llviewerobjectlist.h b/indra/newview/llviewerobjectlist.h index a2893c4b7d..3e148c822f 100644 --- a/indra/newview/llviewerobjectlist.h +++ b/indra/newview/llviewerobjectlist.h @@ -96,6 +96,7 @@ public: void addToMap(LLViewerObject *objectp); void removeFromMap(LLViewerObject *objectp); + void clearDebugText(); //////////////////////////////////////////// // diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp index c1d2f2742e..cd915317ba 100644 --- a/indra/newview/llviewerparcelmgr.cpp +++ b/indra/newview/llviewerparcelmgr.cpp @@ -1552,7 +1552,7 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use gParcelMgr->resetSegments(gParcelMgr->mHighlightSegments); gParcelMgr->writeSegmentsFromBitmap( bitmap, gParcelMgr->mHighlightSegments ); - delete bitmap; + delete[] bitmap; bitmap = NULL; gParcelMgr->mCurrentParcelSelection->mWholeParcelSelected = TRUE; @@ -1604,7 +1604,7 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use gParcelMgr->resetSegments(gParcelMgr->mCollisionSegments); gParcelMgr->writeSegmentsFromBitmap( bitmap, gParcelMgr->mCollisionSegments ); - delete bitmap; + delete[] bitmap; bitmap = NULL; } @@ -1753,10 +1753,10 @@ void optionally_start_music(const LLString& music_url) { if (gSavedSettings.getWarning("FirstStreamingMusic")) { - void* data = (void*)strdup(music_url.c_str()); + std::string* newstring = new std::string(music_url); gViewerWindow->alertXml("ParcelCanPlayMusic", callback_start_music, - (void*)data); + (void*)newstring); } else if (gSavedSettings.getBOOL("AudioStreamingMusic")) @@ -1779,7 +1779,7 @@ void optionally_start_music(const LLString& music_url) void callback_start_music(S32 option, void* data) { - const char* music_url = (const char*)data; + std::string* music_url = (std::string*)data; if (0 == option) { @@ -1787,7 +1787,7 @@ void callback_start_music(S32 option, void* data) llinfos << "Starting first parcel music " << music_url << llendl; if (gAudiop) { - gAudiop->startInternetStream(music_url); + gAudiop->startInternetStream(music_url->c_str()); LLMediaRemoteCtrl* ctrl = gOverlayBar->getMusicRemoteControl(); ctrl->setTransportState( LLMediaRemoteCtrl::Play, FALSE ); } @@ -1799,7 +1799,7 @@ void callback_start_music(S32 option, void* data) gSavedSettings.setWarning("FirstStreamingMusic", FALSE); - delete [] music_url; + delete music_url; music_url = NULL; } diff --git a/indra/newview/llviewerparceloverlay.cpp b/indra/newview/llviewerparceloverlay.cpp index a159bacd16..f5d7aa1094 100644 --- a/indra/newview/llviewerparceloverlay.cpp +++ b/indra/newview/llviewerparceloverlay.cpp @@ -761,27 +761,6 @@ S32 LLViewerParcelOverlay::renderPropertyLines () const S32 GRID_STEP = S32( PARCEL_GRID_STEP_METERS ); const S32 vertex_per_edge = 3 + 2 * (GRID_STEP-1) + 3; - /* JC - Don't do this. Unbinding AGP stalls the draw process, - dropping frame rate. Not unbinding AGP causes random crashes - on nVidia cards due to binding non-AGP arrays. - - gPipeline.unbindAGP(); - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, mVertexArray ); - glColorPointer( 4, GL_UNSIGNED_BYTE, 0, mColorArray ); - - S32 i; - for (i = 0; i < mVertexCount; i += vertex_per_edge) - { - // Each edge is several vertices - glDrawArrays(GL_LINE_STRIP, i, vertex_per_edge); - } - - glDisableClientState(GL_COLOR_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); - */ - // Stomp the camera into two dimensions LLVector3 camera_region = mRegion->getPosRegionFromGlobal( gAgent.getCameraPositionGlobal() ); diff --git a/indra/newview/llviewerpartsim.cpp b/indra/newview/llviewerpartsim.cpp index db18b74d1f..a6895aff2f 100644 --- a/indra/newview/llviewerpartsim.cpp +++ b/indra/newview/llviewerpartsim.cpp @@ -13,6 +13,7 @@ #include "llviewercontrol.h" #include "llagent.h" +#include "llviewercamera.h" #include "llviewerobjectlist.h" #include "llviewerpartsource.h" #include "llviewerregion.h" @@ -22,7 +23,7 @@ const S32 MAX_PART_COUNT = 4096; -const F32 PART_SIM_BOX_SIDE = 32.f; +const F32 PART_SIM_BOX_SIDE = 16.f; const F32 PART_SIM_BOX_OFFSET = 0.5f*PART_SIM_BOX_SIDE; const F32 PART_SIM_BOX_RAD = 0.5f*F_SQRT3*PART_SIM_BOX_SIDE; @@ -33,18 +34,28 @@ S32 LLViewerPartSim::sParticleCount = 0; U32 LLViewerPart::sNextPartID = 1; +F32 calc_desired_size(LLVector3 pos, LLVector2 scale) +{ + F32 desired_size = (pos-gCamera->getOrigin()).magVec(); + desired_size /= 4; + return llclamp(desired_size, scale.magVec()*0.5f, PART_SIM_BOX_SIDE*2); +} + LLViewerPart::LLViewerPart() { + LLMemType mt(LLMemType::MTYPE_PARTICLES); mPartSourcep = NULL; } LLViewerPart::~LLViewerPart() { + LLMemType mt(LLMemType::MTYPE_PARTICLES); mPartSourcep = NULL; } LLViewerPart &LLViewerPart::operator=(const LLViewerPart &part) { + LLMemType mt(LLMemType::MTYPE_PARTICLES); mPartID = part.mPartID; mFlags = part.mFlags; mMaxAge = part.mMaxAge; @@ -74,6 +85,7 @@ LLViewerPart &LLViewerPart::operator=(const LLViewerPart &part) void LLViewerPart::init(LLViewerPartSource *sourcep, LLViewerImage *imagep, LLVPCallback cb) { + LLMemType mt(LLMemType::MTYPE_PARTICLES); mPartID = LLViewerPart::sNextPartID; LLViewerPart::sNextPartID++; mFlags = 0x00f; @@ -96,8 +108,13 @@ void LLViewerPart::init(LLViewerPartSource *sourcep, LLViewerImage *imagep, LLVP LLViewerPartGroup::LLViewerPartGroup(const LLVector3 ¢er_agent, const F32 box_side) { + LLMemType mt(LLMemType::MTYPE_PARTICLES); mVOPartGroupp = NULL; + mUniformParticles = TRUE; + mRegionp = gWorldPointer->getRegionFromPosAgent(center_agent); + llassert_always(center_agent.isFinite()); + if (!mRegionp) { //llwarns << "No region at position, using agent region!" << llendl; @@ -106,28 +123,39 @@ LLViewerPartGroup::LLViewerPartGroup(const LLVector3 ¢er_agent, const F32 bo mCenterAgent = center_agent; mBoxRadius = F_SQRT3*box_side*0.5f; - LLVector3 rad_vec(box_side*0.5f, box_side*0.5f, box_side*0.5f); - rad_vec += LLVector3(0.001f, 0.001f, 0.001f); - mMinObjPos = mCenterAgent - rad_vec; - mMaxObjPos = mCenterAgent + rad_vec; + mVOPartGroupp = (LLVOPartGroup *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_PART_GROUP, getRegion()); + mVOPartGroupp->setViewerPartGroup(this); + mVOPartGroupp->setPositionAgent(getCenterAgent()); + F32 scale = box_side * 0.5f; + mVOPartGroupp->setScale(LLVector3(scale,scale,scale)); + gPipeline.addObject(mVOPartGroupp); + + LLSpatialGroup* group = mVOPartGroupp->mDrawable->getSpatialGroup(); + + LLVector3 center(group->mOctreeNode->getCenter()); + LLVector3 size(group->mOctreeNode->getSize()); + size += LLVector3(0.01f, 0.01f, 0.01f); + mMinObjPos = center - size; + mMaxObjPos = center + size; + + static U32 id_seed = 0; + mID = ++id_seed; } LLViewerPartGroup::~LLViewerPartGroup() { + LLMemType mt(LLMemType::MTYPE_PARTICLES); cleanup(); - S32 count = mParticles.count(); - S32 i; - - for (i = 0; i < count; i++) - { - mParticles[i].mPartSourcep = NULL; - } - mParticles.reset(); + + S32 count = (S32) mParticles.size(); + mParticles.clear(); + LLViewerPartSim::decPartCount(count); } void LLViewerPartGroup::cleanup() { + LLMemType mt(LLMemType::MTYPE_PARTICLES); if (mVOPartGroupp) { if (!mVOPartGroupp->isDead()) @@ -138,8 +166,9 @@ void LLViewerPartGroup::cleanup() } } -BOOL LLViewerPartGroup::posInGroup(const LLVector3 &pos) +BOOL LLViewerPartGroup::posInGroup(const LLVector3 &pos, const F32 desired_size) { + LLMemType mt(LLMemType::MTYPE_PARTICLES); if ((pos.mV[VX] < mMinObjPos.mV[VX]) || (pos.mV[VY] < mMinObjPos.mV[VY]) || (pos.mV[VZ] < mMinObjPos.mV[VZ])) @@ -154,29 +183,33 @@ BOOL LLViewerPartGroup::posInGroup(const LLVector3 &pos) return FALSE; } + if (desired_size > 0 && + (desired_size < mBoxRadius*0.5f || + desired_size > mBoxRadius*2.f)) + { + return FALSE; + } + return TRUE; } -BOOL LLViewerPartGroup::addPart(LLViewerPart &part) +BOOL LLViewerPartGroup::addPart(LLViewerPart* part, F32 desired_size) { - if (!posInGroup(part.mPosAgent) || - (mVOPartGroupp.notNull() && (part.mImagep != mVOPartGroupp->getTEImage(0)))) + LLMemType mt(LLMemType::MTYPE_PARTICLES); + BOOL uniform_part = part->mScale.mV[0] == part->mScale.mV[1] && + !(part->mFlags & LLPartData::LL_PART_FOLLOW_VELOCITY_MASK); + + if (!posInGroup(part->mPosAgent, desired_size) || + (mUniformParticles && !uniform_part) || + (!mUniformParticles && uniform_part)) { return FALSE; } - if (!mVOPartGroupp) - { - mVOPartGroupp = (LLVOPartGroup *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_PART_GROUP, getRegion()); - mVOPartGroupp->setViewerPartGroup(this); - mVOPartGroupp->setPositionAgent(getCenterAgent()); - mVOPartGroupp->setScale(LLVector3(PART_SIM_BOX_SIDE, PART_SIM_BOX_SIDE, PART_SIM_BOX_SIDE)); - mVOPartGroupp->setTEImage(0, part.mImagep); - gPipeline.addObject(mVOPartGroupp); - } + gPipeline.markRebuild(mVOPartGroupp->mDrawable, LLDrawable::REBUILD_ALL, TRUE); - mParticles.put(part); + mParticles.push_back(part); LLViewerPartSim::incPartCount(1); return TRUE; } @@ -184,33 +217,29 @@ BOOL LLViewerPartGroup::addPart(LLViewerPart &part) void LLViewerPartGroup::removePart(const S32 part_num) { + LLMemType mt(LLMemType::MTYPE_PARTICLES); // Remove the entry for the particle we just deleted. - LLPointer<LLViewerPartSource> ps = mParticles[mParticles.count() - 1].mPartSourcep; - - mParticles[mParticles.count() - 1].mPartSourcep = NULL; - mParticles.remove(part_num); - if (part_num < mParticles.count()) + mParticles.erase(mParticles.begin() + part_num); + if (mVOPartGroupp.notNull()) { - mParticles[part_num].mPartSourcep = ps; + gPipeline.markRebuild(mVOPartGroupp->mDrawable, LLDrawable::REBUILD_ALL, TRUE); } - LLViewerPartSim::decPartCount(1); } - void LLViewerPartGroup::updateParticles(const F32 dt) { + LLMemType mt(LLMemType::MTYPE_PARTICLES); S32 i, count; - - + LLVector3 gravity(0.f, 0.f, -9.8f); LLViewerRegion *regionp = getRegion(); - count = mParticles.count(); + count = (S32) mParticles.size(); for (i = 0; i < count; i++) { LLVector3 a(0.f, 0.f, 0.f); - LLViewerPart &part = mParticles[i]; + LLViewerPart& part = *((LLViewerPart*) mParticles[i]); // Update current time const F32 cur_time = part.mLastUpdateTime + dt; @@ -252,8 +281,6 @@ void LLViewerPartGroup::updateParticles(const F32 dt) part.mVelocity *= (1.f - step); part.mVelocity += step*delta_pos; - //part.mPosAgent *= 1.f - to_target_frac; - //part.mPosAgent += to_target_frac*part.mPartSourcep->mTargetPosAgent; } @@ -322,18 +349,22 @@ void LLViewerPartGroup::updateParticles(const F32 dt) i--; count--; } - else if (!posInGroup(part.mPosAgent)) + else { - // Transfer particles between groups - gWorldPointer->mPartSim.put(part); - removePart(i); - i--; - count--; + F32 desired_size = calc_desired_size(part.mPosAgent, part.mScale); + if (!posInGroup(part.mPosAgent, desired_size)) + { + // Transfer particles between groups + gWorldPointer->mPartSim.put(&part); + removePart(i); + i--; + count--; + } } } // Kill the viewer object if this particle group is empty - if (!mParticles.count()) + if (mParticles.empty()) { gObjectList.killObject(mVOPartGroupp); mVOPartGroupp = NULL; @@ -343,15 +374,16 @@ void LLViewerPartGroup::updateParticles(const F32 dt) void LLViewerPartGroup::shift(const LLVector3 &offset) { + LLMemType mt(LLMemType::MTYPE_PARTICLES); mCenterAgent += offset; mMinObjPos += offset; mMaxObjPos += offset; - S32 count = mParticles.count(); + S32 count = (S32) mParticles.size(); S32 i; for (i = 0; i < count; i++) { - mParticles[i].mPosAgent += offset; + mParticles[i]->mPosAgent += offset; } } @@ -365,34 +397,34 @@ void LLViewerPartGroup::shift(const LLVector3 &offset) LLViewerPartSim::LLViewerPartSim() { + LLMemType mt(LLMemType::MTYPE_PARTICLES); sMaxParticleCount = gSavedSettings.getS32("RenderMaxPartCount"); + static U32 id_seed = 0; + mID = ++id_seed; } LLViewerPartSim::~LLViewerPartSim() { + LLMemType mt(LLMemType::MTYPE_PARTICLES); S32 i; S32 count; // Kill all of the groups (and particles) - count = mViewerPartGroups.count(); + count = (S32) mViewerPartGroups.size(); for (i = 0; i < count; i++) { delete mViewerPartGroups[i]; } - mViewerPartGroups.reset(); + mViewerPartGroups.clear(); // Kill all of the sources - count = mViewerPartSources.count(); - for (i = 0; i < count; i++) - { - mViewerPartSources[i] = NULL; - } - mViewerPartSources.reset(); + mViewerPartSources.clear(); } BOOL LLViewerPartSim::shouldAddPart() { + LLMemType mt(LLMemType::MTYPE_PARTICLES); if (sParticleCount > 0.75f*sMaxParticleCount) { @@ -413,33 +445,35 @@ BOOL LLViewerPartSim::shouldAddPart() return TRUE; } -void LLViewerPartSim::addPart(LLViewerPart &part) +void LLViewerPartSim::addPart(LLViewerPart* part) { + LLMemType mt(LLMemType::MTYPE_PARTICLES); if (sParticleCount < MAX_PART_COUNT) { put(part); } } -LLViewerPartGroup *LLViewerPartSim::put(LLViewerPart &part) + +LLViewerPartGroup *LLViewerPartSim::put(LLViewerPart* part) { + LLMemType mt(LLMemType::MTYPE_PARTICLES); const F32 MAX_MAG = 1000000.f*1000000.f; // 1 million - if (part.mPosAgent.magVecSquared() > MAX_MAG) + if (part->mPosAgent.magVecSquared() > MAX_MAG || !part->mPosAgent.isFinite()) { -#ifndef LL_RELEASE_FOR_DOWNLOAD +#if !LL_RELEASE_FOR_DOWNLOAD llwarns << "LLViewerPartSim::put Part out of range!" << llendl; - llwarns << part.mPosAgent << llendl; + llwarns << part->mPosAgent << llendl; #endif return NULL; } + + F32 desired_size = calc_desired_size(part->mPosAgent, part->mScale); - S32 i; - S32 count; - - count = mViewerPartGroups.count(); - for (i = 0; i < count; i++) + S32 count = (S32) mViewerPartGroups.size(); + for (S32 i = 0; i < count; i++) { - if (mViewerPartGroups[i]->addPart(part)) + if (mViewerPartGroups[i]->addPart(part, desired_size)) { // We found a spatial group that we fit into, add us and exit return mViewerPartGroups[i]; @@ -448,43 +482,27 @@ LLViewerPartGroup *LLViewerPartSim::put(LLViewerPart &part) // Hmm, we didn't fit in any of the existing spatial groups // Create a new one... - LLViewerPartGroup *groupp = createViewerPartGroup(part.mPosAgent); + llassert_always(part->mPosAgent.isFinite()); + LLViewerPartGroup *groupp = createViewerPartGroup(part->mPosAgent, desired_size); + groupp->mUniformParticles = (part->mScale.mV[0] == part->mScale.mV[1] && + !(part->mFlags & LLPartData::LL_PART_FOLLOW_VELOCITY_MASK)); if (!groupp->addPart(part)) { llwarns << "LLViewerPartSim::put - Particle didn't go into its box!" << llendl; llinfos << groupp->getCenterAgent() << llendl; - llinfos << part.mPosAgent << llendl; + llinfos << part->mPosAgent << llendl; return NULL; } return groupp; } -LLViewerPartGroup *LLViewerPartSim::createViewerPartGroup(const LLVector3 &pos_agent) +LLViewerPartGroup *LLViewerPartSim::createViewerPartGroup(const LLVector3 &pos_agent, const F32 desired_size) { - F32 x_origin = ((S32)(pos_agent.mV[VX]/PART_SIM_BOX_SIDE))*PART_SIM_BOX_SIDE; - if (x_origin > pos_agent.mV[VX]) - { - x_origin -= PART_SIM_BOX_SIDE; - } - - F32 y_origin = ((S32)(pos_agent.mV[VY]/PART_SIM_BOX_SIDE))*PART_SIM_BOX_SIDE; - if (y_origin > pos_agent.mV[VY]) - { - y_origin -= PART_SIM_BOX_SIDE; - } - - F32 z_origin = ((S32)(pos_agent.mV[VZ]/PART_SIM_BOX_SIDE))*PART_SIM_BOX_SIDE; - if (z_origin > pos_agent.mV[VZ]) - { - z_origin -= PART_SIM_BOX_SIDE; - } - - LLVector3 group_center(x_origin + PART_SIM_BOX_OFFSET, - y_origin + PART_SIM_BOX_OFFSET, - z_origin + PART_SIM_BOX_OFFSET); - - LLViewerPartGroup *groupp = new LLViewerPartGroup(group_center, PART_SIM_BOX_SIDE); - mViewerPartGroups.put(groupp); + LLMemType mt(LLMemType::MTYPE_PARTICLES); + //find a box that has a center position divisible by PART_SIM_BOX_SIDE that encompasses + //pos_agent + LLViewerPartGroup *groupp = new LLViewerPartGroup(pos_agent, desired_size); + mViewerPartGroups.push_back(groupp); return groupp; } @@ -494,7 +512,7 @@ void LLViewerPartSim::shift(const LLVector3 &offset) S32 i; S32 count; - count = mViewerPartSources.count(); + count = (S32) mViewerPartSources.size(); for (i = 0; i < count; i++) { mViewerPartSources[i]->mPosAgent += offset; @@ -502,13 +520,20 @@ void LLViewerPartSim::shift(const LLVector3 &offset) mViewerPartSources[i]->mLastUpdatePosAgent += offset; } - count = mViewerPartGroups.count(); + count = (S32) mViewerPartGroups.size(); for (i = 0; i < count; i++) { mViewerPartGroups[i]->shift(offset); } } +S32 dist_rate_func(F32 distance) +{ + //S32 dist = (S32) sqrtf(distance); + //dist /= 2; + //return llmax(dist,1); + return 1; +} void LLViewerPartSim::updateSimulation() { @@ -523,13 +548,15 @@ void LLViewerPartSim::updateSimulation() return; } + LLFastTimer ftm(LLFastTimer::FTM_SIMULATE_PARTICLES); + // Start at a random particle system so the same // particle system doesn't always get first pick at the // particles. Theoretically we'd want to do this in distance // order or something, but sorting particle sources will be a big // pain. S32 i; - S32 count = mViewerPartSources.count(); + S32 count = (S32) mViewerPartSources.size(); S32 start = (S32)ll_frand((F32)count); S32 dir = 1; if (ll_frand() > 0.5f) @@ -551,12 +578,24 @@ void LLViewerPartSim::updateSimulation() if (!mViewerPartSources[i]->isDead()) { - mViewerPartSources[i]->update(dt); + LLViewerObject* source_object = mViewerPartSources[i]->mSourceObjectp; + if (source_object && source_object->mDrawable.notNull()) + { + S32 dist = dist_rate_func(source_object->mDrawable->mDistanceWRTCamera); + if ((LLDrawable::getCurrentFrame()+mViewerPartSources[i]->mID)%dist == 0) + { + mViewerPartSources[i]->update(dt*dist); + } + } + else + { + mViewerPartSources[i]->update(dt); + } } if (mViewerPartSources[i]->isDead()) { - mViewerPartSources.remove(i); + mViewerPartSources.erase(mViewerPartSources.begin() + i); count--; } else @@ -567,16 +606,36 @@ void LLViewerPartSim::updateSimulation() } - count = mViewerPartGroups.count(); + count = (S32) mViewerPartGroups.size(); for (i = 0; i < count; i++) { - mViewerPartGroups[i]->updateParticles(dt); - if (!mViewerPartGroups[i]->getCount()) + LLViewerObject* vobj = mViewerPartGroups[i]->mVOPartGroupp; + + S32 dist = vobj && !vobj->mDrawable->isState(LLDrawable::IN_REBUILD_Q1) ? + dist_rate_func(vobj->mDrawable->mDistanceWRTCamera) : 1; + if (vobj) { - delete mViewerPartGroups[i]; - mViewerPartGroups.remove(i); - i--; - count--; + LLSpatialGroup* group = vobj->mDrawable->getSpatialGroup(); + if (group && !group->isVisible()) // && !group->isState(LLSpatialGroup::OBJECT_DIRTY)) + { + dist *= 8; + } + } + + if ((LLDrawable::getCurrentFrame()+mViewerPartGroups[i]->mID)%dist == 0) + { + if (vobj) + { + gPipeline.markRebuild(vobj->mDrawable, LLDrawable::REBUILD_ALL, TRUE); + } + mViewerPartGroups[i]->updateParticles(dt*dist); + if (!mViewerPartGroups[i]->getCount()) + { + delete mViewerPartGroups[i]; + mViewerPartGroups.erase(mViewerPartGroups.begin() + i); + i--; + count--; + } } } //llinfos << "Particles: " << sParticleCount << llendl; @@ -585,42 +644,40 @@ void LLViewerPartSim::updateSimulation() void LLViewerPartSim::addPartSource(LLViewerPartSource *sourcep) { + LLMemType mt(LLMemType::MTYPE_PARTICLES); if (!sourcep) { llwarns << "Null part source!" << llendl; return; } - mViewerPartSources.put(sourcep); + mViewerPartSources.push_back(sourcep); } void LLViewerPartSim::cleanupRegion(LLViewerRegion *regionp) { - S32 i, count; - count = mViewerPartGroups.count(); - for (i = 0; i < count; i++) + LLMemType mt(LLMemType::MTYPE_PARTICLES); + for (group_list_t::iterator i = mViewerPartGroups.begin(); i != mViewerPartGroups.end(); ) { - if (mViewerPartGroups[i]->getRegion() == regionp) + group_list_t::iterator iter = i++; + + if ((*iter)->getRegion() == regionp) { - delete mViewerPartGroups[i]; - mViewerPartGroups.remove(i); - i--; - count--; + i = mViewerPartGroups.erase(iter); } } } void LLViewerPartSim::cleanMutedParticles(const LLUUID& task_id) { - S32 i; - S32 count = mViewerPartSources.count(); - for (i = 0; i < count; ++i) + LLMemType mt(LLMemType::MTYPE_PARTICLES); + for (source_list_t::iterator i = mViewerPartSources.begin(); i != mViewerPartSources.end(); ) { - if (mViewerPartSources[i]->getOwnerUUID() == task_id) + source_list_t::iterator iter = i++; + + if ((*iter)->getOwnerUUID() == task_id) { - mViewerPartSources.remove(i); - i--; - count--; + i = mViewerPartSources.erase(iter); } } } diff --git a/indra/newview/llviewerpartsim.h b/indra/newview/llviewerpartsim.h index 83c374a42e..b0b9500ac6 100644 --- a/indra/newview/llviewerpartsim.h +++ b/indra/newview/llviewerpartsim.h @@ -31,7 +31,7 @@ typedef void (*LLVPCallback)(LLViewerPart &part, const F32 dt); // -class LLViewerPart : public LLPartData +class LLViewerPart : public LLPartData, public LLRefCount { public: LLViewerPart(); @@ -71,19 +71,26 @@ public: void cleanup(); - BOOL addPart(LLViewerPart &part); + BOOL addPart(LLViewerPart* part, const F32 desired_size = -1.f); void updateParticles(const F32 dt); - BOOL posInGroup(const LLVector3 &pos); + BOOL posInGroup(const LLVector3 &pos, const F32 desired_size = -1.f); void shift(const LLVector3 &offset); - LLDynamicArray<LLViewerPart> mParticles; + typedef std::vector<LLPointer<LLViewerPart> > part_list_t; + part_list_t mParticles; const LLVector3 &getCenterAgent() const { return mCenterAgent; } - S32 getCount() const { return mParticles.count(); } + S32 getCount() const { return (S32) mParticles.size(); } LLViewerRegion *getRegion() const { return mRegionp; } + + LLPointer<LLVOPartGroup> mVOPartGroupp; + + BOOL mUniformParticles; + U32 mID; + protected: void removePart(const S32 part_num); @@ -93,11 +100,9 @@ protected: LLVector3 mMinObjPos; LLVector3 mMaxObjPos; - LLPointer<LLVOPartGroup> mVOPartGroupp; LLViewerRegion *mRegionp; }; - class LLViewerPartSim { public: @@ -113,7 +118,7 @@ public: void cleanupRegion(LLViewerRegion *regionp); BOOL shouldAddPart(); // Just decides whether this particle should be added or not (for particle count capping) - void addPart(LLViewerPart &part); + void addPart(LLViewerPart* part); void cleanMutedParticles(const LLUUID& task_id); friend class LLViewerPartGroup; @@ -125,15 +130,18 @@ public: static void incPartCount(const S32 count) { sParticleCount += count; } static void decPartCount(const S32 count) { sParticleCount -= count; } + U32 mID; + protected: - LLViewerPartGroup *createViewerPartGroup(const LLVector3 &pos_agent); - LLViewerPartGroup *put(LLViewerPart &part); + LLViewerPartGroup *createViewerPartGroup(const LLVector3 &pos_agent, const F32 desired_size); + LLViewerPartGroup *put(LLViewerPart* part); protected: - LLDynamicArray<LLViewerPartGroup *> mViewerPartGroups; - LLDynamicArrayPtr<LLPointer<LLViewerPartSource> > mViewerPartSources; + typedef std::vector<LLViewerPartGroup *> group_list_t; + typedef std::vector<LLPointer<LLViewerPartSource> > source_list_t; + group_list_t mViewerPartGroups; + source_list_t mViewerPartSources; LLFrameTimer mSimulationTimer; - static S32 sMaxParticleCount; static S32 sParticleCount; }; diff --git a/indra/newview/llviewerpartsource.cpp b/indra/newview/llviewerpartsource.cpp index 981c5531c9..b14a82e3f1 100644 --- a/indra/newview/llviewerpartsource.cpp +++ b/indra/newview/llviewerpartsource.cpp @@ -18,6 +18,7 @@ #include "llviewerobjectlist.h" #include "llvoavatar.h" #include "llworld.h" +#include "pipeline.h" LLViewerPartSource::LLViewerPartSource(const U32 type) : mType(type), @@ -26,6 +27,8 @@ LLViewerPartSource::LLViewerPartSource(const U32 type) : mLastUpdateTime = 0.f; mLastPartTime = 0.f; mIsDead = FALSE; + static U32 id_seed = 0; + mID = ++id_seed; } void LLViewerPartSource::setDead() @@ -48,6 +51,7 @@ void LLViewerPartSource::update(const F32 dt) LLViewerPartSourceScript::LLViewerPartSourceScript(LLViewerObject *source_objp) : LLViewerPartSource(LL_PART_SOURCE_SCRIPT) { + LLMemType mt(LLMemType::MTYPE_PARTICLES); llassert(source_objp); mSourceObjectp = source_objp; mPosAgent = mSourceObjectp->getPositionAgent(); @@ -61,18 +65,18 @@ LLViewerPartSourceScript::LLViewerPartSourceScript(LLViewerObject *source_objp) void LLViewerPartSourceScript::setDead() { + LLMemType mt(LLMemType::MTYPE_PARTICLES); mIsDead = TRUE; mSourceObjectp = NULL; mTargetObjectp = NULL; } - - void LLViewerPartSourceScript::update(const F32 dt) { + LLMemType mt(LLMemType::MTYPE_PARTICLES); F32 old_update_time = mLastUpdateTime; mLastUpdateTime += dt; - + F32 dt_update = mLastUpdateTime - mLastPartTime; // Update this for objects which have the follow flag set... @@ -123,6 +127,17 @@ void LLViewerPartSourceScript::update(const F32 dt) return; } + + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_PARTICLES)) + { + if (mSourceObjectp.notNull()) + { + std::ostringstream ostr; + ostr << mPartSysData; + mSourceObjectp->setDebugText(ostr.str()); + } + } + BOOL first_run = FALSE; if (old_update_time <= 0.f) { @@ -134,21 +149,7 @@ void LLViewerPartSourceScript::update(const F32 dt) while ((dt_update > mPartSysData.mBurstRate) || first_run) { first_run = FALSE; - LLViewerPart part; - - part.init(this, mImagep, NULL); - part.mFlags = mPartSysData.mPartData.mFlags; - part.mMaxAge = mPartSysData.mPartData.mMaxAge; - part.mStartColor = mPartSysData.mPartData.mStartColor; - part.mEndColor = mPartSysData.mPartData.mEndColor; - part.mColor = part.mStartColor; - - part.mStartScale = mPartSysData.mPartData.mStartScale; - part.mEndScale = mPartSysData.mPartData.mEndScale; - part.mScale = part.mStartScale; - - part.mAccel = mPartSysData.mPartAccel; - + // Update the rotation of the particle source by the angular velocity // First check to see if there is still an angular velocity. F32 angular_velocity_mag = mPartSysData.mAngularVelocity.magVec(); @@ -181,14 +182,29 @@ void LLViewerPartSourceScript::update(const F32 dt) continue; } + LLPointer<LLViewerPart> part = new LLViewerPart(); + + part->init(this, mImagep, NULL); + part->mFlags = mPartSysData.mPartData.mFlags; + part->mMaxAge = mPartSysData.mPartData.mMaxAge; + part->mStartColor = mPartSysData.mPartData.mStartColor; + part->mEndColor = mPartSysData.mPartData.mEndColor; + part->mColor = part->mStartColor; + + part->mStartScale = mPartSysData.mPartData.mStartScale; + part->mEndScale = mPartSysData.mPartData.mEndScale; + part->mScale = part->mStartScale; + + part->mAccel = mPartSysData.mPartAccel; + if (mPartSysData.mPattern & LLPartSysData::LL_PART_SRC_PATTERN_DROP) { - part.mPosAgent = mPosAgent; - part.mVelocity.setVec(0.f, 0.f, 0.f); + part->mPosAgent = mPosAgent; + part->mVelocity.setVec(0.f, 0.f, 0.f); } else if (mPartSysData.mPattern & LLPartSysData::LL_PART_SRC_PATTERN_EXPLODE) { - part.mPosAgent = mPosAgent; + part->mPosAgent = mPosAgent; LLVector3 part_dir_vector; F32 mvs; @@ -202,19 +218,18 @@ void LLViewerPartSourceScript::update(const F32 dt) while ((mvs > 1.f) || (mvs < 0.01f)); part_dir_vector.normVec(); - part.mPosAgent += mPartSysData.mBurstRadius*part_dir_vector; - part.mVelocity = part_dir_vector; + part->mPosAgent += mPartSysData.mBurstRadius*part_dir_vector; + part->mVelocity = part_dir_vector; F32 speed = mPartSysData.mBurstSpeedMin + ll_frand(mPartSysData.mBurstSpeedMax - mPartSysData.mBurstSpeedMin); - part.mVelocity *= speed; + part->mVelocity *= speed; } else if (mPartSysData.mPattern & LLPartSysData::LL_PART_SRC_PATTERN_ANGLE || mPartSysData.mPattern & LLPartSysData::LL_PART_SRC_PATTERN_ANGLE_CONE) - { - part.mPosAgent = mPosAgent; + { + part->mPosAgent = mPosAgent; // original implemenetation for part_dir_vector was just: LLVector3 part_dir_vector(0.0, 0.0, 1.0); - // params from the script... // outer = outer cone angle // inner = inner cone angle @@ -224,13 +239,11 @@ void LLViewerPartSourceScript::update(const F32 dt) // generate a random angle within the given space... F32 angle = innerAngle + ll_frand(outerAngle - innerAngle); - // split which side it will go on randomly... if (ll_frand() < 0.5) { angle = -angle; } - // Both patterns rotate around the x-axis first: part_dir_vector.rotVec(angle, 1.0, 0.0, 0.0); @@ -239,31 +252,32 @@ void LLViewerPartSourceScript::update(const F32 dt) { part_dir_vector.rotVec(ll_frand(4*F_PI), 0.0, 0.0, 1.0); } - + // Only apply this rotation if using the deprecated angles. if (! (mPartSysData.mFlags & LLPartSysData::LL_PART_USE_NEW_ANGLE)) { // Deprecated... part_dir_vector.rotVec(outerAngle, 1.0, 0.0, 0.0); } - + if (mSourceObjectp) { part_dir_vector = part_dir_vector * mSourceObjectp->getRenderRotation(); } + part_dir_vector = part_dir_vector * mRotation; + + part->mPosAgent += mPartSysData.mBurstRadius*part_dir_vector; - part.mPosAgent += mPartSysData.mBurstRadius*part_dir_vector; - - part.mVelocity = part_dir_vector; + part->mVelocity = part_dir_vector; F32 speed = mPartSysData.mBurstSpeedMin + ll_frand(mPartSysData.mBurstSpeedMax - mPartSysData.mBurstSpeedMin); - part.mVelocity *= speed; + part->mVelocity *= speed; } else { - part.mPosAgent = mPosAgent; - part.mVelocity.setVec(0.f, 0.f, 0.f); + part->mPosAgent = mPosAgent; + part->mVelocity.setVec(0.f, 0.f, 0.f); //llwarns << "Unknown source pattern " << (S32)mPartSysData.mPattern << llendl; } @@ -278,6 +292,7 @@ void LLViewerPartSourceScript::update(const F32 dt) // static LLViewerPartSourceScript *LLViewerPartSourceScript::unpackPSS(LLViewerObject *source_objp, LLViewerPartSourceScript *pssp, const S32 block_num) { + LLMemType mt(LLMemType::MTYPE_PARTICLES); if (!pssp) { if (LLPartSysData::isNullPS(block_num)) @@ -319,6 +334,7 @@ LLViewerPartSourceScript *LLViewerPartSourceScript::unpackPSS(LLViewerObject *so LLViewerPartSourceScript *LLViewerPartSourceScript::unpackPSS(LLViewerObject *source_objp, LLViewerPartSourceScript *pssp, LLDataPacker &dp) { + LLMemType mt(LLMemType::MTYPE_PARTICLES); if (!pssp) { LLViewerPartSourceScript *new_pssp = new LLViewerPartSourceScript(source_objp); @@ -350,11 +366,13 @@ LLViewerPartSourceScript *LLViewerPartSourceScript::unpackPSS(LLViewerObject *so void LLViewerPartSourceScript::setImage(LLViewerImage *imagep) { + LLMemType mt(LLMemType::MTYPE_PARTICLES); mImagep = imagep; } void LLViewerPartSourceScript::setTargetObject(LLViewerObject *objp) { + LLMemType mt(LLMemType::MTYPE_PARTICLES); mTargetObjectp = objp; } @@ -370,6 +388,7 @@ LLViewerPartSourceSpiral::LLViewerPartSourceSpiral(const LLVector3 &pos) : void LLViewerPartSourceSpiral::setDead() { + LLMemType mt(LLMemType::MTYPE_PARTICLES); mIsDead = TRUE; mSourceObjectp = NULL; } @@ -377,6 +396,7 @@ void LLViewerPartSourceSpiral::setDead() void LLViewerPartSourceSpiral::updatePart(LLViewerPart &part, const F32 dt) { + LLMemType mt(LLMemType::MTYPE_PARTICLES); F32 frac = part.mLastUpdateTime/part.mMaxAge; LLVector3 center_pos; @@ -401,6 +421,7 @@ void LLViewerPartSourceSpiral::updatePart(LLViewerPart &part, const F32 dt) void LLViewerPartSourceSpiral::update(const F32 dt) { + LLMemType mt(LLMemType::MTYPE_PARTICLES); if (!mImagep) { LLUUID id; @@ -429,18 +450,18 @@ void LLViewerPartSourceSpiral::update(const F32 dt) { mPosAgent = mSourceObjectp->getRenderPosition(); } - LLViewerPart part; - part.init(this, mImagep, updatePart); - part.mStartColor = mColor; - part.mEndColor = mColor; - part.mEndColor.mV[3] = 0.f; - part.mPosAgent = mPosAgent; - part.mMaxAge = 1.f; - part.mFlags = LLViewerPart::LL_PART_INTERP_COLOR_MASK; - part.mLastUpdateTime = 0.f; - part.mScale.mV[0] = 0.25f; - part.mScale.mV[1] = 0.25f; - part.mParameter = ll_frand(F_TWO_PI); + LLPointer<LLViewerPart> part = new LLViewerPart(); + part->init(this, mImagep, updatePart); + part->mStartColor = mColor; + part->mEndColor = mColor; + part->mEndColor.mV[3] = 0.f; + part->mPosAgent = mPosAgent; + part->mMaxAge = 1.f; + part->mFlags = LLViewerPart::LL_PART_INTERP_COLOR_MASK; + part->mLastUpdateTime = 0.f; + part->mScale.mV[0] = 0.25f; + part->mScale.mV[1] = 0.25f; + part->mParameter = ll_frand(F_TWO_PI); gWorldPointer->mPartSim.addPart(part); } @@ -448,6 +469,7 @@ void LLViewerPartSourceSpiral::update(const F32 dt) void LLViewerPartSourceSpiral::setSourceObject(LLViewerObject *objp) { + LLMemType mt(LLMemType::MTYPE_PARTICLES); mSourceObjectp = objp; } @@ -471,6 +493,7 @@ LLViewerPartSourceBeam::~LLViewerPartSourceBeam() void LLViewerPartSourceBeam::setDead() { + LLMemType mt(LLMemType::MTYPE_PARTICLES); mIsDead = TRUE; mSourceObjectp = NULL; mTargetObjectp = NULL; @@ -484,6 +507,7 @@ void LLViewerPartSourceBeam::setColor(const LLColor4 &color) void LLViewerPartSourceBeam::updatePart(LLViewerPart &part, const F32 dt) { + LLMemType mt(LLMemType::MTYPE_PARTICLES); F32 frac = part.mLastUpdateTime/part.mMaxAge; LLViewerPartSource *ps = (LLViewerPartSource*)part.mPartSourcep; @@ -528,7 +552,7 @@ void LLViewerPartSourceBeam::updatePart(LLViewerPart &part, const F32 dt) void LLViewerPartSourceBeam::update(const F32 dt) { - + LLMemType mt(LLMemType::MTYPE_PARTICLES); const F32 RATE = 0.025f; mLastUpdateTime += dt; @@ -576,25 +600,25 @@ void LLViewerPartSourceBeam::update(const F32 dt) mImagep = gImageList.getImage(id); } - LLViewerPart part; - part.init(this, mImagep, NULL); + LLPointer<LLViewerPart> part = new LLViewerPart(); + part->init(this, mImagep, NULL); - part.mFlags = LLPartData::LL_PART_INTERP_COLOR_MASK | + part->mFlags = LLPartData::LL_PART_INTERP_COLOR_MASK | LLPartData::LL_PART_INTERP_SCALE_MASK | LLPartData::LL_PART_TARGET_POS_MASK | LLPartData::LL_PART_FOLLOW_VELOCITY_MASK; - part.mMaxAge = 0.5f; - part.mStartColor = mColor; - part.mEndColor = part.mStartColor; - part.mEndColor.mV[3] = 0.4f; - part.mColor = part.mStartColor; + part->mMaxAge = 0.5f; + part->mStartColor = mColor; + part->mEndColor = part->mStartColor; + part->mEndColor.mV[3] = 0.4f; + part->mColor = part->mStartColor; - part.mStartScale = LLVector2(0.1f, 0.1f); - part.mEndScale = LLVector2(0.1f, 0.1f); - part.mScale = part.mStartScale; + part->mStartScale = LLVector2(0.1f, 0.1f); + part->mEndScale = LLVector2(0.1f, 0.1f); + part->mScale = part->mStartScale; - part.mPosAgent = mPosAgent; - part.mVelocity = mTargetPosAgent - mPosAgent; + part->mPosAgent = mPosAgent; + part->mVelocity = mTargetPosAgent - mPosAgent; gWorldPointer->mPartSim.addPart(part); } @@ -602,11 +626,13 @@ void LLViewerPartSourceBeam::update(const F32 dt) void LLViewerPartSourceBeam::setSourceObject(LLViewerObject* objp) { + LLMemType mt(LLMemType::MTYPE_PARTICLES); mSourceObjectp = objp; } void LLViewerPartSourceBeam::setTargetObject(LLViewerObject* objp) { + LLMemType mt(LLMemType::MTYPE_PARTICLES); mTargetObjectp = objp; } @@ -621,6 +647,7 @@ LLViewerPartSourceChat::LLViewerPartSourceChat(const LLVector3 &pos) : void LLViewerPartSourceChat::setDead() { + LLMemType mt(LLMemType::MTYPE_PARTICLES); mIsDead = TRUE; mSourceObjectp = NULL; } @@ -628,6 +655,7 @@ void LLViewerPartSourceChat::setDead() void LLViewerPartSourceChat::updatePart(LLViewerPart &part, const F32 dt) { + LLMemType mt(LLMemType::MTYPE_PARTICLES); F32 frac = part.mLastUpdateTime/part.mMaxAge; LLVector3 center_pos; @@ -652,6 +680,7 @@ void LLViewerPartSourceChat::updatePart(LLViewerPart &part, const F32 dt) void LLViewerPartSourceChat::update(const F32 dt) { + LLMemType mt(LLMemType::MTYPE_PARTICLES); if (!mImagep) { LLUUID id; @@ -690,18 +719,18 @@ void LLViewerPartSourceChat::update(const F32 dt) { mPosAgent = mSourceObjectp->getRenderPosition(); } - LLViewerPart part; - part.init(this, mImagep, updatePart); - part.mStartColor = mColor; - part.mEndColor = mColor; - part.mEndColor.mV[3] = 0.f; - part.mPosAgent = mPosAgent; - part.mMaxAge = 1.f; - part.mFlags = LLViewerPart::LL_PART_INTERP_COLOR_MASK; - part.mLastUpdateTime = 0.f; - part.mScale.mV[0] = 0.25f; - part.mScale.mV[1] = 0.25f; - part.mParameter = ll_frand(F_TWO_PI); + LLPointer<LLViewerPart> part = new LLViewerPart(); + part->init(this, mImagep, updatePart); + part->mStartColor = mColor; + part->mEndColor = mColor; + part->mEndColor.mV[3] = 0.f; + part->mPosAgent = mPosAgent; + part->mMaxAge = 1.f; + part->mFlags = LLViewerPart::LL_PART_INTERP_COLOR_MASK; + part->mLastUpdateTime = 0.f; + part->mScale.mV[0] = 0.25f; + part->mScale.mV[1] = 0.25f; + part->mParameter = ll_frand(F_TWO_PI); gWorldPointer->mPartSim.addPart(part); } @@ -709,6 +738,7 @@ void LLViewerPartSourceChat::update(const F32 dt) void LLViewerPartSourceChat::setSourceObject(LLViewerObject *objp) { + LLMemType mt(LLMemType::MTYPE_PARTICLES); mSourceObjectp = objp; } diff --git a/indra/newview/llviewerpartsource.h b/indra/newview/llviewerpartsource.h index 05fa007ead..4bd577b7a5 100644 --- a/indra/newview/llviewerpartsource.h +++ b/indra/newview/llviewerpartsource.h @@ -51,13 +51,16 @@ public: LLVector3 mPosAgent; // Location of the particle source LLVector3 mTargetPosAgent; // Location of the target position LLVector3 mLastUpdatePosAgent; + LLPointer<LLViewerObject> mSourceObjectp; + U32 mID; + protected: U32 mType; BOOL mIsDead; F32 mLastUpdateTime; F32 mLastPartTime; LLUUID mOwnerUUID; - + // Particle information U32 mPartFlags; // Flags for the particle }; @@ -96,7 +99,6 @@ public: protected: LLQuaternion mRotation; // Current rotation for particle source LLPointer<LLViewerImage> mImagep; // Cached image pointer of the mPartSysData UUID - LLPointer<LLViewerObject> mSourceObjectp; // Source object that this particle system is attached to LLPointer<LLViewerObject> mTargetObjectp; // Target object for the particle source }; @@ -122,7 +124,6 @@ public: LLColor4 mColor; protected: LLPointer<LLViewerImage> mImagep; - LLPointer<LLViewerObject> mSourceObjectp; LLVector3d mLKGSourcePosGlobal; }; @@ -150,7 +151,6 @@ public: static void updatePart(LLViewerPart &part, const F32 dt); LLPointer<LLViewerImage> mImagep; - LLPointer<LLViewerObject> mSourceObjectp; LLPointer<LLViewerObject> mTargetObjectp; LLVector3d mLKGTargetPosGlobal; LLColor4 mColor; @@ -180,7 +180,6 @@ public: LLColor4 mColor; protected: LLPointer<LLViewerImage> mImagep; - LLPointer<LLViewerObject> mSourceObjectp; LLVector3d mLKGSourcePosGlobal; }; diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index fa68e25b0e..5235410156 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -575,23 +575,25 @@ void LLViewerRegion::dirtyHeights() } } -BOOL LLViewerRegion::idleUpdate(LLTimer &timer, const F32 max_time) +BOOL LLViewerRegion::idleUpdate(F32 max_update_time) { - BOOL done = mLandp->idleUpdate(); - + // did_update returns TRUE if we did at least one significant update + BOOL did_update = mLandp->idleUpdate(max_update_time); + if (mParcelOverlay) { + // Hopefully not a significant time sink... mParcelOverlay->idleUpdate(); } - return done; + return did_update; } // As above, but forcibly do the update. void LLViewerRegion::forceUpdate() { - mLandp->idleUpdate(); + mLandp->idleUpdate(0.f); if (mParcelOverlay) { @@ -826,7 +828,7 @@ LLVector3 LLViewerRegion::getPosAgentFromRegion(const LLVector3 &pos_region) con LLVector3 LLViewerRegion::getPosRegionFromAgent(const LLVector3 &pos_agent) const { - return getPosRegionFromGlobal(gAgent.getPosGlobalFromAgent(pos_agent)); + return pos_agent - getOriginAgent(); } F32 LLViewerRegion::getLandHeightRegion(const LLVector3& region_pos) @@ -1260,6 +1262,7 @@ void LLViewerRegion::setSeedCapability(const std::string& url) capabilityNames.append("MapLayerGod"); capabilityNames.append("NewAgentInventory"); capabilityNames.append("EventQueueGet"); + capabilityNames.append("RequestTextureDownload"); LLHTTPClient::post(url, capabilityNames, BaseCapabilitiesComplete::build(this)); } diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h index 3ce6c89430..b3392baf81 100644 --- a/indra/newview/llviewerregion.h +++ b/indra/newview/llviewerregion.h @@ -153,7 +153,7 @@ public: F32 getWidth() const { return mWidth; } - BOOL idleUpdate(LLTimer &timer, const F32 max_time); + BOOL idleUpdate(F32 max_update_time); // Like idleUpdate, but forces everything to complete regardless of // how long it takes. diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index baf241697b..4a5cbd20e6 100644 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -103,13 +103,13 @@ const StatAttributes STAT_INFO[LLViewerStats::ST_COUNT] = // ST_SIM_FPS_20_SECONDS StatAttributes("Seconds with sim FPS below 20", TRUE, TRUE), // ST_PHYS_FPS_20_SECONDS - StatAttributes("Seconds with physics FPS below 20", TRUE, TRUE), + StatAttributes("Seconds with physics FPS below 20", FALSE, TRUE), // ST_LOSS_05_SECONDS StatAttributes("Seconds with packet loss > 5%", TRUE, TRUE), // ST_FPS_DROP_50_RATIO - StatAttributes("Ratio of frames 2x longer than previous", TRUE, FALSE), - // ST_MEDIA_OBJECT_LIST_LENGTH - StatAttributes("Number of objects that want to display web pages", TRUE, FALSE), + StatAttributes("Ratio of frames 2x longer than previous", FALSE, FALSE), + // ST_ENABLE_VBO + StatAttributes("Vertex Buffers Enabled", TRUE, FALSE), // ST_DELTA_BANDWIDTH StatAttributes("Increase/Decrease in bandwidth based on packet loss", TRUE, FALSE), // ST_MAX_BANDWIDTH diff --git a/indra/newview/llviewerstats.h b/indra/newview/llviewerstats.h index 055b21d116..33ed6bcbcf 100644 --- a/indra/newview/llviewerstats.h +++ b/indra/newview/llviewerstats.h @@ -114,7 +114,7 @@ public: ST_PHYS_FPS_20_SECONDS = 32, ST_LOSS_05_SECONDS = 33, ST_FPS_DROP_50_RATIO = 34, - ST_MEDIA_OBJECT_LIST_LENGTH = 35, + ST_ENABLE_VBO = 35, ST_DELTA_BANDWIDTH = 36, ST_MAX_BANDWIDTH = 37, ST_LIGHTING_DETAIL = 38, diff --git a/indra/newview/llviewerthrottle.cpp b/indra/newview/llviewerthrottle.cpp index 4ffdabbbc9..ceef3bbac5 100644 --- a/indra/newview/llviewerthrottle.cpp +++ b/indra/newview/llviewerthrottle.cpp @@ -18,11 +18,7 @@ // consts -// The viewer is allowed to set the under-the-hood bandwidth to 50% -// greater than the prefs UI shows, under the assumption that the -// viewer won't receive all the different message types at once. -// I didn't design this, don't know who did. JC -const F32 MAX_FRACTIONAL = 1.5f; +const F32 MAX_FRACTIONAL = 1.0f; // was 1.5, which was causing packet loss, reduced to 1.0 - SJB const F32 MIN_FRACTIONAL = 0.2f; const F32 MIN_BANDWIDTH = 50.f; diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 1b39c5bf7e..9d4367cc79 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -114,6 +114,8 @@ #include "llimview.h" #include "lltexlayer.h" #include "lltextbox.h" +#include "lltexturecache.h" +#include "lltexturefetch.h" #include "lltextureview.h" #include "lltool.h" #include "lltoolbar.h" @@ -1203,6 +1205,13 @@ LLViewerWindow::LLViewerWindow( LLFontManager::initClass(); + if (!gFeatureManagerp->isFeatureAvailable("RenderVBO") || + !gGLManager.mHasVertexBufferObject) + { + gSavedSettings.setBOOL("RenderVBOEnable", FALSE); + } + LLVertexBuffer::initClass(gSavedSettings.getBOOL("RenderVBOEnable")); + // // We want to set this stuff up BEFORE we initialize the pipeline, so we can turn off // stuff like AGP if we think that it'll crash the viewer. @@ -1231,7 +1240,6 @@ LLViewerWindow::LLViewerWindow( gPipeline.init(); stop_glerror(); initGLDefaults(); - LLViewerImage::initClass(); } // @@ -1244,6 +1252,7 @@ LLViewerWindow::LLViewerWindow( // Init the image list. Must happen after GL is initialized and before the images that // LLViewerWindow needs are requested. gImageList.init(); + LLViewerImage::initClass(); gBumpImageList.init(); // Create container for all sub-views @@ -1677,11 +1686,23 @@ LLViewerWindow::~LLViewerWindow() LLWorldMapView::cleanupTextures(); + llinfos << "Cleaning up pipeline" << llendl; + gPipeline.cleanup(); + stop_glerror(); + LLViewerImage::cleanupClass(); delete[] mPickBuffer; mPickBuffer = NULL; + if (gSelectMgr) + { + llinfos << "Cleaning up select manager" << llendl; + gSelectMgr->cleanup(); + } + + LLVertexBuffer::cleanupClass(); + llinfos << "Stopping GL during shutdown" << llendl; if (!gNoRender) { @@ -1689,15 +1710,7 @@ LLViewerWindow::~LLViewerWindow() stop_glerror(); } - if (gSelectMgr) - { - llinfos << "Cleaning up select manager" << llendl; - gSelectMgr->cleanup(); - } - llinfos << "Cleaning up pipeline" << llendl; - gPipeline.cleanup(); - stop_glerror(); llinfos << "Destroying Window" << llendl; destroyWindow(); } @@ -1829,6 +1842,13 @@ void LLViewerWindow::reshape(S32 width, S32 height) gViewerStats->setStat(LLViewerStats::ST_WINDOW_WIDTH, (F64)width); gViewerStats->setStat(LLViewerStats::ST_WINDOW_HEIGHT, (F64)height); + + //reposition HUD attachments + LLVOAvatar* avatarp = gAgent.getAvatarObject(); + if (avatarp) + { + avatarp->resetHUDAttachments(); + } } } @@ -2263,44 +2283,15 @@ void LLViewerWindow::handleScrollWheel(S32 clicks) void LLViewerWindow::moveCursorToCenter() { -#if 1 // old version - -#if 0 // Dave's changes - this reportedly is making the drift worse on some systems? - S32 x = llround((F32) mVirtualWindowRect.getWidth() / 2); - S32 y = llround((F32) mVirtualWindowRect.getHeight() / 2); -#else S32 x = mVirtualWindowRect.getWidth() / 2; S32 y = mVirtualWindowRect.getHeight() / 2; -#endif //on a forced move, all deltas get zeroed out to prevent jumping mCurrentMousePoint.set(x,y); mLastMousePoint.set(x,y); mCurrentMouseDelta.set(0,0); - LLUI::setCursorPositionScreen(x, y); - -#else // Richard's version - fails on intel macs - - S32 x = llround((F32) mWindowRect.getWidth() / 2); - S32 y = llround((F32) mWindowRect.getHeight() / 2); - - LLCoordWindow window_point; - mWindow->convertCoords(LLCoordGL(x, y), &window_point); - mWindow->setCursorPosition(window_point); - - // read back cursor position - mWindow->getCursorPosition(&window_point); - LLCoordGL new_mouse_pos; - mWindow->convertCoords(window_point, &new_mouse_pos); - new_mouse_pos.mX = llround((F32)new_mouse_pos.mX / mDisplayScale.mV[VX]); - new_mouse_pos.mY = llround((F32)new_mouse_pos.mY / mDisplayScale.mV[VY]); - - //on a forced move, all deltas get zeroed out to prevent jumping - mCurrentMousePoint = new_mouse_pos; - mLastMousePoint = new_mouse_pos; - mCurrentMouseDelta.set(0,0); -#endif + LLUI::setCursorPositionScreen(x, y); } ////////////////////////////////////////////////////////////////////// @@ -2329,10 +2320,29 @@ BOOL LLViewerWindow::handlePerFrameHover() mMouseInWindow = TRUE; } - S32 dx = mCurrentMousePoint.mX - mLastMousePoint.mX; - S32 dy = mCurrentMousePoint.mY - mLastMousePoint.mY; - mCurrentMouseDelta.set(dx,dy); - LLVector2 mouse_vel((F32)dx, (F32)dy); + S32 dx = lltrunc((F32) (mCurrentMousePoint.mX - mLastMousePoint.mX) * LLUI::sGLScaleFactor.mV[VX]); + S32 dy = lltrunc((F32) (mCurrentMousePoint.mY - mLastMousePoint.mY) * LLUI::sGLScaleFactor.mV[VY]); + + LLVector2 mouse_vel; + + if (gSavedSettings.getBOOL("MouseSmooth")) + { + static F32 fdx = 0.f; + static F32 fdy = 0.f; + + F32 amount = 16.f; + fdx = fdx + ((F32) dx - fdx) * llmin(gFrameIntervalSeconds*amount,1.f); + fdy = fdy + ((F32) dy - fdy) * llmin(gFrameIntervalSeconds*amount,1.f); + + mCurrentMouseDelta.set(llround(fdx), llround(fdy)); + mouse_vel.setVec(fdx,fdy); + } + else + { + mCurrentMouseDelta.set(dx, dy); + mouse_vel.setVec((F32) dx, (F32) dy); + } + mMouseVelocityStat.addValue(mouse_vel.magVec()); if (gNoRender) @@ -3377,8 +3387,8 @@ void LLViewerWindow::analyzeHit( const S32 UV_PICK_WIDTH = 41; const S32 UV_PICK_HALF_WIDTH = (UV_PICK_WIDTH - 1) / 2; U8 uv_pick_buffer[UV_PICK_WIDTH * UV_PICK_WIDTH * 4]; - S32 pick_face = ((LLVOVolume*)objectp)->getAllTEsSame() ? 0 : face; - LLFace* facep = objectp->mDrawable->getFace(objectp->getFaceIndexOffset() + pick_face); + S32 pick_face = face; + LLFace* facep = objectp->mDrawable->getFace(pick_face); gCamera->setPerspective(FOR_SELECTION, scaled_x - UV_PICK_HALF_WIDTH, scaled_y - UV_PICK_HALF_WIDTH, UV_PICK_WIDTH, UV_PICK_WIDTH, FALSE); glViewport(scaled_x - UV_PICK_HALF_WIDTH, scaled_y - UV_PICK_HALF_WIDTH, UV_PICK_WIDTH, UV_PICK_WIDTH); gPipeline.renderFaceForUVSelect(facep); @@ -3604,22 +3614,38 @@ BOOL LLViewerWindow::mousePointOnLandGlobal(const S32 x, const S32 y, LLVector3d } // Saves an image to the harddrive as "SnapshotX" where X >= 1. -BOOL LLViewerWindow::saveImageNumbered(LLImageRaw *raw) +BOOL LLViewerWindow::saveImageNumbered(LLImageRaw *raw, const LLString& extension_in) { if (! raw) { return FALSE; } + + LLString extension(extension_in); + if (extension.empty()) + { + extension = (gSavedSettings.getBOOL("CompressSnapshotsToDisk")) ? ".j2c" : ".bmp"; + } + + LLFilePicker::ESaveFilter pick_type; + if (extension == ".j2c") + pick_type = LLFilePicker::FFSAVE_J2C; + else if (extension == ".bmp") + pick_type = LLFilePicker::FFSAVE_BMP; + else if (extension == ".tga") + pick_type = LLFilePicker::FFSAVE_TGA; + else + pick_type = LLFilePicker::FFSAVE_ALL; // ??? // Get a directory if this is the first time. if (strlen(sSnapshotDir) == 0) /* Flawfinder: ignore */ { LLString proposed_name( sSnapshotBaseName ); - proposed_name.append( ".bmp" ); + proposed_name.append( extension ); // pick a directory in which to save LLFilePicker& picker = LLFilePicker::instance(); - if (!picker.getSaveFile(LLFilePicker::FFSAVE_BMP, proposed_name.c_str())) + if (!picker.getSaveFile(pick_type, proposed_name.c_str())) { // Clicked cancel return FALSE; @@ -3634,8 +3660,8 @@ BOOL LLViewerWindow::saveImageNumbered(LLImageRaw *raw) S32 length = strlen(directory); /* Flawfinder: ignore */ S32 index = length; - // Back up over ".bmp" - index -= 4; + // Back up over extension + index -= extension.length(); if (index >= 0 && directory[index] == '.') { directory[index] = '\0'; @@ -3674,10 +3700,9 @@ BOOL LLViewerWindow::saveImageNumbered(LLImageRaw *raw) do { - char extension[100]; /* Flawfinder: ignore */ - snprintf( extension, sizeof(extension), "_%.3d.bmp", i ); /* Flawfinder: ignore */ filepath = sSnapshotDir; filepath += sSnapshotBaseName; + filepath += llformat("_%.3d",i); filepath += extension; struct stat stat_info; @@ -3686,12 +3711,12 @@ BOOL LLViewerWindow::saveImageNumbered(LLImageRaw *raw) } while( -1 != err ); // search until the file is not found (i.e., stat() gives an error). - LLPointer<LLImageBMP> bmp_image = new LLImageBMP; + LLPointer<LLImageFormatted> formatted_image = LLImageFormatted::createFromExtension(extension); LLImageBase::setSizeOverride(TRUE); - BOOL success = bmp_image->encode(raw); + BOOL success = formatted_image->encode(raw); if( success ) { - success = bmp_image->save(filepath); + success = formatted_image->save(filepath); } else { @@ -3894,10 +3919,11 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei LLPipeline::toggleRenderDebugFeature((void*)LLPipeline::RENDER_DEBUG_FEATURE_UI); } - BOOL hide_hud = !gSavedSettings.getBOOL("RenderHUDInSnapshot") && gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD); + + BOOL hide_hud = !gSavedSettings.getBOOL("RenderHUDInSnapshot") && LLPipeline::sShowHUDAttachments; if (hide_hud) { - LLPipeline::toggleRenderType((void*)LLPipeline::RENDER_TYPE_HUD); + LLPipeline::sShowHUDAttachments = FALSE; } // Copy screen to a buffer @@ -4034,7 +4060,7 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei if (hide_hud) { - LLPipeline::toggleRenderType((void*)LLPipeline::RENDER_TYPE_HUD); + LLPipeline::sShowHUDAttachments = TRUE; } if (high_res) @@ -4296,6 +4322,12 @@ void LLViewerWindow::stopGL(BOOL save_state) if (!gGLManager.mIsDisabled) { llinfos << "Shutting down GL..." << llendl; + + // Pause texture decode threads (will get unpaused during main loop) + gTextureCache->pause(); + gImageDecodeThread->pause(); + gTextureFetch->pause(); + gSky.destroyGL(); stop_glerror(); @@ -4346,7 +4378,6 @@ void LLViewerWindow::restoreGL(const LLString& progress_message) LLManipTranslate::restoreGL(); gImageList.restoreGL(); gBumpImageList.restoreGL(); - gPipeline.setUseAGP(gSavedSettings.getBOOL("RenderUseAGP")); LLDynamicTexture::restoreGL(); LLVOAvatar::restoreGL(); diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index 0097a00b7a..5b56bbae06 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -189,7 +189,7 @@ public: BOOL saveSnapshot(const LLString& filename, S32 image_width, S32 image_height, BOOL show_ui = TRUE, BOOL do_rebuild = FALSE, ESnapshotType type = SNAPSHOT_TYPE_COLOR); BOOL rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_height, BOOL keep_window_aspect = TRUE, BOOL show_ui = TRUE, BOOL do_rebuild = FALSE, ESnapshotType type = SNAPSHOT_TYPE_COLOR ); - BOOL saveImageNumbered(LLImageRaw *raw); + BOOL saveImageNumbered(LLImageRaw *raw, const LLString& extension = ""); void playSnapshotAnimAndSound(); diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 193fd4e325..2c920ecde8 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -28,7 +28,6 @@ #include "timing.h" #include "llagent.h" // Get state values from here -#include "llagparray.h" #include "llviewercontrol.h" #include "llcriticaldamp.h" #include "lldir.h" @@ -191,7 +190,7 @@ const F32 UNDERWATER_FREQUENCY_DAMP = 0.33f; const F32 APPEARANCE_MORPH_TIME = 0.65f; const F32 CAMERA_SHAKE_ACCEL_THRESHOLD_SQUARED = 5.f * 5.f; const F32 TIME_BEFORE_MESH_CLEANUP = 5.f; // seconds -const S32 AVATAR_AGP_RELEASE_THRESHOLD = 10; // number of avatar instances before releasing AGP memory +const S32 AVATAR_RELEASE_THRESHOLD = 10; // number of avatar instances before releasing memory const F32 FOOT_GROUND_COLLISION_TOLERANCE = 0.25f; const F32 AVATAR_LOD_TWEAK_RANGE = 0.7f; const S32 MAX_LOD_CHANGES_PER_FRAME = 2; @@ -770,7 +769,6 @@ LLVOAvatar::LLVOAvatar( mEyesLayerSet( NULL ), mSkirtLayerSet( NULL ), mRenderPriority(1.0f), - mNumAGPVertices(0), mNameString(), mTitle(), mNameAway(FALSE), @@ -988,7 +986,7 @@ LLVOAvatar::LLVOAvatar( //------------------------------------------------------------------------- // register motions //------------------------------------------------------------------------- - if (LLCharacter::sInstances.getLength() == 1) + if (LLCharacter::sInstances.size() == 1) { LLKeyframeMotion::setVFS(gStaticVFS); addMotion( ANIM_AGENT_BUSY, LLNullMotion::create ); @@ -1132,7 +1130,8 @@ void LLVOAvatar::markDead() BOOL LLVOAvatar::isFullyBaked() { if (mIsDummy) return TRUE; - + if (getNumTEs() == 0) return FALSE; + BOOL head_baked = ( getTEImage( TEX_HEAD_BAKED )->getID() != IMG_DEFAULT_AVATAR ); BOOL upper_baked = ( getTEImage( TEX_UPPER_BAKED )->getID() != IMG_DEFAULT_AVATAR ); BOOL lower_baked = ( getTEImage( TEX_LOWER_BAKED )->getID() != IMG_DEFAULT_AVATAR ); @@ -1161,10 +1160,10 @@ void LLVOAvatar::deleteLayerSetCaches() // static BOOL LLVOAvatar::areAllNearbyInstancesBaked() { - for( LLVOAvatar* inst = (LLVOAvatar*)LLCharacter::sInstances.getFirstData(); - inst; - inst = (LLVOAvatar*)LLCharacter::sInstances.getNextData() ) + for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin(); + iter != LLCharacter::sInstances.end(); ++iter) { + LLVOAvatar* inst = (LLVOAvatar*) *iter; if( inst->isDead() ) { continue; @@ -1194,10 +1193,10 @@ void LLVOAvatar::dumpBakedStatus() { LLVector3d camera_pos_global = gAgent.getCameraPositionGlobal(); - for( LLVOAvatar* inst = (LLVOAvatar*)LLCharacter::sInstances.getFirstData(); - inst; - inst = (LLVOAvatar*)LLCharacter::sInstances.getNextData() ) + for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin(); + iter != LLCharacter::sInstances.end(); ++iter) { + LLVOAvatar* inst = (LLVOAvatar*) *iter; llinfos << "Avatar "; LLNameValue* firstname = inst->getNVPair("FirstName"); @@ -1386,11 +1385,10 @@ void LLVOAvatar::initVertexPrograms() //static void LLVOAvatar::restoreGL() { - LLVOAvatar* inst; - for( inst = (LLVOAvatar*)LLCharacter::sInstances.getFirstData(); - inst; - inst = (LLVOAvatar*)LLCharacter::sInstances.getNextData() ) + for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin(); + iter != LLCharacter::sInstances.end(); ++iter) { + LLVOAvatar* inst = (LLVOAvatar*) *iter; inst->setCompositeUpdatesEnabled( TRUE ); inst->invalidateComposite( inst->mHeadLayerSet, FALSE ); inst->invalidateComposite( inst->mLowerBodyLayerSet, FALSE ); @@ -1414,10 +1412,10 @@ void LLVOAvatar::deleteCachedImages() if (LLTexLayerSet::sHasCaches) { lldebugs << "Deleting layer set caches" << llendl; - for( LLVOAvatar* inst = (LLVOAvatar*)LLCharacter::sInstances.getFirstData(); - inst; - inst = (LLVOAvatar*)LLCharacter::sInstances.getNextData() ) + for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin(); + iter != LLCharacter::sInstances.end(); ++iter) { + LLVOAvatar* inst = (LLVOAvatar*) *iter; inst->deleteLayerSetCaches(); } LLTexLayerSet::sHasCaches = FALSE; @@ -1518,30 +1516,30 @@ void LLVOAvatar::initClass() sSkeletonInfo = new LLVOAvatarSkeletonInfo; if (!sSkeletonInfo->parseXml(sSkeletonXMLTree.getRoot())) { - llerrs << "Error parsing skeleton XML file" << llendl; + llerrs << "Error parsing skeleton XML file: " << skeleton_path << llendl; } // parse avatar_lad.xml llassert(!sAvatarInfo); sAvatarInfo = new LLVOAvatarInfo; if (!sAvatarInfo->parseXmlSkeletonNode(root)) { - llerrs << "Error parsing skeleton node in avatar XML file" << llendl; + llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl; } if (!sAvatarInfo->parseXmlMeshNodes(root)) { - llerrs << "Error parsing skeleton node in avatar XML file" << llendl; + llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl; } if (!sAvatarInfo->parseXmlColorNodes(root)) { - llerrs << "Error parsing skeleton node in avatar XML file" << llendl; + llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl; } if (!sAvatarInfo->parseXmlLayerNodes(root)) { - llerrs << "Error parsing skeleton node in avatar XML file" << llendl; + llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl; } if (!sAvatarInfo->parseXmlDriverNodes(root)) { - llerrs << "Error parsing skeleton node in avatar XML file" << llendl; + llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl; } } @@ -1557,6 +1555,19 @@ void LLVOAvatar::cleanupClass() } +void LLVOAvatar::updateSpatialExtents(LLVector3& newMin, LLVector3 &newMax) +{ + LLVector3 center = getRenderPosition(); + LLVector3 size = getScale(); + //maximum amount an animation can move avatar from drawable position + LLVector3 animation_buffer(5, 5, 5); + + newMin.setVec((center-size)-animation_buffer); + newMax.setVec(center+size+animation_buffer); + mDrawable->setPositionGroup((newMin + newMax) * 0.5f); +} + + //----------------------------------------------------------------------------- // parseSkeletonFile() //----------------------------------------------------------------------------- @@ -1709,10 +1720,13 @@ BOOL LLVOAvatar::buildSkeleton(LLVOAvatarSkeletonInfo *info) } // add special-purpose "screen" joint - mScreenp = new LLViewerJoint("mScreen", NULL); - // for now, put screen at origin, as it is only used during special - // HUD rendering mode - mScreenp->setWorldPosition(LLVector3::zero); + if (mIsSelf) + { + mScreenp = new LLViewerJoint("mScreen", NULL); + // for now, put screen at origin, as it is only used during special + // HUD rendering mode + mScreenp->setWorldPosition(LLVector3::zero); + } return TRUE; } @@ -1793,7 +1807,7 @@ void LLVOAvatar::buildCharacter() return; } - gPrintMessagesThisFrame = TRUE; +// gPrintMessagesThisFrame = TRUE; lldebugs << "Avatar load took " << timer.getElapsedTimeF32() << " seconds." << llendl; if ( ! status ) @@ -2076,7 +2090,7 @@ void LLVOAvatar::releaseMeshData() { LLMemType mt(LLMemType::MTYPE_AVATAR); - if (sInstances.getLength() < AVATAR_AGP_RELEASE_THRESHOLD || mIsDummy) + if (sInstances.size() < AVATAR_RELEASE_THRESHOLD || mIsDummy) { return; } @@ -2093,18 +2107,11 @@ void LLVOAvatar::releaseMeshData() mEyeBallRightLOD.setValid(FALSE, TRUE); mSkirtLOD.setValid(FALSE, TRUE); - //cleanup AGP data + //cleanup data if (mDrawable.notNull()) { LLFace* facep = mDrawable->getFace(0); facep->setSize(0, 0); - mNumAGPVertices = 0; - - // You need to reset the vertex data in order to guarantee - // that the data is deallocated, AND you start at the 0 index - // when you restore the face. We're assuming ONLY ONE FACE per - // avatar pool, this logic is broken if that isn't the case! - facep->getPool()->resetVertexData(0); } for (LLViewerJointAttachment *attachmentPoint = mAttachmentPoints.getFirstData(); @@ -2148,7 +2155,7 @@ void LLVOAvatar::restoreMeshData() } // force mesh update as LOD might not have changed to trigger this - updateMeshData(); + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, TRUE); } //----------------------------------------------------------------------------- @@ -2161,29 +2168,28 @@ void LLVOAvatar::updateMeshData() LLFace* facep = mDrawable->getFace(0); U32 num_vertices = 0; + U32 num_indices = 0; // this order is determined by number of LODS // if a mesh earlier in this list changed LODs while a later mesh doesn't, // the later mesh's index offset will be inaccurate - mEyeBallLeftLOD.updateFaceSizes(num_vertices, mAdjustedPixelArea); - mEyeBallRightLOD.updateFaceSizes(num_vertices, mAdjustedPixelArea); - mEyeLashLOD.updateFaceSizes(num_vertices, mAdjustedPixelArea); - mHeadLOD.updateFaceSizes(num_vertices, mAdjustedPixelArea); - mLowerBodyLOD.updateFaceSizes(num_vertices, mAdjustedPixelArea); - mSkirtLOD.updateFaceSizes(num_vertices, mAdjustedPixelArea); - mUpperBodyLOD.updateFaceSizes(num_vertices, mAdjustedPixelArea); - mHairLOD.updateFaceSizes(num_vertices, mAdjustedPixelArea); - - if (num_vertices != mNumAGPVertices) - { - // resize immediately -// llinfos << "Resizing avatar AGP buffer!" << llendl; - facep->getPool()->resetVertexData(num_vertices); - facep->setSize(0,0); - facep->setSize(num_vertices, 0); - mNumAGPVertices = num_vertices; - } - + mEyeBallLeftLOD.updateFaceSizes(num_vertices, num_indices, mAdjustedPixelArea); + mEyeBallRightLOD.updateFaceSizes(num_vertices, num_indices, mAdjustedPixelArea); + mEyeLashLOD.updateFaceSizes(num_vertices, num_indices, mAdjustedPixelArea); + mHeadLOD.updateFaceSizes(num_vertices, num_indices, mAdjustedPixelArea); + mLowerBodyLOD.updateFaceSizes(num_vertices, num_indices, mAdjustedPixelArea); + mSkirtLOD.updateFaceSizes(num_vertices, num_indices, mAdjustedPixelArea); + mUpperBodyLOD.updateFaceSizes(num_vertices, num_indices, mAdjustedPixelArea); + mHairLOD.updateFaceSizes(num_vertices, num_indices, mAdjustedPixelArea); + + // resize immediately + facep->setSize(num_vertices, num_indices); + + facep->mVertexBuffer = new LLVertexBufferAvatar(); + facep->mVertexBuffer->allocateBuffer(num_vertices, num_indices, TRUE); + facep->setGeomIndex(0); + facep->setIndicesIndex(0); + // This is a hack! Avatars have their own pool, so we are detecting // the case of more than one avatar in the pool (thus > 0 instead of >= 0) if (facep->getGeomIndex() > 0) @@ -2366,13 +2372,8 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) setPixelAreaAndAngle(gAgent); // Update the LOD of the joints - static const F32 UPDATE_TIME = .5f; - if (mUpdateLODTimer.hasExpired()) - { - mUpdateLODTimer.setTimerExpirySec(UPDATE_TIME * (.75f + ll_frand(0.5f))); - updateJointLODs(); - } - + //static const F32 UPDATE_TIME = .5f; + // force asynchronous drawable update if(mDrawable.notNull() && !gNoRender) { @@ -2432,6 +2433,17 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) updateCharacter(agent); + + + if (LLVOAvatar::sJointDebug) + { + llinfos << getNVPair("FirstName")->getString() << getNVPair("LastName")->getString() << ": joint touches: " << LLJoint::sNumTouches << " updates: " << LLJoint::sNumUpdates << llendl; + } + + LLJoint::sNumUpdates = 0; + LLJoint::sNumTouches = 0; + + if (gNoRender) { return TRUE; @@ -2440,7 +2452,7 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) // *NOTE: this is necessary for the floating name text above your head. if (mDrawable.notNull()) { - gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE); + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_SHADOW, TRUE); } // update attachments positions @@ -2450,8 +2462,12 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) attachment; attachment = mAttachmentPoints.getNextData()) { - LLViewerObject *attached_object = attachment->getObject(0); - if (attached_object && !attached_object->isDead() && attachment->getValid()) + LLViewerObject *attached_object = attachment->getObject(); + + BOOL visibleAttachment = isVisible() || !(attached_object && attached_object->mDrawable->getSpatialBridge() + && (attached_object->mDrawable->getSpatialBridge()->getRadius() < 2.0)); + + if (visibleAttachment && attached_object && !attached_object->isDead() && attachment->getValid()) { // if selecting any attachments, update all of them as non-damped if (gSelectMgr->getSelection()->getObjectCount() && gSelectMgr->getSelection()->isAttachment()) @@ -2605,9 +2621,9 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) const F32 FADE_DURATION = gSavedSettings.getF32("RenderNameFadeDuration"); // seconds BOOL visible_chat = gSavedSettings.getBOOL("UseChatBubbles") && (mChats.size() || mTyping); BOOL render_name = visible_chat || - (mVisible && - (sRenderName == RENDER_NAME_ALWAYS) || - (sRenderName == RENDER_NAME_FADE && time_visible < NAME_SHOW_TIME)); + (isVisible() && + ((sRenderName == RENDER_NAME_ALWAYS) || + (sRenderName == RENDER_NAME_FADE && time_visible < NAME_SHOW_TIME))); // If it's your own avatar, don't draw in mouselook, and don't // draw if we're specifically hiding our own name. if (mIsSelf) @@ -2984,6 +3000,15 @@ void LLVOAvatar::updateCharacter(LLAgent &agent) { LLMemType mt(LLMemType::MTYPE_AVATAR); + // update screen joint size + if (mScreenp) + { + F32 aspect = gCamera->getAspect(); + LLVector3 scale(1.f, aspect, 1.f); + mScreenp->setScale(scale); + mScreenp->updateWorldMatrixChildren(); + } + // clear debug text mDebugText.clear(); @@ -3020,14 +3045,6 @@ void LLVOAvatar::updateCharacter(LLAgent &agent) } } - if (LLVOAvatar::sJointDebug) - { - llinfos << getNVPair("FirstName")->getString() << ": joint touches: " << LLJoint::sNumTouches << " updates: " << LLJoint::sNumUpdates << llendl; - - LLJoint::sNumUpdates = 0; - LLJoint::sNumTouches = 0; - } -// llinfos << mPixelArea << llendl; if (gNoRender) { // Hack if we're running drones... @@ -3046,10 +3063,15 @@ void LLVOAvatar::updateCharacter(LLAgent &agent) return; } + if (!mIsSelf && !isVisible()) + { + return; + } + // change animation time quanta based on avatar render load if (!mIsSelf) { - F32 time_quantum = clamp_rescale((F32)sInstances.getLength(), 10.f, 35.f, 0.f, 0.25f); + F32 time_quantum = clamp_rescale((F32)sInstances.size(), 10.f, 35.f, 0.f, 0.25f); F32 pixel_area_scale = clamp_rescale(mPixelArea, 100, 5000, 1.f, 0.f); F32 time_step = time_quantum * pixel_area_scale; if (time_step != 0.f) @@ -3078,10 +3100,6 @@ void LLVOAvatar::updateCharacter(LLAgent &agent) mTimeVisible.reset(); } - // update screen joint size - mScreenp->setScale(LLVector3(1.f, gCamera->getAspect(), 1.f)); - mScreenp->updateWorldMatrixChildren(); - //-------------------------------------------------------------------- // create local variables in world coords for region position values //-------------------------------------------------------------------- @@ -3092,6 +3110,8 @@ void LLVOAvatar::updateCharacter(LLAgent &agent) xyVel.mV[VZ] = 0.0f; speed = xyVel.magVec(); + BOOL throttle = TRUE; + if (!(mIsSitting && getParent())) { //-------------------------------------------------------------------- @@ -3102,6 +3122,7 @@ void LLVOAvatar::updateCharacter(LLAgent &agent) if (mTimeLast == 0.0f) { mTimeLast = animation_time; + throttle = FALSE; // put the pelvis at slaved position/mRotation mRoot.setWorldPosition( getPositionAgent() ); // first frame @@ -3145,7 +3166,16 @@ void LLVOAvatar::updateCharacter(LLAgent &agent) // correct for the fact that the pelvis is not necessarily the center // of the agent's physical representation root_pos.mdV[VZ] -= (0.5f * mBodySize.mV[VZ]) - mPelvisToFoot; - mRoot.setWorldPosition(gAgent.getPosAgentFromGlobal(root_pos) ); // regular update + + + LLVector3 newPosition = gAgent.getPosAgentFromGlobal(root_pos); + + if (newPosition != mRoot.getXform()->getWorldPosition()) + { + mRoot.touch(); + mRoot.setWorldPosition(newPosition ); // regular update + } + //-------------------------------------------------------------------- // Propagate viewer object rotation to root of avatar @@ -3315,9 +3345,10 @@ void LLVOAvatar::updateCharacter(LLAgent &agent) //} //end Ventrella - F32 u = llclamp((deltaTime / pelvis_lag_time), 0.0f, 1.0f); - + F32 u = llclamp((deltaTime / pelvis_lag_time), 0.0f, 1.0f); + mRoot.setWorldRotation( slerp(u, mRoot.getWorldRotation(), wQv) ); + } } else if (mDrawable.notNull()) @@ -3329,8 +3360,17 @@ void LLVOAvatar::updateCharacter(LLAgent &agent) //-------------------------------------------------------------------- // the rest should only be done when close enough to see it //-------------------------------------------------------------------- + + + if (mPixelArea > 12.0f) + throttle = FALSE; + if (mPixelArea < 400.0f) + { + throttle = (LLDrawable::getCurrentFrame()+mID.mData[0])%2 != 0; + } + if ( !(mIsSitting && getParent()) && - ((mPixelArea < 12.0f) || + (throttle || (!isVisible() && (mPixelArea < MIN_PIXEL_AREA_FOR_COMPOSITE))) ) { mRoot.setWorldRotation( getRotation() ); @@ -3434,7 +3474,7 @@ void LLVOAvatar::updateCharacter(LLAgent &agent) } } } - + mRoot.updateWorldMatrixChildren(); if (!mDebugText.size() && mText.notNull()) @@ -3491,10 +3531,8 @@ void LLVOAvatar::updateVisibility(BOOL force_invisible) else if (!force_invisible) { // calculate avatar distance wrt head - LLVector3 pos = mDrawable->getPositionAgent(); - pos -= gCamera->getOrigin(); - mDrawable->mDistanceWRTCamera = pos.magVec(); - + mDrawable->updateDistance(*gCamera); + if (!mDrawable->getSpatialGroup() || mDrawable->getSpatialGroup()->isVisible()) { visible = TRUE; @@ -3566,9 +3604,9 @@ void LLVOAvatar::updateVisibility(BOOL force_invisible) attachment; attachment = mAttachmentPoints.getNextData()) { - if (attachment->getObject(0)) + if (attachment->getObject()) { - if(attachment->getObject(0)->mDrawable->isVisible()) + if(attachment->getObject()->mDrawable->isVisible()) { llinfos << attachment->getName() << " visible" << llendl; } @@ -3592,7 +3630,6 @@ void LLVOAvatar::updateVisibility(BOOL force_invisible) { restoreMeshData(); } - gPipeline.markVisible(mDrawable); } else { @@ -3619,11 +3656,12 @@ void LLVOAvatar::updateVisibility(BOOL force_invisible) void LLVOAvatar::updateAllAvatarVisiblity() { LLVOAvatar::sNumVisibleAvatars = 0; - LLVOAvatar *avatarp; - + F32 render_priority = (F32)LLVOAvatar::sMaxVisible; - for (avatarp = (LLVOAvatar*)sInstances.getFirstData(); avatarp; avatarp = (LLVOAvatar*)sInstances.getNextData()) + for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin(); + iter != LLCharacter::sInstances.end(); ++iter) { + LLVOAvatar* avatarp = (LLVOAvatar*) *iter; if (avatarp->isDead()) { continue; @@ -3761,26 +3799,22 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass) if (pass == AVATAR_RENDER_PASS_SINGLE) { + BOOL first_pass = TRUE; if (!mIsSelf || gAgent.needsRenderHead()) { num_indices += mHeadLOD.render(mAdjustedPixelArea); + first_pass = FALSE; } - num_indices += mUpperBodyLOD.render(mAdjustedPixelArea); - num_indices += mLowerBodyLOD.render(mAdjustedPixelArea); - if( isWearingWearableType( WT_SKIRT ) ) - { - glAlphaFunc(GL_GREATER,0.25f); - num_indices += mSkirtLOD.render(mAdjustedPixelArea); - glAlphaFunc(GL_GREATER,0.01f); - } + num_indices += mUpperBodyLOD.render(mAdjustedPixelArea, first_pass); + num_indices += mLowerBodyLOD.render(mAdjustedPixelArea, FALSE); - if (!mIsSelf || gAgent.needsRenderHead()) { - num_indices += mEyeLashLOD.render(mAdjustedPixelArea); - num_indices += mHairLOD.render(mAdjustedPixelArea); + LLGLEnable blend(GL_BLEND); + LLGLEnable test(GL_ALPHA_TEST); + num_indices += renderTransparent(); } } - else if (pass == AVATAR_RENDER_PASS_CLOTHING_INNER) + /*else if (pass == AVATAR_RENDER_PASS_CLOTHING_INNER) { if (!mIsSelf || gAgent.needsRenderHead()) { @@ -3813,7 +3847,7 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass) LLViewerJointMesh::sClothingMaskImageName = mLowerMaskTexName; num_indices += mLowerBodyLOD.render(mAdjustedPixelArea); LLViewerJointMesh::sClothingMaskImageName = 0; - } + }*/ LLViewerJointMesh::sRenderPass = AVATAR_RENDER_PASS_SINGLE; @@ -3824,6 +3858,27 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass) return num_indices; } +U32 LLVOAvatar::renderTransparent() +{ + U32 num_indices = 0; + BOOL first_pass = FALSE; + if( isWearingWearableType( WT_SKIRT ) ) + { + glAlphaFunc(GL_GREATER,0.25f); + num_indices += mSkirtLOD.render(mAdjustedPixelArea, FALSE); + first_pass = FALSE; + glAlphaFunc(GL_GREATER,0.01f); + } + + if (!mIsSelf || gAgent.needsRenderHead()) + { + num_indices += mEyeLashLOD.render(mAdjustedPixelArea, first_pass); + num_indices += mHairLOD.render(mAdjustedPixelArea, FALSE); + } + + return num_indices; +} + //----------------------------------------------------------------------------- // renderRigid() //----------------------------------------------------------------------------- @@ -3852,6 +3907,39 @@ U32 LLVOAvatar::renderRigid() return num_indices; } +U32 LLVOAvatar::renderFootShadows() +{ + U32 num_indices = 0; + + if (!mIsBuilt) + { + return 0; + } + + if (mIsSelf && (!gAgent.needsRenderAvatar() || !gAgent.needsRenderHead())) + { + return 0; + } + + if (!mIsBuilt) + { + return 0; + } + + U32 foot_mask = LLVertexBuffer::MAP_VERTEX | + LLVertexBuffer::MAP_TEXCOORD; + + //render foot shadows + LLGLEnable blend(GL_BLEND); + mShadowImagep->bind(); + glColor4fv(mShadow0Facep->getRenderColor().mV); + mShadow0Facep->renderIndexed(foot_mask); + glColor4fv(mShadow1Facep->getRenderColor().mV); + mShadow1Facep->renderIndexed(foot_mask); + + return num_indices; +} + //----------------------------------------------------------------------------- // renderCollisionVolumes() //----------------------------------------------------------------------------- @@ -3868,6 +3956,7 @@ void LLVOAvatar::renderCollisionVolumes() //------------------------------------------------------------------------ void LLVOAvatar::updateTextures(LLAgent &agent) { + LLFastTimer ftm(LLFastTimer::FTM_TEMP5); BOOL render_avatar = TRUE; if (mIsDummy || gNoRender) @@ -3942,6 +4031,8 @@ void LLVOAvatar::updateTextures(LLAgent &agent) } */ + mMaxPixelArea = 0.f; + mMinPixelArea = 99999999.f; for (U32 i = 0; i < getNumTEs(); i++) { LLViewerImage *imagep = getTEImage(i); @@ -4039,40 +4130,35 @@ void LLVOAvatar::updateTextures(LLAgent &agent) case TEX_HEAD_BAKED: if (head_baked) { - imagep->setBoostLevel(boost_level); - imagep->addTextureStats(mPixelArea, texel_area_ratio); + addBakedTextureStats( imagep, mPixelArea, texel_area_ratio, boost_level ); } break; case TEX_UPPER_BAKED: if (upper_baked) { - imagep->setBoostLevel(boost_level); - imagep->addTextureStats(mPixelArea, texel_area_ratio); + addBakedTextureStats( imagep, mPixelArea, texel_area_ratio, boost_level ); } break; case TEX_LOWER_BAKED: if (lower_baked) { - imagep->setBoostLevel(boost_level); - imagep->addTextureStats(mPixelArea, texel_area_ratio); + addBakedTextureStats( imagep, mPixelArea, texel_area_ratio, boost_level ); } break; case TEX_EYES_BAKED: if (eyes_baked) { - imagep->setBoostLevel(boost_level); - imagep->addTextureStats(mPixelArea, texel_area_ratio); + addBakedTextureStats( imagep, mPixelArea, texel_area_ratio, boost_level ); } break; case TEX_SKIRT_BAKED: if (skirt_baked) { - imagep->setBoostLevel(boost_level); - imagep->addTextureStats(mPixelArea, texel_area_ratio); + addBakedTextureStats( imagep, mPixelArea, texel_area_ratio, boost_level ); } break; @@ -4080,15 +4166,8 @@ void LLVOAvatar::updateTextures(LLAgent &agent) // Hair is neither a local texture used for baking, nor the output // of the baking process. It's just a texture that happens to be // used to draw avatars. Hence BOOST_AVATAR. JC - if (mIsSelf) - { - imagep->setBoostLevel(LLViewerImage::BOOST_AVATAR_SELF); - } - else - { - imagep->setBoostLevel(LLViewerImage::BOOST_AVATAR); - } - imagep->addTextureStats(mPixelArea, texel_area_ratio); + boost_level = mIsSelf ? LLViewerImage::BOOST_AVATAR_SELF : LLViewerImage::BOOST_AVATAR; + addBakedTextureStats( imagep, mPixelArea, texel_area_ratio, boost_level ); break; default: @@ -4098,6 +4177,11 @@ void LLVOAvatar::updateTextures(LLAgent &agent) } } + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_AREA)) + { + setDebugText(llformat("%4.0f:%4.0f", fsqrtf(mMinPixelArea),fsqrtf(mMaxPixelArea))); + } + if( render_avatar ) { mShadowImagep->addTextureStats(mPixelArea, 1.f); @@ -4127,6 +4211,15 @@ void LLVOAvatar::addLocalTextureStats( LLVOAvatar::ELocTexIndex idx, LLViewerIma } } + +void LLVOAvatar::addBakedTextureStats( LLViewerImage* imagep, F32 pixel_area, F32 texel_area_ratio, S32 boost_level) +{ + mMaxPixelArea = llmax(pixel_area, mMaxPixelArea); + mMinPixelArea = llmin(pixel_area, mMinPixelArea); + imagep->addTextureStats(pixel_area, texel_area_ratio); + imagep->setBoostLevel(boost_level); +} + //----------------------------------------------------------------------------- // resolveHeight() //----------------------------------------------------------------------------- @@ -4611,7 +4704,7 @@ F32 LLVOAvatar::getTimeDilation() //----------------------------------------------------------------------------- // LLVOAvatar::getPixelArea() //----------------------------------------------------------------------------- -F32 LLVOAvatar::getPixelArea() +F32 LLVOAvatar::getPixelArea() const { if (mIsDummy) { @@ -4973,6 +5066,11 @@ BOOL LLVOAvatar::loadSkeletonNode () iter != sAvatarInfo->mAttachmentInfoList.end(); iter++) { LLVOAvatarInfo::LLVOAvatarAttachmentInfo *info = *iter; + if (!isSelf() && info->mJointName == "mScreen") + { //don't process screen joint for other avatars + continue; + } + LLViewerJointAttachment* attachment = new LLViewerJointAttachment(); attachment->setName(info->mName); @@ -5323,15 +5421,6 @@ void LLVOAvatar::setPixelAreaAndAngle(LLAgent &agent) { LLMemType mt(LLMemType::MTYPE_AVATAR); - LLVector3 viewer_pos_agent = agent.getCameraPositionAgent(); - LLVector3 pos_agent; - - pos_agent = getRenderPosition(); - - F32 dx = viewer_pos_agent.mV[VX] - pos_agent.mV[VX]; - F32 dy = viewer_pos_agent.mV[VY] - pos_agent.mV[VY]; - F32 dz = viewer_pos_agent.mV[VZ] - pos_agent.mV[VZ]; - F32 max_scale = getMaxScale(); F32 mid_scale = getMidScale(); F32 min_scale = llmin( getScale().mV[VX], llmin( getScale().mV[VY], getScale().mV[VZ] ) ); @@ -5340,7 +5429,7 @@ void LLVOAvatar::setPixelAreaAndAngle(LLAgent &agent) // to try to get a min distance from face, subtract min_scale/2 from the range. // This means we'll load too much detail sometimes, but that's better than not enough // I don't think there's a better way to do this without calculating distance per-poly - F32 range = sqrt(dx*dx + dy*dy + dz*dz) - min_scale/2; + F32 range = (getRenderPosition()-gCamera->getOrigin()).magVec() - min_scale/2; if (range < 0.001f) // range == zero { @@ -5375,17 +5464,11 @@ void LLVOAvatar::setPixelAreaAndAngle(LLAgent &agent) //----------------------------------------------------------------------------- // updateJointLODs() //----------------------------------------------------------------------------- -void LLVOAvatar::updateJointLODs() +BOOL LLVOAvatar::updateJointLODs() { - if (!mMeshValid) - { - return; - } - F32 lod_factor = (sLODFactor * AVATAR_LOD_TWEAK_RANGE + (1.f - AVATAR_LOD_TWEAK_RANGE)); F32 avatar_num_min_factor = clamp_rescale(sLODFactor, 0.f, 1.f, 0.25f, 0.6f); F32 avatar_num_factor = clamp_rescale((F32)sNumVisibleAvatars, 8, 25, 1.f, avatar_num_min_factor); - { if (mIsSelf) { @@ -5408,16 +5491,17 @@ void LLVOAvatar::updateJointLODs() mAdjustedPixelArea = (F32)mPixelArea * lod_factor * lod_factor * avatar_num_factor * avatar_num_factor; } - // now select meshes to render based on adjusted pixel area, and perform AGP data push as necessary + // now select meshes to render based on adjusted pixel area BOOL res = mRoot.updateLOD(mAdjustedPixelArea, TRUE); if (res) { sNumLODChangesThisFrame++; - updateMeshData(); + dirtyMesh(); + return TRUE; } } - return; + return FALSE; } //----------------------------------------------------------------------------- @@ -5428,24 +5512,22 @@ LLDrawable *LLVOAvatar::createDrawable(LLPipeline *pipeline) pipeline->allocDrawable(this); mDrawable->setLit(FALSE); - LLDrawPool *poolp = gPipeline.getPool(LLDrawPool::POOL_AVATAR); + LLDrawPoolAvatar *poolp = (LLDrawPoolAvatar*) gPipeline.getPool(LLDrawPool::POOL_AVATAR); // Only a single face (one per avatar) mDrawable->setState(LLDrawable::ACTIVE); mDrawable->addFace(poolp, NULL); + mDrawable->setRenderType(LLPipeline::RENDER_TYPE_AVATAR); - poolp = gPipeline.getPool(LLDrawPool::POOL_ALPHA); - LLFace *facep; // Add faces for the foot shadows - facep = mDrawable->addFace(poolp, mShadowImagep); + facep = mDrawable->addFace((LLFacePool*) NULL, mShadowImagep); mShadow0Facep = facep; - facep = mDrawable->addFace(poolp, mShadowImagep); + facep = mDrawable->addFace((LLFacePool*) NULL, mShadowImagep); mShadow1Facep = facep; - gPipeline.markMaterialed(mDrawable); dirtyMesh(); return mDrawable; } @@ -5456,6 +5538,7 @@ LLDrawable *LLVOAvatar::createDrawable(LLPipeline *pipeline) //----------------------------------------------------------------------------- BOOL LLVOAvatar::updateGeometry(LLDrawable *drawable) { + LLFastTimer ftm(LLFastTimer::FTM_UPDATE_AVATAR); if (!(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_AVATAR))) { return TRUE; @@ -5471,30 +5554,9 @@ BOOL LLVOAvatar::updateGeometry(LLDrawable *drawable) llerrs << "LLVOAvatar::updateGeometry() called with NULL drawable" << llendl; } - // Update the shadow, tractor, and text label geometry. - - updateShadowFaces(); - - if (!drawable->isVisible()) - { - return TRUE; - } - - LLFace* facep = drawable->getFace(0); - if (!mDirtyMesh && !facep->getDirty()) - { - return TRUE; - } - - // U32 num_vertices = 0; - - updateMeshData(); - - mDirtyMesh = FALSE; return TRUE; } - //----------------------------------------------------------------------------- // updateShadowFaces() //----------------------------------------------------------------------------- @@ -5710,28 +5772,26 @@ void LLVOAvatar::removeChild(LLViewerObject *childp) detachObject(childp); } -//----------------------------------------------------------------------------- -// attachObject() -//----------------------------------------------------------------------------- -BOOL LLVOAvatar::attachObject(LLViewerObject *viewer_object) +LLViewerJointAttachment* LLVOAvatar::getTargetAttachmentPoint(LLViewerObject* viewer_object) { S32 attachmentID = ATTACHMENT_ID_FROM_STATE(viewer_object->getState()); - //clamp((S32)(viewer_object->getState() & AGENT_ATTACH_MASK) >> AGENT_ATTACH_OFFSET, 1, 0xff); - - //if (mIsSelf) - //{ - // gSelectMgr->deselectObjectAndFamily(viewer_object); - //} LLViewerJointAttachment* attachment = mAttachmentPoints.getIfThere(attachmentID); if (!attachment) { - llwarns << "Tried to attach object to invalid attachment point: " << attachmentID << llendl; - return FALSE; + llwarns << "Object attachment point invalid: " << attachmentID << llendl; } -// LLQuaternion object_world_rot = viewer_object->getWorldRotation(); + return attachment; +} + +//----------------------------------------------------------------------------- +// attachObject() +//----------------------------------------------------------------------------- +BOOL LLVOAvatar::attachObject(LLViewerObject *viewer_object) +{ + LLViewerJointAttachment* attachment = getTargetAttachmentPoint(viewer_object); if (!attachment->addObject(viewer_object)) { @@ -5744,10 +5804,6 @@ BOOL LLVOAvatar::attachObject(LLViewerObject *viewer_object) gSelectMgr->updatePointAt(); } -// LLQuaternion desired_rot = (object_world_rot * ~attachment->getWorldRotation()); - - lldebugs << "Attaching object (" << attachmentID << ") item_id=" << attachment->getItemID() << " task_id=" << viewer_object->getID() << "to " << attachment->getName() << llendl; - if (mIsSelf) { updateAttachmentVisibility(gAgent.getCameraMode()); @@ -5780,6 +5836,23 @@ void LLVOAvatar::lazyAttach() } } +void LLVOAvatar::resetHUDAttachments() +{ + for(LLViewerJointAttachment* attachment = mAttachmentPoints.getFirstData(); + attachment; + attachment = mAttachmentPoints.getNextData()) + { + if (attachment->getIsHUDAttachment()) + { + LLViewerObject* obj = attachment->getObject(); + if (obj && obj->mDrawable.notNull()) + { + gPipeline.markMoved(obj->mDrawable); + } + } + } +} + //----------------------------------------------------------------------------- // detachObject() //----------------------------------------------------------------------------- @@ -5790,7 +5863,7 @@ BOOL LLVOAvatar::detachObject(LLViewerObject *viewer_object) attachment = mAttachmentPoints.getNextData()) { // only one object per attachment point for now - if (attachment->getObject(0) == viewer_object) + if (attachment->getObject() == viewer_object) { LLUUID item_id = attachment->getItemID(); attachment->removeObject(viewer_object); @@ -5983,7 +6056,7 @@ LLViewerObject* LLVOAvatar::getWornAttachment( const LLUUID& inv_item_id ) { if( attachment_point->getItemID() == inv_item_id ) { - return attachment_point->getObject(0); + return attachment_point->getObject(); } } return NULL; @@ -6321,10 +6394,10 @@ const LLUUID& LLVOAvatar::getLocalTextureID( S32 index ) void LLVOAvatar::dumpTotalLocalTextureByteCount() { S32 total_gl_bytes = 0; - for( LLVOAvatar* cur = (LLVOAvatar*)LLCharacter::sInstances.getFirstData(); - cur; - cur = (LLVOAvatar*)LLCharacter::sInstances.getNextData() ) + for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin(); + iter != LLCharacter::sInstances.end(); ++iter) { + LLVOAvatar* cur = (LLVOAvatar*) *iter; S32 gl_bytes = 0; cur->getLocalTextureByteCount(&gl_bytes ); total_gl_bytes += gl_bytes; @@ -7724,7 +7797,7 @@ BOOL LLVOAvatar::hasHUDAttachment() attachment; attachment = mAttachmentPoints.getNextData()) { - if (attachment->getIsHUDAttachment() && attachment->getObject(0)) + if (attachment->getIsHUDAttachment() && attachment->getObject()) { return TRUE; } @@ -7739,9 +7812,9 @@ LLBBox LLVOAvatar::getHUDBBox() attachment; attachment = mAttachmentPoints.getNextData()) { - if (attachment->getIsHUDAttachment() && attachment->getObject(0)) + if (attachment->getIsHUDAttachment() && attachment->getObject()) { - LLViewerObject* hud_object = attachment->getObject(0); + LLViewerObject* hud_object = attachment->getObject(); // initialize bounding box to contain identity orientation and center point for attached object bbox.addPointLocal(hud_object->getPosition()); @@ -7759,52 +7832,6 @@ LLBBox LLVOAvatar::getHUDBBox() void LLVOAvatar::rebuildHUD() { - if (!mIsSelf) - { - return; - } - - for(LLViewerJointAttachment *attachment = mAttachmentPoints.getFirstData(); - attachment; - attachment = mAttachmentPoints.getNextData()) - { - if (attachment->getIsHUDAttachment() && attachment->getObject(0)) - { - LLViewerObject* hud_object = attachment->getObject(0); - LLDrawable* hud_drawable = hud_object->mDrawable; - - if (hud_drawable) - { - // this assumes that an AGP sync will happen because face has been backlisted, - // so that pool has been rebuilt this frame and is scheduled for a sync - for(S32 face_index = 0; face_index < hud_drawable->getNumFaces(); ++face_index) - { - LLFace* facep = hud_drawable->getFace(face_index); - if (facep->isState(LLFace::BACKLIST)) - { - facep->restore(); - } - } - } - for (U32 child_num = 0; child_num < hud_object->mChildList.size(); ++child_num) - { - LLViewerObject* childp = hud_object->mChildList[child_num]; - LLDrawable* child_drawable = childp->mDrawable; - - if (child_drawable) - { - for(S32 face_index = 0; face_index < child_drawable->getNumFaces(); ++face_index) - { - LLFace* facep = child_drawable->getFace(face_index); - if (facep->isState(LLFace::BACKLIST)) - { - facep->restore(); - } - } - } - } - } - } } //----------------------------------------------------------------------------- @@ -8061,8 +8088,7 @@ void LLVOAvatar::onBakedTextureMasksLoaded( BOOL success, LLViewerImage *src_vi, { if (!aux_src->getData()) { - llwarns << "No auxiliary source data for onBakedTextureMasksLoaded" << llendl; - src_vi->startImageDecode(); + llerrs << "No auxiliary source data for onBakedTextureMasksLoaded" << llendl; return; } @@ -8370,10 +8396,10 @@ void LLVOAvatar::dumpArchetypeXML( void* ) S32 LLVOAvatar::getUnbakedPixelAreaRank() { S32 rank = 1; - for( LLVOAvatar* inst = (LLVOAvatar*)LLCharacter::sInstances.getFirstData(); - inst; - inst = (LLVOAvatar*)LLCharacter::sInstances.getNextData() ) + for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin(); + iter != LLCharacter::sInstances.end(); ++iter) { + LLVOAvatar* inst = (LLVOAvatar*) *iter; if( inst == this ) { return rank; @@ -8392,16 +8418,15 @@ S32 LLVOAvatar::getUnbakedPixelAreaRank() // static void LLVOAvatar::cullAvatarsByPixelArea() { - LLVOAvatar::sInstances.bubbleSortList(); - - + std::sort(LLCharacter::sInstances.begin(), LLCharacter::sInstances.end(), CompareScreenAreaGreater()); + // Update the avatars that have changed status S32 rank = 1; - for( LLVOAvatar* inst = (LLVOAvatar*)LLCharacter::sInstances.getFirstData(); - inst; - inst = (LLVOAvatar*)LLCharacter::sInstances.getNextData() ) + for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin(); + iter != LLCharacter::sInstances.end(); ++iter) { + LLVOAvatar* inst = (LLVOAvatar*) *iter; BOOL culled; if( inst->isDead() ) { @@ -8591,8 +8616,6 @@ void LLVOAvatar::dumpLocalTextures() else { LLViewerImage* image = mLocalTexture[i]; - F32 data_progress = 0.0f; - F32 decode_progress = image->getDecodeProgress(&data_progress); llinfos << "LocTex " << names[i] << ": " << "Discard " << image->getDiscardLevel() << ", " @@ -8602,10 +8625,7 @@ void LLVOAvatar::dumpLocalTextures() // makes textures easier to steal << image->getID() << " " #endif - << "Data: " << (data_progress * 100) << "% " - << "Decode: " << (decode_progress * 100) << "% " - << "Priority: " << image->getDecodePriority() << " " - << (image->needsDecode() ? "pending decode" : "not pending decode") + << "Priority: " << image->getDecodePriority() << llendl; } } @@ -8707,7 +8727,7 @@ BOOL LLVOAvatarBoneInfo::parseXml(LLXmlTreeNode* node) } else { - llerrs << "Invalid node " << node->getName() << llendl; + llwarns << "Invalid node " << node->getName() << llendl; return FALSE; } @@ -8765,7 +8785,7 @@ BOOL LLVOAvatarSkeletonInfo::parseXml(LLXmlTreeNode* node) static LLStdStringHandle num_bones_string = LLXmlTree::addAttributeString("num_bones"); if (!node->getFastAttributeS32(num_bones_string, mNumBones)) { - llerrs << "Couldn't find number of bones." << llendl; + llwarns << "Couldn't find number of bones." << llendl; return FALSE; } @@ -8779,7 +8799,8 @@ BOOL LLVOAvatarSkeletonInfo::parseXml(LLXmlTreeNode* node) if (!info->parseXml(child)) { delete info; - llerrs << "Error parsing bone in skeleton file" << llendl; + llwarns << "Error parsing bone in skeleton file" << llendl; + return FALSE; } mBoneInfoList.push_back(info); } @@ -9210,7 +9231,7 @@ void LLVOAvatar::writeCAL3D(std::string& path, std::string& file_base) attachment; attachment = mAttachmentPoints.getNextData()) { - LLViewerObject *attached_object = attachment->getObject(0); + LLViewerObject *attached_object = attachment->getObject(); if (attached_object && !attached_object->isDead() && attached_object->mDrawable.notNull() && attached_object->getPCode() == LL_PCODE_VOLUME) { @@ -9231,7 +9252,7 @@ void LLVOAvatar::writeCAL3D(std::string& path, std::string& file_base) attachment; attachment = mAttachmentPoints.getNextData()) { - LLViewerObject *attached_object = attachment->getObject(0); + LLViewerObject *attached_object = attachment->getObject(); if (attached_object && !attached_object->isDead() && attached_object->getPCode() == LL_PCODE_VOLUME) { LLVOVolume* attached_volume = (LLVOVolume*)attached_object; @@ -9443,3 +9464,58 @@ LLHost LLVOAvatar::getObjectHost() const return LLHost::invalid; } } + +BOOL LLVOAvatar::updateLOD() +{ + BOOL res = updateJointLODs(); + + LLFace* facep = mDrawable->getFace(0); + if (facep->mVertexBuffer.isNull() || + LLVertexBuffer::sEnableVBOs && + ((facep->mVertexBuffer->getUsage() == GL_STATIC_DRAW ? TRUE : FALSE) != + (facep->getPool()->getVertexShaderLevel() > 0 ? TRUE : FALSE))) + { + mDirtyMesh = TRUE; + } + + if (mDirtyMesh || mDrawable->isState(LLDrawable::REBUILD_GEOMETRY)) + { //LOD changed or new mesh created, allocate new vertex buffer if needed + updateMeshData(); + mDirtyMesh = FALSE; + mDrawable->clearState(LLDrawable::REBUILD_GEOMETRY); + } + + if (facep->getPool()->getVertexShaderLevel() <= 0) + { + //generate animated mesh + mLowerBodyLOD.updateGeometry(); + mUpperBodyLOD.updateGeometry(); + + if( isWearingWearableType( WT_SKIRT ) ) + { + mSkirtLOD.updateGeometry(); + } + + if (!mIsSelf || gAgent.needsRenderHead()) + { + mEyeLashLOD.updateGeometry(); + mHeadLOD.updateGeometry(); + mHairLOD.updateGeometry(); + } + } + + // Update the shadow, tractor, and text label geometry. + if (mDrawable->isState(LLDrawable::REBUILD_SHADOW)) + { + updateShadowFaces(); + mDrawable->clearState(LLDrawable::REBUILD_SHADOW); + } + + return res; +} + +U32 LLVOAvatar::getPartitionType() const +{ //avatars merely exist as drawables in the bridge partition + return LLPipeline::PARTITION_BRIDGE; +} + diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 871502a373..2660e7c90d 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -57,6 +57,13 @@ class LLDriverParamInfo; class LLHUDText; class LLHUDEffectSpiral; +class LLVertexBufferAvatar : public LLVertexBuffer +{ +public: + LLVertexBufferAvatar(); + virtual void setupVertexBuffer(U32 data_mask) const; +}; + typedef enum e_mesh_id { MESH_ID_HAIR, @@ -213,6 +220,25 @@ protected: virtual ~LLVOAvatar(); public: + + struct CompareScreenAreaGreater + { + bool operator()(const LLCharacter* const& lhs, const LLCharacter* const& rhs) + { + return lhs->getPixelArea() > rhs->getPixelArea(); + } + }; + + enum + { + VERTEX_DATA_MASK = (1 << LLVertexBuffer::TYPE_VERTEX) | + (1 << LLVertexBuffer::TYPE_NORMAL) | + (1 << LLVertexBuffer::TYPE_TEXCOORD) | + (1 << LLVertexBuffer::TYPE_WEIGHT) | + (1 << LLVertexBuffer::TYPE_CLOTHWEIGHT) + } + eVertexDataMask; + LLVOAvatar(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp); /*virtual*/ void markDead(); @@ -228,20 +254,24 @@ public: const EObjectUpdateType update_type, LLDataPacker *dp); virtual BOOL idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time); + virtual BOOL updateLOD(); void setFootPlane(const LLVector4 &plane) { mFootPlane = plane; } /*virtual*/ BOOL isActive() const; // Whether this object needs to do an idleUpdate. // Graphical stuff for objects - maybe broken out into render class later? - U32 renderSkinned(EAvatarRenderPass pass); + U32 renderFootShadows(); U32 renderRigid(); - + U32 renderSkinned(EAvatarRenderPass pass); + U32 renderTransparent(); void renderCollisionVolumes(); /*virtual*/ void updateTextures(LLAgent &agent); // If setting a baked texture, need to request it from a non-local sim. /*virtual*/ S32 setTETexture(const U8 te, const LLUUID& uuid); - + + virtual U32 getPartitionType() const; + void updateVisibility(BOOL force_invisible); void updateAttachmentVisibility(U32 camera_mode); void clampAttachmentPositions(); @@ -259,11 +289,14 @@ public: void updateShadowFaces(); /*virtual*/ void setPixelAreaAndAngle(LLAgent &agent); - void updateJointLODs(); + BOOL updateJointLODs(); void writeCAL3D(std::string& path, std::string& file_base); virtual void updateRegion(LLViewerRegion *regionp); + + + void updateSpatialExtents(LLVector3& newMin, LLVector3 &newMax); //-------------------------------------------------------------------- // texture entry assignment @@ -323,7 +356,7 @@ public: virtual BOOL allocateCharacterJoints( U32 num ); virtual LLJoint *getCharacterJoint( U32 num ); virtual void requestStopMotion( LLMotion* motion ); - virtual F32 getPixelArea(); + virtual F32 getPixelArea() const; virtual LLPolyMesh* getHeadMesh(); virtual LLPolyMesh* getUpperBodyMesh(); virtual LLVector3d getPosGlobalFromAgent(const LLVector3 &position); @@ -343,7 +376,7 @@ public: // Other public functions //-------------------------------------------------------------------- BOOL allocateCollisionVolumes( U32 num ); - + void resetHUDAttachments(); static void getAnimLabels( LLDynamicArray<const char*>* labels ); static void getAnimNames( LLDynamicArray<const char*>* names ); @@ -420,6 +453,7 @@ public: virtual void addChild(LLViewerObject *childp); virtual void removeChild(LLViewerObject *childp); + LLViewerJointAttachment* getTargetAttachmentPoint(LLViewerObject* viewer_object); BOOL attachObject(LLViewerObject *viewer_object); BOOL detachObject(LLViewerObject *viewer_object); void lazyAttach(); @@ -817,7 +851,6 @@ protected: F32 mRenderPriority; F32 mAdjustedPixelArea; - S32 mNumAGPVertices; LLWString mNameString; LLString mTitle; @@ -858,6 +891,8 @@ protected: U32 mLowerMaskTexName; BOOL mCulled; + F32 mMinPixelArea; // debug + F32 mMaxPixelArea; // debug //-------------------------------------------------------------------- // Global Colors @@ -884,6 +919,7 @@ protected: void requestLayerSetUpdate(LLVOAvatar::ELocTexIndex i); void addLocalTextureStats(LLVOAvatar::ELocTexIndex i, LLViewerImage* imagep, F32 texel_area_ratio, BOOL rendered, BOOL covered_by_baked); + void addBakedTextureStats( LLViewerImage* imagep, F32 pixel_area, F32 texel_area_ratio, S32 boost_level); static void onInitialBakedTextureLoaded( BOOL success, LLViewerImage *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata ); static void onBakedTextureLoaded(BOOL success, LLViewerImage *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata); void useBakedTexture(const LLUUID& id); diff --git a/indra/newview/llvoclouds.cpp b/indra/newview/llvoclouds.cpp index b4924a45f1..1e5caa17d4 100644 --- a/indra/newview/llvoclouds.cpp +++ b/indra/newview/llvoclouds.cpp @@ -10,6 +10,8 @@ #include "llvoclouds.h" +#include "lldrawpoolalpha.h" + #include "llviewercontrol.h" #include "llagent.h" // to get camera position @@ -27,7 +29,7 @@ #include "viewer.h" LLVOClouds::LLVOClouds(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp) -: LLViewerObject(id, LL_VO_CLOUDS, regionp) +: LLAlphaObject(id, LL_VO_CLOUDS, regionp) { mCloudGroupp = NULL; mbCanSelect = FALSE; @@ -80,77 +82,132 @@ LLDrawable* LLVOClouds::createDrawable(LLPipeline *pipeline) mDrawable->setLit(FALSE); mDrawable->setRenderType(LLPipeline::RENDER_TYPE_CLOUDS); - LLDrawPool *pool = gPipeline.getPool(LLDrawPool::POOL_CLOUDS); - - mDrawable->setNumFaces(1, pool, getTEImage(0)); - return mDrawable; } BOOL LLVOClouds::updateGeometry(LLDrawable *drawable) { + LLFastTimer ftm(LLFastTimer::FTM_UPDATE_CLOUDS); if (!(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_CLOUDS))) return TRUE; - LLVector3 at; - LLVector3 up; - LLVector3 right; - LLVector3 normal(0.f,0.f,-1.f); - LLVector3 position_agent; - //LLVector3 v[4]; LLFace *facep; - const LLVector3 region_pos_agent = mRegionp->getOriginAgent(); - const LLVector3 camera_agent = gAgent.getCameraPositionAgent(); - LLVector3 center_offset = getPositionRegion(); - LLVector2 uvs[4]; - - uvs[0].setVec(0.f, 1.f); - uvs[1].setVec(0.f, 0.f); - uvs[2].setVec(1.f, 1.f); - uvs[3].setVec(1.f, 0.f); - - LLVector3 vtx[4]; - + S32 num_faces = mCloudGroupp->getNumPuffs(); - drawable->setNumFacesFast(num_faces, gPipeline.getPool(LLDrawPool::POOL_CLOUDS), getTEImage(0)); + if (num_faces > drawable->getNumFaces()) + { + drawable->setNumFacesFast(num_faces, NULL, getTEImage(0)); + } + + mDepth = (getPositionAgent()-gCamera->getOrigin())*gCamera->getAtAxis(); S32 face_indx = 0; for ( ; face_indx < num_faces; face_indx++) { facep = drawable->getFace(face_indx); - - LLStrider<LLVector3> verticesp, normalsp; - LLStrider<LLVector2> texCoordsp; - U32 *indicesp; - S32 index_offset; - - facep->setPrimType(LLTriangles); - facep->setSize(4, 6); - index_offset = facep->getGeometry(verticesp,normalsp,texCoordsp, indicesp); - if (-1 == index_offset) + if (isParticle()) { - return TRUE; + facep->setSize(1,1); } - + else + { + facep->setSize(4, 6); + } + facep->setTEOffset(face_indx); + facep->setTexture(getTEImage(0)); const LLCloudPuff &puff = mCloudGroupp->getPuff(face_indx); const LLVector3 puff_pos_agent = gAgent.getPosAgentFromGlobal(puff.getPositionGlobal()); - facep->mCenterAgent = puff_pos_agent; + facep->mCenterLocal = puff_pos_agent; + } + for ( ; face_indx < drawable->getNumFaces(); face_indx++) + { + facep = drawable->getFace(face_indx); + facep->setTEOffset(face_indx); + facep->setSize(0,0); + } + + drawable->movePartition(); + + return TRUE; +} + +BOOL LLVOClouds::isParticle() +{ + return FALSE; // gGLManager.mHasPointParameters; +} + +F32 LLVOClouds::getPartSize(S32 idx) +{ + return (CLOUD_PUFF_HEIGHT+CLOUD_PUFF_WIDTH)*0.5f; +} + +void LLVOClouds::getGeometry(S32 te, + LLStrider<LLVector3>& verticesp, + LLStrider<LLVector3>& normalsp, + LLStrider<LLVector2>& texcoordsp, + LLStrider<LLColor4U>& colorsp, + LLStrider<U32>& indicesp) +{ - LLVector3 from_camera_vec = gCamera->getAtAxis();//puff_pos_agent - camera_agent; - at = from_camera_vec; + if (te >= mCloudGroupp->getNumPuffs()) + { + return; + } + + LLDrawable* drawable = mDrawable; + LLFace *facep = drawable->getFace(te); + + if (!facep->hasGeometry()) + { + return; + } + + LLVector3 normal(0.f,0.f,-1.f); + + const LLCloudPuff &puff = mCloudGroupp->getPuff(te); + S32 index_offset = facep->getGeomIndex(); + LLColor4U color(255, 255, 255, (U8) (puff.getAlpha()*255)); + facep->setFaceColor(LLColor4(color)); + + + if (isParticle()) + { + *verticesp++ = facep->mCenterLocal; + *texcoordsp++ = LLVector2(0.5f, 0.5f); + *colorsp++ = color; + *normalsp++ = normal; + *indicesp++ = facep->getGeomIndex(); + } + else + { + LLVector3 up; + LLVector3 right; + LLVector3 at; + + const LLVector3& puff_pos_agent = facep->mCenterLocal; + LLVector2 uvs[4]; + + uvs[0].setVec(0.f, 1.f); + uvs[1].setVec(0.f, 0.f); + uvs[2].setVec(1.f, 1.f); + uvs[3].setVec(1.f, 0.f); + + LLVector3 vtx[4]; + + at = gCamera->getAtAxis(); right = at % LLVector3(0.f, 0.f, 1.f); right.normVec(); up = right % at; up.normVec(); right *= 0.5f*CLOUD_PUFF_WIDTH; up *= 0.5f*CLOUD_PUFF_HEIGHT;; - - facep->mCenterAgent = puff_pos_agent; - - LLColor4 color(1.f, 1.f, 1.f, puff.getAlpha()); - facep->setFaceColor(color); + *colorsp++ = color; + *colorsp++ = color; + *colorsp++ = color; + *colorsp++ = color; + vtx[0] = puff_pos_agent - right + up; vtx[1] = puff_pos_agent - right - up; vtx[2] = puff_pos_agent + right + up; @@ -161,10 +218,10 @@ BOOL LLVOClouds::updateGeometry(LLDrawable *drawable) *verticesp++ = vtx[2]; *verticesp++ = vtx[3]; - *texCoordsp++ = uvs[0]; - *texCoordsp++ = uvs[1]; - *texCoordsp++ = uvs[2]; - *texCoordsp++ = uvs[3]; + *texcoordsp++ = uvs[0]; + *texcoordsp++ = uvs[1]; + *texcoordsp++ = uvs[2]; + *texcoordsp++ = uvs[3]; *normalsp++ = normal; *normalsp++ = normal; @@ -179,10 +236,28 @@ BOOL LLVOClouds::updateGeometry(LLDrawable *drawable) *indicesp++ = index_offset + 3; *indicesp++ = index_offset + 2; } - for ( ; face_indx < drawable->getNumFaces(); face_indx++) +} + +U32 LLVOClouds::getPartitionType() const +{ + return LLPipeline::PARTITION_CLOUD; +} + +// virtual +void LLVOClouds::updateDrawable(BOOL force_damped) +{ + // Force an immediate rebuild on any update + if (mDrawable.notNull()) { - drawable->getFace(face_indx)->setSize(0,0); + mDrawable->updateXform(TRUE); + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE); } + clearChanged(SHIFTED); +} - return TRUE; +LLCloudPartition::LLCloudPartition() +{ + mDrawableType = LLPipeline::RENDER_TYPE_CLOUDS; + mPartitionType = LLPipeline::PARTITION_CLOUD; } + diff --git a/indra/newview/llvoclouds.h b/indra/newview/llvoclouds.h index 0debe20730..180e4703b9 100644 --- a/indra/newview/llvoclouds.h +++ b/indra/newview/llvoclouds.h @@ -19,7 +19,7 @@ class LLViewerCloudGroup; class LLCloudGroup; -class LLVOClouds : public LLViewerObject +class LLVOClouds : public LLAlphaObject { public: LLVOClouds(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp ); @@ -28,16 +28,29 @@ public: // Initialize data that's only inited once per class. static void initClass(); + void updateDrawable(BOOL force_damped); + /*virtual*/ LLDrawable* createDrawable(LLPipeline *pipeline); /*virtual*/ BOOL updateGeometry(LLDrawable *drawable); + /*virtual*/ void getGeometry(S32 te, + LLStrider<LLVector3>& verticesp, + LLStrider<LLVector3>& normalsp, + LLStrider<LLVector2>& texcoordsp, + LLStrider<LLColor4U>& colorsp, + LLStrider<U32>& indicesp); /*virtual*/ BOOL isActive() const; // Whether this object needs to do an idleUpdate. + BOOL isParticle(); + F32 getPartSize(S32 idx); /*virtual*/ void updateTextures(LLAgent &agent); /*virtual*/ void setPixelAreaAndAngle(LLAgent &agent); // generate accurate apparent angle and area - + + void updateFaceSize(S32 idx) { } BOOL idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time); + virtual U32 getPartitionType() const; + void setCloudGroup(LLCloudGroup *cgp) { mCloudGroupp = cgp; } protected: LLCloudGroup *mCloudGroupp; diff --git a/indra/newview/llvograss.cpp b/indra/newview/llvograss.cpp index b9d39272ac..418a810f6a 100644 --- a/indra/newview/llvograss.cpp +++ b/indra/newview/llvograss.cpp @@ -49,7 +49,7 @@ S32 LLVOGrass::sMaxGrassSpecies = 0; LLVOGrass::LLVOGrass(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp) -: LLViewerObject(id, pcode, regionp) +: LLAlphaObject(id, pcode, regionp) { mPatch = NULL; mLastPatchUpdateTime = 0; @@ -299,38 +299,45 @@ void LLVOGrass::setPixelAreaAndAngle(LLAgent &agent) { // This should be the camera's center, as soon as we move to all region-local. LLVector3 relative_position = getPositionAgent() - agent.getCameraPositionAgent(); - F32 range = relative_position.magVec(); // ugh, square root + F32 range = relative_position.magVec(); F32 max_scale = getMaxScale(); mAppAngle = (F32) atan2( max_scale, range) * RAD_TO_DEG; // Compute pixels per meter at the given range - F32 pixels_per_meter = gCamera->getViewHeightInPixels() / - (tan(gCamera->getView()) * range); + F32 pixels_per_meter = gCamera->getViewHeightInPixels() / (tan(gCamera->getView()) * range); - // Assume grass texture is a 1 meter by 1 meter sprite at the grass object's center - mPixelArea = (pixels_per_meter) * (pixels_per_meter); + // Assume grass texture is a 5 meter by 5 meter sprite at the grass object's center + mPixelArea = (pixels_per_meter) * (pixels_per_meter) * 25.f; } // BUG could speed this up by caching the relative_position and range calculations void LLVOGrass::updateTextures(LLAgent &agent) { - // dot_product = A B cos T - // BUT at_axis is unit, so dot_product = B cos T - LLVector3 relative_position = getPositionAgent() - agent.getCameraPositionAgent(); - F32 dot_product = relative_position * agent.getFrameAgent().getAtAxis(); - F32 cos_angle = dot_product / relative_position.magVec(); + F32 texel_area_ratio = 1.f; + F32 cos_angle = 1.f; if (getTEImage(0)) { - getTEImage(0)->addTextureStats(mPixelArea*20.f, 1.f, cos_angle); + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_AREA)) + { + setDebugText(llformat("%4.0f", fsqrtf(mPixelArea))); + } + getTEImage(0)->addTextureStats(mPixelArea, texel_area_ratio, cos_angle); } } BOOL LLVOGrass::updateLOD() { + if (mDrawable->getNumFaces() <= 0) + { + return FALSE; + } + + LLFace* face = mDrawable->getFace(0); + F32 tan_angle = 0.f; S32 num_blades = 0; @@ -344,6 +351,7 @@ BOOL LLVOGrass::updateLOD() mNumBlades <<= 1; } + face->setSize(mNumBlades*8, mNumBlades*12); gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE); } else if (num_blades <= (mNumBlades >> 1)) @@ -353,6 +361,7 @@ BOOL LLVOGrass::updateLOD() mNumBlades >>=1; } + face->setSize(mNumBlades*8, mNumBlades*12); gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE); return TRUE; } @@ -363,53 +372,20 @@ BOOL LLVOGrass::updateLOD() LLDrawable* LLVOGrass::createDrawable(LLPipeline *pipeline) { pipeline->allocDrawable(this); -// mDrawable->setLit(FALSE); mDrawable->setRenderType(LLPipeline::RENDER_TYPE_GRASS); - - LLDrawPool *pool = gPipeline.getPool(LLDrawPool::POOL_ALPHA); - - mDrawable->setNumFaces(1, pool, getTEImage(0)); - + return mDrawable; } BOOL LLVOGrass::updateGeometry(LLDrawable *drawable) { + LLFastTimer ftm(LLFastTimer::FTM_UPDATE_GRASS); plantBlades(); return TRUE; } void LLVOGrass::plantBlades() { - mPatch = mRegionp->getLand().resolvePatchRegion(getPositionRegion()); - mLastPatchUpdateTime = mPatch->getLastUpdateTime(); - - LLVector3 position; - // Create random blades of grass with gaussian distribution - F32 x,y,xf,yf,dzx,dzy; - - LLVector3 normal(0,0,1); - LLColor4U color(0,0,0,1); - - LLFace *face = mDrawable->getFace(0); - - LLStrider<LLVector3> verticesp; - LLStrider<LLVector3> normalsp; - LLStrider<LLVector2> texCoordsp; - LLStrider<LLColor4U> colorsp; - - U32 *indicesp; - - face->setPool(face->getPool(), getTEImage(0)); - face->setState(LLFace::GLOBAL); - face->setSize(mNumBlades * 4, mNumBlades * 12); - face->setPrimType(LLTriangles); - S32 index_offset = face->getGeometryColors(verticesp,normalsp,texCoordsp,colorsp,indicesp); - if (-1 == index_offset) - { - return; - } - // It is possible that the species of a grass is not defined // This is bad, but not the end of the world. if (!sSpeciesTable.count(mSpecies)) @@ -418,9 +394,49 @@ void LLVOGrass::plantBlades() return; } + if (mDrawable->getNumFaces() < 1) + { + mDrawable->setNumFaces(1, NULL, getTEImage(0)); + } + + LLFace *face = mDrawable->getFace(0); + + face->setTexture(getTEImage(0)); + face->setState(LLFace::GLOBAL); + face->setSize(mNumBlades * 8, mNumBlades * 12); + face->mVertexBuffer = NULL; + face->setTEOffset(0); + face->mCenterLocal = mPosition + mRegionp->getOriginAgent(); + + mDepth = (face->mCenterLocal - gCamera->getOrigin())*gCamera->getAtAxis(); + mDrawable->setPosition(face->mCenterLocal); + mDrawable->movePartition(); + LLPipeline::sCompiles++; +} + +void LLVOGrass::getGeometry(S32 idx, + LLStrider<LLVector3>& verticesp, + LLStrider<LLVector3>& normalsp, + LLStrider<LLVector2>& texcoordsp, + LLStrider<LLColor4U>& colorsp, + LLStrider<U32>& indicesp) +{ + mPatch = mRegionp->getLand().resolvePatchRegion(getPositionRegion()); + mLastPatchUpdateTime = mPatch->getLastUpdateTime(); + + LLVector3 position; + // Create random blades of grass with gaussian distribution + F32 x,y,xf,yf,dzx,dzy; + + LLColor4U color(255,255,255,255); + + LLFace *face = mDrawable->getFace(idx); + F32 width = sSpeciesTable[mSpecies]->mBladeSizeX; F32 height = sSpeciesTable[mSpecies]->mBladeSizeY; + U32 index_offset = face->getGeomIndex(); + for (S32 i = 0; i < mNumBlades; i++) { x = exp_x[i] * mScale.mV[VX]; @@ -430,70 +446,113 @@ void LLVOGrass::plantBlades() dzx = dz_x [i]; dzy = dz_y [i]; + LLVector3 v1,v2,v3; F32 blade_height= GRASS_BLADE_HEIGHT * height * w_mod[i]; - *texCoordsp++ = LLVector2(0, 0); - *texCoordsp++ = LLVector2(0, 0.98f); - *texCoordsp++ = LLVector2(1, 0); - *texCoordsp++ = LLVector2(1, 0.98f); + *texcoordsp++ = LLVector2(0, 0); + *texcoordsp++ = LLVector2(0, 0); + *texcoordsp++ = LLVector2(0, 0.98f); + *texcoordsp++ = LLVector2(0, 0.98f); + *texcoordsp++ = LLVector2(1, 0); + *texcoordsp++ = LLVector2(1, 0); + *texcoordsp++ = LLVector2(1, 0.98f); + *texcoordsp++ = LLVector2(1, 0.98f); position.mV[0] = mPosition.mV[VX] + x + xf; position.mV[1] = mPosition.mV[VY] + y + yf; - position.mV[2] = 0.f; position.mV[2] = mRegionp->getLand().resolveHeightRegion(position); - *verticesp++ = position + mRegionp->getOriginAgent(); + *verticesp++ = v1 = position + mRegionp->getOriginAgent(); + *verticesp++ = v1; + position.mV[0] += dzx; position.mV[1] += dzy; position.mV[2] += blade_height; - *verticesp++ = position + mRegionp->getOriginAgent(); + *verticesp++ = v2 = position + mRegionp->getOriginAgent(); + *verticesp++ = v2; position.mV[0] = mPosition.mV[VX] + x - xf; position.mV[1] = mPosition.mV[VY] + y - xf; - position.mV[2] = 0.f; position.mV[2] = mRegionp->getLand().resolveHeightRegion(position); - *verticesp++ = position + mRegionp->getOriginAgent(); + *verticesp++ = v3 = position + mRegionp->getOriginAgent(); + *verticesp++ = v3; + + LLVector3 normal1 = (v1-v2) % (v2-v3); + normal1.mV[VZ] = 0.75f; + normal1.normVec(); + LLVector3 normal2 = -normal1; + normal2.mV[VZ] = -normal2.mV[VZ]; position.mV[0] += dzx; position.mV[1] += dzy; position.mV[2] += blade_height; - *verticesp++ = position + mRegionp->getOriginAgent(); + *verticesp++ = v1 = position + mRegionp->getOriginAgent(); + *verticesp++ = v1; + + *(normalsp++) = normal1; + *(normalsp++) = normal2; + *(normalsp++) = normal1; + *(normalsp++) = normal2; - *(normalsp++) = normal; - *(normalsp++) = normal; - *(normalsp++) = normal; - *(normalsp++) = normal; + *(normalsp++) = normal1; + *(normalsp++) = normal2; + *(normalsp++) = normal1; + *(normalsp++) = normal2; *(colorsp++) = color; *(colorsp++) = color; *(colorsp++) = color; *(colorsp++) = color; + *(colorsp++) = color; + *(colorsp++) = color; + *(colorsp++) = color; + *(colorsp++) = color; *indicesp++ = index_offset + 0; - *indicesp++ = index_offset + 1; *indicesp++ = index_offset + 2; + *indicesp++ = index_offset + 4; - *indicesp++ = index_offset + 1; - *indicesp++ = index_offset + 3; *indicesp++ = index_offset + 2; + *indicesp++ = index_offset + 6; + *indicesp++ = index_offset + 4; - *indicesp++ = index_offset + 0; - *indicesp++ = index_offset + 2; *indicesp++ = index_offset + 1; + *indicesp++ = index_offset + 5; + *indicesp++ = index_offset + 3; - *indicesp++ = index_offset + 1; - *indicesp++ = index_offset + 2; *indicesp++ = index_offset + 3; - index_offset += 4; + *indicesp++ = index_offset + 5; + *indicesp++ = index_offset + 7; + index_offset += 8; } LLPipeline::sCompiles++; - - face->mCenterLocal = mPosition; - } +U32 LLVOGrass::getPartitionType() const +{ + return LLPipeline::PARTITION_GRASS; +} +LLGrassPartition::LLGrassPartition() +{ + mDrawableType = LLPipeline::RENDER_TYPE_GRASS; + mPartitionType = LLPipeline::PARTITION_GRASS; + mLODPeriod = 16; + mDepthMask = TRUE; + mSlopRatio = 0.1f; + mRenderPass = LLRenderPass::PASS_GRASS; + mBufferUsage = GL_DYNAMIC_DRAW_ARB; +} - - +// virtual +void LLVOGrass::updateDrawable(BOOL force_damped) +{ + // Force an immediate rebuild on any update + if (mDrawable.notNull()) + { + mDrawable->updateXform(TRUE); + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE); + } + clearChanged(SHIFTED); +} diff --git a/indra/newview/llvograss.h b/indra/newview/llvograss.h index ef3d30c5ea..38aef64cd8 100644 --- a/indra/newview/llvograss.h +++ b/indra/newview/llvograss.h @@ -17,7 +17,7 @@ class LLSurfacePatch; class LLViewerImage; -class LLVOGrass : public LLViewerObject +class LLVOGrass : public LLAlphaObject { public: LLVOGrass(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp); @@ -27,6 +27,8 @@ public: static void initClass(); static void cleanupClass(); + virtual U32 getPartitionType() const; + /*virtual*/ U32 processUpdateMessage(LLMessageSystem *mesgsys, void **user_data, U32 block_num, @@ -34,11 +36,19 @@ public: LLDataPacker *dp); static void import(FILE *file, LLMessageSystem *mesgsys, const LLVector3 &pos); /*virtual*/ void exportFile(FILE *file, const LLVector3 &position); - + + void updateDrawable(BOOL force_damped); /*virtual*/ LLDrawable* createDrawable(LLPipeline *pipeline); /*virtual*/ BOOL updateGeometry(LLDrawable *drawable); - + /*virtual*/ void getGeometry(S32 idx, + LLStrider<LLVector3>& verticesp, + LLStrider<LLVector3>& normalsp, + LLStrider<LLVector2>& texcoordsp, + LLStrider<LLColor4U>& colorsp, + LLStrider<U32>& indicesp); + + void updateFaceSize(S32 idx) { } /*virtual*/ void updateTextures(LLAgent &agent); /*virtual*/ BOOL updateLOD(); /*virtual*/ void setPixelAreaAndAngle(LLAgent &agent); // generate accurate apparent angle and area diff --git a/indra/newview/llvoground.cpp b/indra/newview/llvoground.cpp index dd3ef61173..ef81943718 100644 --- a/indra/newview/llvoground.cpp +++ b/indra/newview/llvoground.cpp @@ -9,6 +9,7 @@ #include "llviewerprecompiledheaders.h" #include "llvoground.h" +#include "lldrawpoolground.h" #include "llviewercontrol.h" @@ -21,7 +22,7 @@ #include "pipeline.h" LLVOGround::LLVOGround(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp) -: LLViewerObject(id, pcode, regionp) +: LLStaticViewerObject(id, pcode, regionp) { mbCanSelect = FALSE; } @@ -38,10 +39,10 @@ BOOL LLVOGround::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) return TRUE; } - if (mDrawable) + /*if (mDrawable) { gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE); - } + }*/ return TRUE; } @@ -56,7 +57,8 @@ LLDrawable *LLVOGround::createDrawable(LLPipeline *pipeline) pipeline->allocDrawable(this); mDrawable->setLit(FALSE); - LLDrawPool *poolp = gPipeline.getPool(LLDrawPool::POOL_GROUND); + mDrawable->setRenderType(LLPipeline::RENDER_TYPE_GROUND); + LLDrawPoolGround *poolp = (LLDrawPoolGround*) gPipeline.getPool(LLDrawPool::POOL_GROUND); mDrawable->addFace(poolp, NULL); @@ -68,15 +70,25 @@ BOOL LLVOGround::updateGeometry(LLDrawable *drawable) LLStrider<LLVector3> verticesp; LLStrider<LLVector3> normalsp; LLStrider<LLVector2> texCoordsp; - U32 *indicesp; + LLStrider<U32> indicesp; S32 index_offset; LLFace *face; + LLDrawPoolGround *poolp = (LLDrawPoolGround*) gPipeline.getPool(LLDrawPool::POOL_GROUND); + if (drawable->getNumFaces() < 1) - drawable->addFace(gPipeline.getPool(LLDrawPool::POOL_GROUND), NULL); + drawable->addFace(poolp, NULL); face = drawable->getFace(0); - face->setPrimType(LLTriangles); - face->setSize(6, 12); + + if (face->mVertexBuffer.isNull()) + { + face->setSize(5, 12); + face->mVertexBuffer = new LLVertexBuffer(LLDrawPoolGround::VERTEX_DATA_MASK, GL_STREAM_DRAW_ARB); + face->mVertexBuffer->allocateBuffer(face->getGeomCount(), face->getIndicesCount(), TRUE); + face->setGeomIndex(0); + face->setIndicesIndex(0); + } + index_offset = face->getGeometry(verticesp,normalsp,texCoordsp, indicesp); if (-1 == index_offset) { @@ -98,68 +110,40 @@ BOOL LLVOGround::updateGeometry(LLDrawable *drawable) left_dir.normVec(); // Our center top point - LLVector3 center_top, center_bottom; - LLColor4 ground_color = gSky.getFogColor(); ground_color.mV[3] = 1.f; face->setFaceColor(ground_color); - if (gCamera->getOrigin().mV[VZ] < gAgent.getRegion()->getWaterHeight()) - { - // Underwater - //center_top = gCamera->getOrigin() + at_dir*gCamera->getFar(); - center_top = gCamera->getOrigin() - LLVector3(0, 0, 5); - center_bottom = gCamera->getOrigin() + at_dir*gCamera->getFar();; - //center_top.mV[VZ] = gAgent.getRegion()->getWaterHeight() + 0.5f; - center_bottom.mV[VZ] = -100.f; - } - else - { - // Above water - center_top = gCamera->getOrigin() - LLVector3(0, 0, 30); - if ((gPipeline.getVertexShaderLevel(LLPipeline::SHADER_ENVIRONMENT) > 0)) - { - center_top.mV[VZ] = gAgent.getRegion()->getWaterHeight(); - } - //center_top = gCamera->getOrigin() + at_dir*9000.f; - center_bottom = gCamera->getOrigin() - at_dir*gCamera->getFar(); - //center_top.mV[VZ] = 0.f; - //center_bottom.mV[VZ] = gAgent.getRegion()->getWaterHeight(); - } - - *(verticesp++) = center_top + LLVector3(6000, 6000, 0); - *(verticesp++) = center_top + LLVector3(-6000, 6000, 0); - *(verticesp++) = center_top + LLVector3(-6000, -6000, 0); - - *(verticesp++) = center_top + LLVector3(-6000, -6000, 0); - *(verticesp++) = center_top + LLVector3(6000, -6000, 0); - *(verticesp++) = center_top + LLVector3(6000, 6000, 0); + *(verticesp++) = LLVector3(64, 64, 0); + *(verticesp++) = LLVector3(-64, 64, 0); + *(verticesp++) = LLVector3(-64, -64, 0); + *(verticesp++) = LLVector3(64, -64, 0); + *(verticesp++) = LLVector3(0, 0, -1024); // Triangles for each side *indicesp++ = index_offset + 0; *indicesp++ = index_offset + 1; - *indicesp++ = index_offset + 3; + *indicesp++ = index_offset + 4; - *indicesp++ = index_offset + 0; - *indicesp++ = index_offset + 3; + *indicesp++ = index_offset + 1; *indicesp++ = index_offset + 2; + *indicesp++ = index_offset + 4; *indicesp++ = index_offset + 2; *indicesp++ = index_offset + 3; - *indicesp++ = index_offset + 5; + *indicesp++ = index_offset + 4; - *indicesp++ = index_offset + 2; - *indicesp++ = index_offset + 5; + *indicesp++ = index_offset + 3; + *indicesp++ = index_offset + 0; *indicesp++ = index_offset + 4; *(texCoordsp++) = LLVector2(0.f, 0.f); *(texCoordsp++) = LLVector2(1.f, 0.f); - *(texCoordsp++) = LLVector2(0.f, 1.f); *(texCoordsp++) = LLVector2(1.f, 1.f); - *(texCoordsp++) = LLVector2(0.f, 2.f); - *(texCoordsp++) = LLVector2(1.f, 2.f); - + *(texCoordsp++) = LLVector2(0.f, 1.f); + *(texCoordsp++) = LLVector2(0.5f, 0.5f); + LLPipeline::sCompiles++; return TRUE; } diff --git a/indra/newview/llvoground.h b/indra/newview/llvoground.h index 228d872eaf..587b0064de 100644 --- a/indra/newview/llvoground.h +++ b/indra/newview/llvoground.h @@ -15,7 +15,7 @@ #include "llviewerimage.h" #include "llviewerobject.h" -class LLVOGround : public LLViewerObject +class LLVOGround : public LLStaticViewerObject { protected: public: diff --git a/indra/newview/llvopartgroup.cpp b/indra/newview/llvopartgroup.cpp index 38db15c0c7..b641bf6f27 100644 --- a/indra/newview/llvopartgroup.cpp +++ b/indra/newview/llvopartgroup.cpp @@ -10,6 +10,8 @@ #include "llvopartgroup.h" +#include "lldrawpoolalpha.h" + #include "llfasttimer.h" #include "message.h" #include "v2math.h" @@ -28,7 +30,7 @@ const F32 MAX_PART_LIFETIME = 120.f; extern U64 gFrameTime; LLVOPartGroup::LLVOPartGroup(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp) - : LLViewerObject(id, pcode, regionp), + : LLAlphaObject(id, pcode, regionp), mViewerPartGroupp(NULL) { setNumTEs(1); @@ -42,37 +44,37 @@ LLVOPartGroup::~LLVOPartGroup() { } + BOOL LLVOPartGroup::isActive() const { return TRUE; } +F32 LLVOPartGroup::getBinRadius() +{ + return mScale.mV[0]*2.f; +} + +void LLVOPartGroup::updateSpatialExtents(LLVector3& newMin, LLVector3& newMax) +{ + LLVector3 pos_agent = getPositionAgent(); + mExtents[0] = pos_agent - mScale; + mExtents[1] = pos_agent + mScale; + newMin = mExtents[0]; + newMax = mExtents[1]; + mDrawable->setPositionGroup(pos_agent); +} + BOOL LLVOPartGroup::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) { - if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES)) - { - gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE); - } - - // Particle groups don't need any of default idleUpdate velocity interpolation stuff. - //LLViewerObject::idleUpdate(agent, world, time); return TRUE; } - void LLVOPartGroup::setPixelAreaAndAngle(LLAgent &agent) { // mPixelArea is calculated during render - - LLVector3 viewer_pos_agent = agent.getCameraPositionAgent(); - LLVector3 pos_agent = getRenderPosition(); - - F32 dx = viewer_pos_agent.mV[VX] - pos_agent.mV[VX]; - F32 dy = viewer_pos_agent.mV[VY] - pos_agent.mV[VY]; - F32 dz = viewer_pos_agent.mV[VZ] - pos_agent.mV[VZ]; - F32 mid_scale = getMidScale(); - F32 range = sqrt(dx*dx + dy*dy + dz*dz); + F32 range = (getRenderPosition()-gCamera->getOrigin()).magVec(); if (range < 0.001f || isHUDAttachment()) // range == zero { @@ -86,7 +88,7 @@ void LLVOPartGroup::setPixelAreaAndAngle(LLAgent &agent) void LLVOPartGroup::updateTextures(LLAgent &agent) { - // Texture stats for particles will need to be updated in a different way... + // Texture stats for particles need to be updated in a different way... } @@ -95,37 +97,45 @@ LLDrawable* LLVOPartGroup::createDrawable(LLPipeline *pipeline) pipeline->allocDrawable(this); mDrawable->setLit(FALSE); mDrawable->setRenderType(LLPipeline::RENDER_TYPE_PARTICLES); - - LLDrawPool *pool = gPipeline.getPool(LLDrawPool::POOL_ALPHA); - mDrawable->setNumFaces(mViewerPartGroupp->getCount(), pool, getTEImage(0)); return mDrawable; } const F32 MAX_PARTICLE_AREA_SCALE = 0.02f; // some tuned constant, limits on how much particle area to draw -BOOL LLVOPartGroup::updateGeometry(LLDrawable *drawable) +F32 LLVOPartGroup::getPartSize(S32 idx) { - LLFastTimer t(LLFastTimer::FTM_UPDATE_PARTICLES); - - LLVector3 at; - LLVector3 up; - LLVector3 right; - LLVector3 position_agent; - LLVector3 camera_agent = gAgent.getCameraPositionAgent(); - LLVector2 uvs[4]; + if (idx < (S32) mViewerPartGroupp->mParticles.size()) + { + return mViewerPartGroupp->mParticles[idx]->mScale.mV[0]; + } + + return 0.f; +} - uvs[0].setVec(0.f, 1.f); - uvs[1].setVec(0.f, 0.f); - uvs[2].setVec(1.f, 1.f); - uvs[3].setVec(1.f, 0.f); +BOOL LLVOPartGroup::updateGeometry(LLDrawable *drawable) +{ + LLFastTimer ftm(LLFastTimer::FTM_UPDATE_PARTICLES); - LLDrawPool *drawpool = gPipeline.getPool(LLDrawPool::POOL_ALPHA); + LLVector3 at; + LLVector3 position_agent; + LLVector3 camera_agent = gCamera->getOrigin(); + S32 num_parts = mViewerPartGroupp->getCount(); LLFace *facep; - + LLSpatialGroup* group = drawable->getSpatialGroup(); + if (!group && num_parts) + { + drawable->movePartition(); + group = drawable->getSpatialGroup(); + } + if (!num_parts) { - drawable->setNumFaces(0, drawpool, getTEImage(0)); + if (drawable->getNumFaces()) + { + group->dirtyGeom(); + } + drawable->setNumFaces(0, NULL, getTEImage(0)); LLPipeline::sCompiles++; return TRUE; } @@ -135,30 +145,30 @@ BOOL LLVOPartGroup::updateGeometry(LLDrawable *drawable) return TRUE; } -// drawable->setNumFaces(num_parts, drawpool, getTEImage(0)); - drawable->setNumFacesFast(num_parts, drawpool, getTEImage(0)); - - LLVector3 normal(-gCamera->getXAxis()); // make point agent face camera - - LLStrider<LLVector3> verticesp; - LLStrider<LLVector3> normalsp; - LLStrider<LLVector2> texCoordsp; - U32 *indicesp = 0; + if (num_parts > drawable->getNumFaces()) + { + drawable->setNumFacesFast(num_parts+num_parts/4, NULL, getTEImage(0)); + } - S32 vert_offset; F32 tot_area = 0; + BOOL is_particle = isParticle(); + F32 max_area = LLViewerPartSim::getMaxPartCount() * MAX_PARTICLE_AREA_SCALE; - + F32 pixel_meter_ratio = gCamera->getPixelMeterRatio(); + pixel_meter_ratio *= pixel_meter_ratio; + S32 count=0; - for (S32 i = 0; i < num_parts; i++) + S32 i; + F32 max_width = 0.f; + mDepth = 0.f; + + for (i = 0; i < num_parts; i++) { - const LLViewerPart &part = mViewerPartGroupp->mParticles[i]; + const LLViewerPart &part = *((LLViewerPart*) mViewerPartGroupp->mParticles[i]); LLVector3 part_pos_agent(part.mPosAgent); at = part_pos_agent - camera_agent; - //F32 invcamdist = 1.0f / at.magVec(); - //area += (part.mScale.mV[0]*invcamdist)*(part.mScale.mV[1]*invcamdist); F32 camera_dist_squared = at.magVecSquared(); F32 inv_camera_dist_squared; if (camera_dist_squared > 1.f) @@ -167,29 +177,124 @@ BOOL LLVOPartGroup::updateGeometry(LLDrawable *drawable) inv_camera_dist_squared = 1.f; F32 area = part.mScale.mV[0] * part.mScale.mV[1] * inv_camera_dist_squared; tot_area += area; - if (tot_area > max_area) + + if (!is_particle && tot_area > max_area) { break; } - + count++; facep = drawable->getFace(i); + facep->setTEOffset(i); const F32 NEAR_PART_DIST_SQ = 5.f*5.f; // Only discard particles > 5 m from the camera const F32 MIN_PART_AREA = .005f*.005f; // only less than 5 mm x 5 mm at 1 m from camera - if (camera_dist_squared > NEAR_PART_DIST_SQ && area < MIN_PART_AREA) + + if (!is_particle) { - facep->setSize(0, 0); - continue; + if (camera_dist_squared > NEAR_PART_DIST_SQ && area < MIN_PART_AREA) + { + facep->setSize(0, 0); + continue; + } + + facep->setSize(4, 6); + } + else + { + facep->setSize(1,1); + } + + facep->setViewerObject(this); + + if (part.mFlags & LLPartData::LL_PART_EMISSIVE_MASK) + { + facep->setState(LLFace::FULLBRIGHT); } - facep->setSize(4, 6); - facep->mCenterAgent = part_pos_agent; - vert_offset = facep->getGeometry(verticesp,normalsp,texCoordsp, indicesp); - if (-1 == vert_offset) + else { - return TRUE; + facep->clearState(LLFace::FULLBRIGHT); } + + facep->mCenterLocal = part.mPosAgent; + facep->setFaceColor(part.mColor); + facep->setTexture(part.mImagep); + if (i == 0) + { + mExtents[0] = mExtents[1] = part.mPosAgent; + } + else + { + update_min_max(mExtents[0], mExtents[1], part.mPosAgent); + } + + max_width = llmax(max_width, part.mScale.mV[0]); + max_width = llmax(max_width, part.mScale.mV[1]); + + mPixelArea = tot_area * pixel_meter_ratio; + const F32 area_scale = 10.f; // scale area to increase priority a bit + facep->setVirtualSize(mPixelArea*area_scale); + } + for (i = count; i < drawable->getNumFaces(); i++) + { + LLFace* facep = drawable->getFace(i); + facep->setTEOffset(i); + facep->setSize(0,0); + } + + LLVector3 y = gCamera->mYAxis; + LLVector3 z = gCamera->mZAxis; + + LLVector3 pad; + for (i = 0; i < 3; i++) + { + pad.mV[i] = llmax(max_width, max_width * (fabsf(y.mV[i]) + fabsf(z.mV[i]))); + } + + mExtents[0] -= pad; + mExtents[1] += pad; + + mDrawable->movePartition(); + LLPipeline::sCompiles++; + return TRUE; +} + +void LLVOPartGroup::getGeometry(S32 idx, + LLStrider<LLVector3>& verticesp, + LLStrider<LLVector3>& normalsp, + LLStrider<LLVector2>& texcoordsp, + LLStrider<LLColor4U>& colorsp, + LLStrider<U32>& indicesp) +{ + if (idx >= (S32) mViewerPartGroupp->mParticles.size()) + { + return; + } + + const LLViewerPart &part = *((LLViewerPart*) (mViewerPartGroupp->mParticles[idx])); + + U32 vert_offset = mDrawable->getFace(idx)->getGeomIndex(); + + if (isParticle()) + { + LLVector3 part_pos_agent(part.mPosAgent); + + const LLVector3& normal = -gCamera->getXAxis(); + + *verticesp++ = part_pos_agent; + *normalsp++ = normal; + *colorsp++ = part.mColor; + *texcoordsp++ = LLVector2(0.5f, 0.5f); + *indicesp++ = vert_offset; + } + else + { + LLVector3 part_pos_agent(part.mPosAgent); + LLVector3 camera_agent = gAgent.getCameraPositionAgent(); + LLVector3 at = part_pos_agent - camera_agent; + LLVector3 up, right; + right = at % LLVector3(0.f, 0.f, 1.f); right.normVec(); up = right % at; @@ -217,31 +322,28 @@ BOOL LLVOPartGroup::updateGeometry(LLDrawable *drawable) right *= 0.5f*part.mScale.mV[0]; up *= 0.5f*part.mScale.mV[1]; + const LLVector3& normal = -gCamera->getXAxis(); + *verticesp++ = part_pos_agent + up - right; *verticesp++ = part_pos_agent - up - right; *verticesp++ = part_pos_agent + up + right; *verticesp++ = part_pos_agent - up + right; - *texCoordsp++ = uvs[0]; - *texCoordsp++ = uvs[1]; - *texCoordsp++ = uvs[2]; - *texCoordsp++ = uvs[3]; + *colorsp++ = part.mColor; + *colorsp++ = part.mColor; + *colorsp++ = part.mColor; + *colorsp++ = part.mColor; + + *texcoordsp++ = LLVector2(0.f, 1.f); + *texcoordsp++ = LLVector2(0.f, 0.f); + *texcoordsp++ = LLVector2(1.f, 1.f); + *texcoordsp++ = LLVector2(1.f, 0.f); *normalsp++ = normal; *normalsp++ = normal; *normalsp++ = normal; *normalsp++ = normal; - if (part.mFlags & LLPartData::LL_PART_EMISSIVE_MASK) - { - facep->setState(LLFace::FULLBRIGHT); - } - else - { - facep->clearState(LLFace::FULLBRIGHT); - } - facep->setFaceColor(part.mColor); - *indicesp++ = vert_offset + 0; *indicesp++ = vert_offset + 1; *indicesp++ = vert_offset + 2; @@ -250,17 +352,149 @@ BOOL LLVOPartGroup::updateGeometry(LLDrawable *drawable) *indicesp++ = vert_offset + 3; *indicesp++ = vert_offset + 2; } - for (S32 j = count; j < drawable->getNumFaces(); j++) +} + +BOOL LLVOPartGroup::isParticle() +{ + return FALSE; //gGLManager.mHasPointParameters && mViewerPartGroupp->mUniformParticles; +} + +U32 LLVOPartGroup::getPartitionType() const +{ + return LLPipeline::PARTITION_PARTICLE; +} + +LLParticlePartition::LLParticlePartition() +: LLSpatialPartition(LLDrawPoolAlpha::VERTEX_DATA_MASK) +{ + mRenderPass = LLRenderPass::PASS_ALPHA; + mDrawableType = LLPipeline::RENDER_TYPE_PARTICLES; + mPartitionType = LLPipeline::PARTITION_PARTICLE; + mBufferUsage = GL_DYNAMIC_DRAW_ARB; + mSlopRatio = 0.f; + mLODPeriod = 1; +} + +void LLParticlePartition::addGeometryCount(LLSpatialGroup* group, U32& vertex_count, U32& index_count) +{ + group->mBufferUsage = mBufferUsage; + + mFaceList.clear(); + + for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i) { - drawable->getFace(j)->setSize(0,0); + LLDrawable* drawablep = *i; + + if (drawablep->isDead()) + { + continue; + } + + LLAlphaObject* obj = (LLAlphaObject*) drawablep->getVObj(); + obj->mDepth = 0.f; + + if (drawablep->isAnimating()) + { + group->mBufferUsage = GL_STREAM_DRAW_ARB; + } + + U32 count = 0; + for (S32 j = 0; j < drawablep->getNumFaces(); ++j) + { + drawablep->updateFaceSize(j); + + LLFace* facep = drawablep->getFace(j); + if (!facep->hasGeometry()) + { + continue; + } + + count++; + facep->mDistance = (facep->mCenterLocal - gCamera->getOrigin()) * gCamera->getAtAxis(); + obj->mDepth += facep->mDistance; + + mFaceList.push_back(facep); + vertex_count += facep->getGeomCount(); + index_count += facep->getIndicesCount(); + } + + obj->mDepth /= count; } - - mPixelArea = tot_area * gCamera->getPixelMeterRatio() * gCamera->getPixelMeterRatio(); - const F32 area_scale = 10.f; // scale area to increase priority a bit - getTEImage(0)->addTextureStats(mPixelArea * area_scale); +} - LLPipeline::sCompiles++; +void LLParticlePartition::getGeometry(LLSpatialGroup* group) +{ + LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - return TRUE; + std::sort(mFaceList.begin(), mFaceList.end(), LLFace::CompareDistanceGreater()); + + U32 index_count = 0; + U32 vertex_count = 0; + + group->clearDrawMap(); + + LLVertexBuffer* buffer = group->mVertexBuffer; + + LLStrider<U32> indicesp; + LLStrider<LLVector3> verticesp; + LLStrider<LLVector3> normalsp; + LLStrider<LLVector2> texcoordsp; + LLStrider<LLColor4U> colorsp; + + buffer->getVertexStrider(verticesp); + buffer->getNormalStrider(normalsp); + buffer->getColorStrider(colorsp); + buffer->getTexCoordStrider(texcoordsp); + buffer->getIndexStrider(indicesp); + + std::vector<LLDrawInfo*>& draw_vec = group->mDrawMap[mRenderPass]; + + for (std::vector<LLFace*>::iterator i = mFaceList.begin(); i != mFaceList.end(); ++i) + { + LLFace* facep = *i; + LLAlphaObject* object = (LLAlphaObject*) facep->getViewerObject(); + facep->setGeomIndex(vertex_count); + facep->setIndicesIndex(index_count); + facep->mVertexBuffer = buffer; + facep->setPoolType(LLDrawPool::POOL_ALPHA); + object->getGeometry(facep->getTEOffset(), verticesp, normalsp, texcoordsp, colorsp, indicesp); + + vertex_count += facep->getGeomCount(); + index_count += facep->getIndicesCount(); + + S32 idx = draw_vec.size()-1; + + BOOL fullbright = facep->isState(LLFace::FULLBRIGHT); + F32 vsize = facep->getVirtualSize(); + + if (idx >= 0 && draw_vec[idx]->mEnd == facep->getGeomIndex()-1 && + draw_vec[idx]->mTexture == facep->getTexture() && + draw_vec[idx]->mEnd - draw_vec[idx]->mStart + facep->getGeomCount() <= (U32) gGLManager.mGLMaxVertexRange && + draw_vec[idx]->mCount + facep->getIndicesCount() <= (U32) gGLManager.mGLMaxIndexRange && + draw_vec[idx]->mEnd - draw_vec[idx]->mStart + facep->getGeomCount() < 4096 && + draw_vec[idx]->mFullbright == fullbright) + { + draw_vec[idx]->mCount += facep->getIndicesCount(); + draw_vec[idx]->mEnd += facep->getGeomCount(); + draw_vec[idx]->mVSize = llmax(draw_vec[idx]->mVSize, vsize); + } + else + { + U32 start = facep->getGeomIndex(); + U32 end = start + facep->getGeomCount()-1; + U32 offset = facep->getIndicesStart(); + U32 count = facep->getIndicesCount(); + LLDrawInfo* info = new LLDrawInfo(start,end,count,offset,facep->getTexture(), buffer, fullbright); + info->mVSize = vsize; + draw_vec.push_back(info); + } + } + + mFaceList.clear(); +} + +F32 LLParticlePartition::calcPixelArea(LLSpatialGroup* group, LLCamera& camera) +{ + return 1024.f; } diff --git a/indra/newview/llvopartgroup.h b/indra/newview/llvopartgroup.h index 657d1824d0..4082700971 100644 --- a/indra/newview/llvopartgroup.h +++ b/indra/newview/llvopartgroup.h @@ -16,26 +16,50 @@ class LLViewerPartGroup; -class LLVOPartGroup : public LLViewerObject +class LLVOPartGroup : public LLAlphaObject { public: + enum + { + VERTEX_DATA_MASK = (1 << LLVertexBuffer::TYPE_VERTEX) | + (1 << LLVertexBuffer::TYPE_NORMAL) | + (1 << LLVertexBuffer::TYPE_TEXCOORD) | + (1 << LLVertexBuffer::TYPE_COLOR) + } + eVertexDataMask; + LLVOPartGroup(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp); ~LLVOPartGroup(); /*virtual*/ BOOL isActive() const; // Whether this object needs to do an idleUpdate. BOOL idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time); + BOOL isParticle(); + virtual F32 getBinRadius(); + virtual void updateSpatialExtents(LLVector3& newMin, LLVector3& newMax); + virtual U32 getPartitionType() const; + /*virtual*/ void setPixelAreaAndAngle(LLAgent &agent); /*virtual*/ void updateTextures(LLAgent &agent); /*virtual*/ LLDrawable* createDrawable(LLPipeline *pipeline); /*virtual*/ BOOL updateGeometry(LLDrawable *drawable); + void getGeometry(S32 idx, + LLStrider<LLVector3>& verticesp, + LLStrider<LLVector3>& normalsp, + LLStrider<LLVector2>& texcoordsp, + LLStrider<LLColor4U>& colorsp, + LLStrider<U32>& indicesp); + void updateFaceSize(S32 idx) { } + F32 getPartSize(S32 idx); void setViewerPartGroup(LLViewerPartGroup *part_groupp) { mViewerPartGroupp = part_groupp; } + LLViewerPartGroup* getViewerPartGroup() { return mViewerPartGroupp; } + protected: LLViewerPartGroup *mViewerPartGroupp; - + LLVector3 mExtents[2]; LLColor4 mDebugColor; }; diff --git a/indra/newview/llvosky.cpp b/indra/newview/llvosky.cpp index 2f580ba5f7..eb62f8ceb0 100644 --- a/indra/newview/llvosky.cpp +++ b/indra/newview/llvosky.cpp @@ -421,7 +421,7 @@ void LLSkyTex::initEmpty(const S32 tex) } } - createTexture(tex); + createGLImage(tex); } @@ -448,10 +448,10 @@ void LLSkyTex::create(const F32 brightness_scale, const LLColor3& multiscatt) *pix = temp1.mAll; } } - createTexture(sCurrent); + createGLImage(sCurrent); } -void LLSkyTex::createTexture(S32 which) +void LLSkyTex::createGLImage(S32 which) { mImageGL[which]->createGLTexture(0, mImageRaw[which]); mImageGL[which]->setClamp(TRUE, TRUE); @@ -475,7 +475,7 @@ S32 LLVOSky::sTileResX = sResolution/NUM_TILES_X; S32 LLVOSky::sTileResY = sResolution/NUM_TILES_Y; LLVOSky::LLVOSky(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp) -: LLViewerObject(id, pcode, regionp), +: LLStaticViewerObject(id, pcode, regionp), mSun(SUN_DISK_RADIUS), mMoon(MOON_DISK_RADIUS), mBrightnessScale(1.f), mBrightnessScaleNew(0.f), @@ -1035,11 +1035,9 @@ void LLVOSky::calcBrightnessScaleAndColors() } calculateColors(); // MSMSM Moved this down here per Milo Lindens suggestion, to fix orange flashing bug at sunset. - generateScatterMap(); } - void LLVOSky::calculateColors() { const F32 h = -0.1f; @@ -1049,14 +1047,13 @@ void LLVOSky::calculateColors() F32 sun_factor = 1; // Sun Diffuse - if (calcHitsEarth(mCameraPosAgent, tosun) < 0) - { - mSunDiffuse = mBrightnessScaleGuess * mSun.getIntensity() * mTransp.calcTransp(tosun.mV[2], h); - } - else - { - mSunDiffuse = mBrightnessScaleGuess * mSun.getIntensity() * mTransp.calcTransp(0, h); - } + F32 sun_height = tosun.mV[2]; + + if (sun_height <= 0.0) + sun_height = 0.0; + + mSunDiffuse = mBrightnessScaleGuess * mSun.getIntensity() * mTransp.calcTransp(sun_height, h); + mSunDiffuse = 1.0f * color_norm(mSunDiffuse); // Sun Ambient @@ -1169,8 +1166,6 @@ BOOL LLVOSky::updateSky() return TRUE; } - setPositionAgent(gAgent.getCameraPositionAgent()); - static S32 next_frame = 0; const S32 total_no_tiles = 6 * NUM_TILES; const S32 cycle_frame_no = total_no_tiles + 1; @@ -1234,21 +1229,27 @@ BOOL LLVOSky::updateSky() LLImageRaw* raw1 = mSkyTex[side].getImageRaw(TRUE); LLImageRaw* raw2 = mSkyTex[side].getImageRaw(FALSE); raw2->copy(raw1); - mSkyTex[side].createTexture(mSkyTex[side].getWhich(FALSE)); + mSkyTex[side].createGLImage(mSkyTex[side].getWhich(FALSE)); } next_frame = 0; //llSkyTex::stepCurrent(); } - std::vector<LLPointer<LLImageRaw> > images; - for (S32 side = 0; side < 6; side++) + if (!gSavedSettings.getBOOL("RenderDynamicReflections")) { - images.push_back(mSkyTex[side].getImageRaw(FALSE)); + std::vector<LLPointer<LLImageRaw> > images; + for (S32 side = 0; side < 6; side++) + { + images.push_back(mSkyTex[side].getImageRaw(FALSE)); + } + mCubeMap->init(images); } - mCubeMap->init(images); } } + gPipeline.markRebuild(gSky.mVOGroundp->mDrawable, LLDrawable::REBUILD_ALL, TRUE); + gPipeline.markRebuild(gSky.mVOStarsp->mDrawable, LLDrawable::REBUILD_ALL, TRUE); + mForceUpdate = FALSE; } else @@ -1287,7 +1288,8 @@ LLDrawable *LLVOSky::createDrawable(LLPipeline *pipeline) poolp->setSkyTex(mSkyTex); poolp->setSun(&mSun); poolp->setMoon(&mMoon); - + mDrawable->setRenderType(LLPipeline::RENDER_TYPE_SKY); + for (S32 i = 0; i < 6; ++i) { mFace[FACE_SIDE0 + i] = mDrawable->addFace(poolp, NULL); @@ -1297,9 +1299,6 @@ LLDrawable *LLVOSky::createDrawable(LLPipeline *pipeline) mFace[FACE_MOON] = mDrawable->addFace(poolp, mMoonTexturep); mFace[FACE_BLOOM] = mDrawable->addFace(poolp, mBloomTexturep); - //mDrawable->addFace(poolp, LLViewerImage::sDefaultImagep); - gPipeline.markMaterialed(mDrawable); - return mDrawable; } @@ -1307,70 +1306,74 @@ BOOL LLVOSky::updateGeometry(LLDrawable *drawable) { if (mFace[FACE_REFLECTION] == NULL) { - mFace[FACE_REFLECTION] = drawable->addFace(gPipeline.getPool(LLDrawPool::POOL_WATER), NULL); + LLDrawPoolWater *poolp = (LLDrawPoolWater*) gPipeline.getPool(LLDrawPool::POOL_WATER); + mFace[FACE_REFLECTION] = drawable->addFace(poolp, NULL); } mCameraPosAgent = drawable->getPositionAgent(); mEarthCenter.mV[0] = mCameraPosAgent.mV[0]; mEarthCenter.mV[1] = mCameraPosAgent.mV[1]; - LLVector3 v_agent[8]; for (S32 i = 0; i < 8; ++i) { F32 x_sgn = (i&1) ? 1.f : -1.f; F32 y_sgn = (i&2) ? 1.f : -1.f; F32 z_sgn = (i&4) ? 1.f : -1.f; - v_agent[i] = mCameraPosAgent + HORIZON_DIST * LLVector3(x_sgn, y_sgn, z_sgn); + v_agent[i] = HORIZON_DIST*0.25f * LLVector3(x_sgn, y_sgn, z_sgn); } LLStrider<LLVector3> verticesp; LLStrider<LLVector3> normalsp; LLStrider<LLVector2> texCoordsp; - U32 *indicesp; + LLStrider<U32> indicesp; S32 index_offset; LLFace *face; for (S32 side = 0; side < 6; ++side) { face = mFace[FACE_SIDE0 + side]; - face->setPrimType(LLTriangles); - face->setSize(4, 6); - index_offset = face->getGeometry(verticesp,normalsp,texCoordsp, indicesp); - if (-1 == index_offset) + + if (face->mVertexBuffer.isNull()) { - return TRUE; + face->setSize(4, 6); + face->setGeomIndex(0); + face->setIndicesIndex(0); + face->mVertexBuffer = new LLVertexBuffer(LLDrawPoolSky::VERTEX_DATA_MASK, GL_STREAM_DRAW_ARB); + face->mVertexBuffer->allocateBuffer(4, 6, TRUE); + + index_offset = face->getGeometry(verticesp,normalsp,texCoordsp, indicesp); + + S32 vtx = 0; + S32 curr_bit = side >> 1; // 0/1 = Z axis, 2/3 = Y, 4/5 = X + S32 side_dir = side & 1; // even - 0, odd - 1 + S32 i_bit = (curr_bit + 2) % 3; + S32 j_bit = (i_bit + 2) % 3; + + LLVector3 axis; + axis.mV[curr_bit] = 1; + face->mCenterAgent = (F32)((side_dir << 1) - 1) * axis * HORIZON_DIST; + + vtx = side_dir << curr_bit; + *(verticesp++) = v_agent[vtx]; + *(verticesp++) = v_agent[vtx | 1 << j_bit]; + *(verticesp++) = v_agent[vtx | 1 << i_bit]; + *(verticesp++) = v_agent[vtx | 1 << i_bit | 1 << j_bit]; + + *(texCoordsp++) = TEX00; + *(texCoordsp++) = TEX01; + *(texCoordsp++) = TEX10; + *(texCoordsp++) = TEX11; + + // Triangles for each side + *indicesp++ = index_offset + 0; + *indicesp++ = index_offset + 1; + *indicesp++ = index_offset + 3; + + *indicesp++ = index_offset + 0; + *indicesp++ = index_offset + 3; + *indicesp++ = index_offset + 2; } - - S32 vtx = 0; - S32 curr_bit = side >> 1; // 0/1 = Z axis, 2/3 = Y, 4/5 = X - S32 side_dir = side & 1; // even - 0, odd - 1 - S32 i_bit = (curr_bit + 2) % 3; - S32 j_bit = (i_bit + 2) % 3; - - LLVector3 axis; - axis.mV[curr_bit] = 1; - face->mCenterAgent = mCameraPosAgent + (F32)((side_dir << 1) - 1) * axis * HORIZON_DIST; - - vtx = side_dir << curr_bit; - *(verticesp++) = v_agent[vtx]; - *(verticesp++) = v_agent[vtx | 1 << j_bit]; - *(verticesp++) = v_agent[vtx | 1 << i_bit]; - *(verticesp++) = v_agent[vtx | 1 << i_bit | 1 << j_bit]; - - *(texCoordsp++) = TEX00; - *(texCoordsp++) = TEX01; - *(texCoordsp++) = TEX10; - *(texCoordsp++) = TEX11; - - // Triangles for each side - *indicesp++ = index_offset + 0; - *indicesp++ = index_offset + 1; - *indicesp++ = index_offset + 3; - - *indicesp++ = index_offset + 0; - *indicesp++ = index_offset + 3; - *indicesp++ = index_offset + 2; } const LLVector3 &look_at = gCamera->getAtAxis(); @@ -1445,7 +1448,7 @@ BOOL LLVOSky::updateHeavenlyBodyGeometry(LLDrawable *drawable, const S32 f, cons LLStrider<LLVector3> verticesp; LLStrider<LLVector3> normalsp; LLStrider<LLVector2> texCoordsp; - U32 *indicesp; + LLStrider<U32> indicesp; S32 index_offset; LLFace *facep; @@ -1493,8 +1496,16 @@ BOOL LLVOSky::updateHeavenlyBodyGeometry(LLDrawable *drawable, const S32 f, cons hb.setVisible(TRUE); facep = mFace[f]; - facep->setPrimType(LLTriangles); - facep->setSize(4, 6); + + if (facep->mVertexBuffer.isNull()) + { + facep->setSize(4, 6); + facep->mVertexBuffer = new LLVertexBuffer(LLDrawPoolWater::VERTEX_DATA_MASK, GL_STREAM_DRAW_ARB); + facep->mVertexBuffer->allocateBuffer(facep->getGeomCount(), facep->getIndicesCount(), TRUE); + facep->setGeomIndex(0); + facep->setIndicesIndex(0); + } + index_offset = facep->getGeometry(verticesp,normalsp,texCoordsp, indicesp); if (-1 == index_offset) { @@ -1623,7 +1634,7 @@ void LLVOSky::updateSunHaloGeometry(LLDrawable *drawable ) LLStrider<LLVector3> verticesp; LLStrider<LLVector3> normalsp; LLStrider<LLVector2> texCoordsp; - U32 *indicesp; + LLStrider<U32> indicesp; S32 index_offset; LLFace *face; @@ -1642,8 +1653,16 @@ void LLVOSky::updateSunHaloGeometry(LLDrawable *drawable ) v_glow_corner[3] = draw_pos + right - up; face = mFace[FACE_BLOOM]; - face->setPrimType(LLTriangles); - face->setSize(4, 6); + + if (face->mVertexBuffer.isNull()) + { + face->setSize(4, 6); + face->setGeomIndex(0); + face->setIndicesIndex(0); + face->mVertexBuffer = new LLVertexBuffer(LLDrawPoolWater::VERTEX_DATA_MASK, GL_STREAM_DRAW_ARB); + face->mVertexBuffer->allocateBuffer(4, 6, TRUE); + } + index_offset = face->getGeometry(verticesp,normalsp,texCoordsp, indicesp); if (-1 == index_offset) { @@ -1877,15 +1896,23 @@ void LLVOSky::updateReflectionGeometry(LLDrawable *drawable, F32 H, dt_clip = -0.1f; } + LLFace *face = mFace[FACE_REFLECTION]; + + if (face->mVertexBuffer.isNull() || quads*4 != face->getGeomCount()) + { + face->setSize(quads * 4, quads * 6); + face->mVertexBuffer = new LLVertexBuffer(LLDrawPoolWater::VERTEX_DATA_MASK, GL_STREAM_DRAW_ARB); + face->mVertexBuffer->allocateBuffer(face->getGeomCount(), face->getIndicesCount(), TRUE); + face->setIndicesIndex(0); + face->setGeomIndex(0); + } + LLStrider<LLVector3> verticesp; LLStrider<LLVector3> normalsp; LLStrider<LLVector2> texCoordsp; - U32 *indicesp; + LLStrider<U32> indicesp; S32 index_offset; - LLFace *face = mFace[FACE_REFLECTION]; - - face->setPrimType(LLTriangles); - face->setSize(quads * 4, quads * 6); + index_offset = face->getGeometry(verticesp,normalsp,texCoordsp, indicesp); if (-1 == index_offset) { @@ -2113,16 +2140,14 @@ void LLVOSky::updateFog(const F32 distance) color_gamma_correct(sky_fog_color); - if (!(gPipeline.getVertexShaderLevel(LLPipeline::SHADER_ENVIRONMENT) > LLDrawPool::SHADER_LEVEL_SCATTERING)) - { - render_fog_color = sky_fog_color; - } - + render_fog_color = sky_fog_color; + if (camera_height > water_height) { fog_distance = mFogRatio * distance; LLColor4 fog(render_fog_color); glFogfv(GL_FOG_COLOR, fog.mV); + mGLFogCol = fog; } else { @@ -2142,6 +2167,7 @@ void LLVOSky::updateFog(const F32 distance) LLColor4 fogCol = brightness * (color_frac * render_fog_color + (1.f - color_frac) * LLColor4(0.f, 0.2f, 0.3f, 1.f)); fogCol.setAlpha(1); glFogfv(GL_FOG_COLOR, (F32 *) &fogCol.mV); + mGLFogCol = fogCol; } mFogColor = sky_fog_color; diff --git a/indra/newview/llvosky.h b/indra/newview/llvosky.h index c140e97e5e..c705c3951e 100644 --- a/indra/newview/llvosky.h +++ b/indra/newview/llvosky.h @@ -178,7 +178,7 @@ protected: } LLImageRaw* getImageRaw(BOOL curr=TRUE) { return mImageRaw[getWhich(curr)]; } - void createTexture(BOOL curr=TRUE); + void createGLImage(BOOL curr=TRUE); }; @@ -492,7 +492,7 @@ public: class LLCubeMap; -class LLVOSky : public LLViewerObject +class LLVOSky : public LLStaticViewerObject { public: enum @@ -574,6 +574,7 @@ public: LLColor4 getMoonAmbientColor() const { return mMoonAmbient; } const LLColor4& getTotalAmbientColor() const { return mTotalAmbient; } LLColor4 getFogColor() const { return mFogColor; } + LLColor4 getGLFogColor() const { return mGLFogCol; } LLVector3 calcUpVec(const LLVector3 &pos) const { @@ -710,6 +711,8 @@ protected: F32 sInterpVal; LLColor4 mFogColor; + LLColor4 mGLFogCol; + F32 mFogRatio; F32 mWorldScale; @@ -720,7 +723,7 @@ protected: LLColor3 mMoonDiffuse; LLColor4U mFadeColor; // Color to fade in from - LLCubeMap *mCubeMap; // Cube map for the sky + LLCubeMap *mCubeMap; // Cube map for the environment S32 mDrawRefl; LLFrameTimer mUpdateTimer; diff --git a/indra/newview/llvosurfacepatch.cpp b/indra/newview/llvosurfacepatch.cpp index ae7d46dfee..759493504e 100644 --- a/indra/newview/llvosurfacepatch.cpp +++ b/indra/newview/llvosurfacepatch.cpp @@ -10,6 +10,8 @@ #include "llvosurfacepatch.h" +#include "lldrawpoolterrain.h" + #include "lldrawable.h" #include "llface.h" #include "llprimitive.h" @@ -22,8 +24,52 @@ #include "llvovolume.h" #include "pipeline.h" +//============================================================================ + +class LLVertexBufferTerrain : public LLVertexBuffer +{ +public: + LLVertexBufferTerrain() : + LLVertexBuffer(MAP_VERTEX | MAP_NORMAL | MAP_TEXCOORD | MAP_TEXCOORD2 | MAP_COLOR, GL_DYNAMIC_DRAW_ARB) + { + }; + + // virtual + void setupVertexBuffer(U32 data_mask) const + { + if (LLDrawPoolTerrain::getDetailMode() == 0) + { + LLVertexBuffer::setupVertexBuffer(data_mask); + } + else if (data_mask & LLVertexBuffer::MAP_TEXCOORD2) + { + U8* base = useVBOs() ? NULL : mMappedData; + + glVertexPointer(3,GL_FLOAT, mStride, (void*)(base + 0)); + glNormalPointer(GL_FLOAT, mStride, (void*)(base + mOffsets[TYPE_NORMAL])); + glColorPointer(4, GL_UNSIGNED_BYTE, mStride, (void*)(base + mOffsets[TYPE_COLOR])); + + glClientActiveTextureARB(GL_TEXTURE3_ARB); + glTexCoordPointer(2,GL_FLOAT, mStride, (void*)(base + mOffsets[TYPE_TEXCOORD2])); + glClientActiveTextureARB(GL_TEXTURE2_ARB); + glTexCoordPointer(2,GL_FLOAT, mStride, (void*)(base + mOffsets[TYPE_TEXCOORD2])); + glClientActiveTextureARB(GL_TEXTURE1_ARB); + glTexCoordPointer(2,GL_FLOAT, mStride, (void*)(base + mOffsets[TYPE_TEXCOORD2])); + glClientActiveTextureARB(GL_TEXTURE0_ARB); + glTexCoordPointer(2,GL_FLOAT, mStride, (void*)(base + mOffsets[TYPE_TEXCOORD2])); + } + else + { + LLVertexBuffer::setupVertexBuffer(data_mask); + } + llglassertok(); + } +}; + +//============================================================================ + LLVOSurfacePatch::LLVOSurfacePatch(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp) -: LLViewerObject(id, LL_VO_SURFACE_PATCH, regionp) +: LLStaticViewerObject(id, LL_VO_SURFACE_PATCH, regionp) { // Terrain must draw during selection passes so it can block objects behind it. mbCanSelect = TRUE; @@ -76,9 +122,9 @@ void LLVOSurfacePatch::updateTextures(LLAgent &agent) } -LLDrawPool *LLVOSurfacePatch::getPool() +LLFacePool *LLVOSurfacePatch::getPool() { - mPool = gPipeline.getPool(LLDrawPool::POOL_TERRAIN, mPatchp->getSurface()->getSTexture()); + mPool = (LLDrawPoolTerrain*) gPipeline.getPool(LLDrawPool::POOL_TERRAIN, mPatchp->getSurface()->getSTexture()); return mPool; } @@ -106,15 +152,18 @@ LLDrawable *LLVOSurfacePatch::createDrawable(LLPipeline *pipeline) range = 3; } - LLDrawPool *poolp = getPool(); + LLFacePool *poolp = getPool(); mDrawable->addFace(poolp, NULL); + return mDrawable; } BOOL LLVOSurfacePatch::updateGeometry(LLDrawable *drawable) { + LLFastTimer ftm(LLFastTimer::FTM_UPDATE_TERRAIN); + S32 min_comp, max_comp, range; min_comp = lltrunc(mPatchp->getMinComposition()); max_comp = lltrunc(ceil(mPatchp->getMaxComposition())); @@ -166,57 +215,63 @@ BOOL LLVOSurfacePatch::updateGeometry(LLDrawable *drawable) east_stride = render_stride; } + mLastLength = length; + mLastStride = render_stride; + mLastNorthStride = north_stride; + mLastEastStride = east_stride; + + return TRUE; +} + +void LLVOSurfacePatch::updateFaceSize(S32 idx) +{ + if (idx != 0) + { + llwarns << "Terrain partition requested invalid face!!!" << llendl; + return; + } + + LLFace* facep = mDrawable->getFace(idx); + S32 num_vertices = 0; S32 num_indices = 0; - S32 new_north_offset = 0; - S32 new_east_offset = 0; - - getGeomSizesMain(render_stride, num_vertices, num_indices); - new_north_offset = num_vertices; - getGeomSizesNorth(render_stride, north_stride, num_vertices, num_indices); - new_east_offset = num_vertices; - getGeomSizesEast(render_stride, east_stride, num_vertices, num_indices); - S32 new_num_vertices = num_vertices; - S32 new_num_indices = num_indices; - - LLFace *facep = NULL; - - // Update the allocated face - LLStrider<LLVector3> verticesp; - LLStrider<LLVector3> normalsp; - LLStrider<LLVector2> texCoords0p; - LLStrider<LLVector2> texCoords1p; - LLStrider<LLColor4U> colorsp; - U32* indicesp = NULL; - S32 index_offset; - - facep = mDrawable->getFace(0); - - facep->setSize(new_num_vertices, new_num_indices); - facep->setPrimType(LLTriangles); - - index_offset = facep->getGeometryTerrain( - verticesp, - normalsp, - colorsp, - texCoords0p, - texCoords1p, - indicesp); - if (-1 == index_offset) + + if (mLastStride) { - return TRUE; + getGeomSizesMain(mLastStride, num_vertices, num_indices); + getGeomSizesNorth(mLastStride, mLastNorthStride, num_vertices, num_indices); + getGeomSizesEast(mLastStride, mLastEastStride, num_vertices, num_indices); } - mDrawable->updateLightSet(); + facep->setSize(num_vertices, num_indices); +} + +BOOL LLVOSurfacePatch::updateLOD() +{ + //mDrawable->updateLightSet(); + mDrawable->setState(LLDrawable::LIGHTING_BUILT); + return TRUE; +} + +void LLVOSurfacePatch::getGeometry(LLStrider<LLVector3> &verticesp, + LLStrider<LLVector3> &normalsp, + LLStrider<LLColor4U> &colorsp, + LLStrider<LLVector2> &texCoords0p, + LLStrider<LLVector2> &texCoords1p, + LLStrider<U32> &indicesp) +{ + LLFace* facep = mDrawable->getFace(0); + + U32 index_offset = facep->getGeomIndex(); updateMainGeometry(facep, - verticesp, - normalsp, - colorsp, - texCoords0p, - texCoords1p, - indicesp, - index_offset); + verticesp, + normalsp, + colorsp, + texCoords0p, + texCoords1p, + indicesp, + index_offset); updateNorthGeometry(facep, verticesp, normalsp, @@ -233,24 +288,6 @@ BOOL LLVOSurfacePatch::updateGeometry(LLDrawable *drawable) texCoords1p, indicesp, index_offset); - - if (mLastLength != 0) - { - // lazy, should cache the geom sizes so we know the offsets. - num_vertices = 0; - num_indices = 0; - - } - - mLastLength = length; - mLastStride = render_stride; - mLastNorthStride = north_stride; - mLastEastStride = east_stride; - - mDrawable->setState(LLDrawable::LIGHTING_BUILT); - - LLPipeline::sCompiles++; - return TRUE; } void LLVOSurfacePatch::updateMainGeometry(LLFace *facep, @@ -259,8 +296,8 @@ void LLVOSurfacePatch::updateMainGeometry(LLFace *facep, LLStrider<LLColor4U> &colorsp, LLStrider<LLVector2> &texCoords0p, LLStrider<LLVector2> &texCoords1p, - U32* &indicesp, - S32 &index_offset) + LLStrider<U32> &indicesp, + U32 &index_offset) { S32 i, j, x, y; @@ -268,7 +305,7 @@ void LLVOSurfacePatch::updateMainGeometry(LLFace *facep, S32 num_vertices, num_indices; U32 index; - render_stride = mPatchp->getRenderStride(); + render_stride = mLastStride; patch_size = mPatchp->getSurface()->getGridsPerPatchEdge(); S32 vert_size = patch_size / render_stride; @@ -364,29 +401,20 @@ void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep, LLStrider<LLColor4U> &colorsp, LLStrider<LLVector2> &texCoords0p, LLStrider<LLVector2> &texCoords1p, - U32* &indicesp, - S32 &index_offset) + LLStrider<U32> &indicesp, + U32 &index_offset) { S32 vertex_count = 0; S32 i, x, y; S32 num_vertices, num_indices; - U32 render_stride = mPatchp->getRenderStride(); + U32 render_stride = mLastStride; S32 patch_size = mPatchp->getSurface()->getGridsPerPatchEdge(); S32 length = patch_size / render_stride; S32 half_length = length / 2; - - U32 north_stride; - if (mPatchp->getNeighborPatch(NORTH)) - { - north_stride = mPatchp->getNeighborPatch(NORTH)->getRenderStride(); - } - else - { - north_stride = render_stride; - } - + U32 north_stride = mLastNorthStride; + /////////////////////////// // // Render the north strip @@ -586,27 +614,19 @@ void LLVOSurfacePatch::updateEastGeometry(LLFace *facep, LLStrider<LLColor4U> &colorsp, LLStrider<LLVector2> &texCoords0p, LLStrider<LLVector2> &texCoords1p, - U32* &indicesp, - S32 &index_offset) + LLStrider<U32> &indicesp, + U32 &index_offset) { S32 i, x, y; S32 num_vertices, num_indices; - U32 render_stride = mPatchp->getRenderStride(); + U32 render_stride = mLastStride; S32 patch_size = mPatchp->getSurface()->getGridsPerPatchEdge(); S32 length = patch_size / render_stride; S32 half_length = length / 2; - U32 east_stride; - if (mPatchp->getNeighborPatch(EAST)) - { - east_stride = mPatchp->getNeighborPatch(EAST)->getRenderStride(); - } - else - { - east_stride = render_stride; - } + U32 east_stride = mLastEastStride; // Stride lengths are the same if (east_stride == render_stride) @@ -825,10 +845,6 @@ void LLVOSurfacePatch::setPatch(LLSurfacePatch *patchp) void LLVOSurfacePatch::dirtyPatch() { - if (mDrawable) - { - gPipeline.markMoved(mDrawable); - } mDirtiedPatch = TRUE; dirtyGeom(); mDirtyTerrain = TRUE; @@ -846,6 +862,8 @@ void LLVOSurfacePatch::dirtyGeom() if (mDrawable) { gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE); + mDrawable->getFace(0)->mVertexBuffer = NULL; + mDrawable->movePartition(); } } @@ -918,7 +936,67 @@ void LLVOSurfacePatch::updateSpatialExtents(LLVector3& newMin, LLVector3 &newMax { LLVector3 posAgent = getPositionAgent(); LLVector3 scale = getScale(); - newMin = posAgent-scale; - newMax = posAgent+scale; + newMin = posAgent-scale*0.5f; + newMax = posAgent+scale*0.5f; mDrawable->setPositionGroup((newMin+newMax)*0.5f); } + +U32 LLVOSurfacePatch::getPartitionType() const +{ + return LLPipeline::PARTITION_TERRAIN; +} + +LLTerrainPartition::LLTerrainPartition() +: LLSpatialPartition(LLDrawPoolTerrain::VERTEX_DATA_MASK) +{ + mRenderByGroup = FALSE; + mBufferUsage = GL_DYNAMIC_DRAW_ARB; + mDrawableType = LLPipeline::RENDER_TYPE_TERRAIN; + mPartitionType = LLPipeline::PARTITION_TERRAIN; +} + +LLVertexBuffer* LLTerrainPartition::createVertexBuffer(U32 type_mask, U32 usage) +{ + return new LLVertexBufferTerrain(); +} + +void LLTerrainPartition::getGeometry(LLSpatialGroup* group) +{ + LLVertexBuffer* buffer = group->mVertexBuffer; + + //get vertex buffer striders + LLStrider<LLVector3> vertices; + LLStrider<LLVector3> normals; + LLStrider<LLVector2> texcoords2; + LLStrider<LLVector2> texcoords; + LLStrider<LLColor4U> colors; + LLStrider<U32> indices; + + buffer->getVertexStrider(vertices); + buffer->getNormalStrider(normals); + buffer->getTexCoordStrider(texcoords); + buffer->getTexCoord2Strider(texcoords2); + buffer->getColorStrider(colors); + buffer->getIndexStrider(indices); + + U32 indices_index = 0; + U32 index_offset = 0; + + for (std::vector<LLFace*>::iterator i = mFaceList.begin(); i != mFaceList.end(); ++i) + { + LLFace* facep = *i; + + facep->setIndicesIndex(indices_index); + facep->setGeomIndex(index_offset); + facep->mVertexBuffer = buffer; + + LLVOSurfacePatch* patchp = (LLVOSurfacePatch*) facep->getViewerObject(); + patchp->getGeometry(vertices, normals, colors, texcoords, texcoords2, indices); + + indices_index += facep->getIndicesCount(); + index_offset += facep->getGeomCount(); + } + + mFaceList.clear(); +} + diff --git a/indra/newview/llvosurfacepatch.h b/indra/newview/llvosurfacepatch.h index f1c44aa598..fd2eff710b 100644 --- a/indra/newview/llvosurfacepatch.h +++ b/indra/newview/llvosurfacepatch.h @@ -16,9 +16,19 @@ class LLSurfacePatch; class LLDrawPool; class LLVector2; -class LLVOSurfacePatch : public LLViewerObject +class LLVOSurfacePatch : public LLStaticViewerObject { public: + enum + { + VERTEX_DATA_MASK = (1 << LLVertexBuffer::TYPE_VERTEX) | + (1 << LLVertexBuffer::TYPE_NORMAL) | + (1 << LLVertexBuffer::TYPE_TEXCOORD) | + (1 << LLVertexBuffer::TYPE_TEXCOORD2) | + (1 << LLVertexBuffer::TYPE_COLOR) + } + eVertexDataMask; + LLVOSurfacePatch(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp); virtual ~LLVOSurfacePatch(); @@ -27,8 +37,18 @@ public: // Initialize data that's only inited once per class. static void initClass(); + virtual U32 getPartitionType() const; + /*virtual*/ LLDrawable* createDrawable(LLPipeline *pipeline); /*virtual*/ BOOL updateGeometry(LLDrawable *drawable); + /*virtual*/ BOOL updateLOD(); + /*virtual*/ void updateFaceSize(S32 idx); + void getGeometry(LLStrider<LLVector3> &verticesp, + LLStrider<LLVector3> &normalsp, + LLStrider<LLColor4U> &colorsp, + LLStrider<LLVector2> &texCoords0p, + LLStrider<LLVector2> &texCoords1p, + LLStrider<U32> &indicesp); /*virtual*/ void updateTextures(LLAgent &agent); /*virtual*/ void setPixelAreaAndAngle(LLAgent &agent); // generate accurate apparent angle and area @@ -44,8 +64,8 @@ public: BOOL mDirtiedPatch; protected: - LLDrawPool *mPool; - LLDrawPool *getPool(); + LLFacePool *mPool; + LLFacePool *getPool(); S32 mBaseComp; LLSurfacePatch *mPatchp; BOOL mDirtyTexture; @@ -70,24 +90,24 @@ protected: LLStrider<LLColor4U> &colorsp, LLStrider<LLVector2> &texCoords0p, LLStrider<LLVector2> &texCoords1p, - U32* &indicesp, - S32 &index_offset); + LLStrider<U32> &indicesp, + U32 &index_offset); void updateNorthGeometry(LLFace *facep, LLStrider<LLVector3> &verticesp, LLStrider<LLVector3> &normalsp, LLStrider<LLColor4U> &colorsp, LLStrider<LLVector2> &texCoords0p, LLStrider<LLVector2> &texCoords1p, - U32* &indicesp, - S32 &index_offset); + LLStrider<U32> &indicesp, + U32 &index_offset); void updateEastGeometry(LLFace *facep, LLStrider<LLVector3> &verticesp, LLStrider<LLVector3> &normalsp, LLStrider<LLColor4U> &colorsp, LLStrider<LLVector2> &texCoords0p, LLStrider<LLVector2> &texCoords1p, - U32* &indicesp, - S32 &index_offset); + LLStrider<U32> &indicesp, + U32 &index_offset); }; #endif // LL_VOSURFACEPATCH_H diff --git a/indra/newview/llvotextbubble.cpp b/indra/newview/llvotextbubble.cpp index d9f3d83f11..1a68fa88bf 100644 --- a/indra/newview/llvotextbubble.cpp +++ b/indra/newview/llvotextbubble.cpp @@ -24,7 +24,7 @@ #include "pipeline.h" LLVOTextBubble::LLVOTextBubble(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp) -: LLViewerObject(id, pcode, regionp) +: LLAlphaObject(id, pcode, regionp) { setScale(LLVector3(1.5f, 1.5f, 0.25f)); mbCanSelect = FALSE; @@ -83,8 +83,10 @@ BOOL LLVOTextBubble::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) for (i = 0; i < getNumTEs(); i++) { setTEColor(i, color); + setTEFullbright(i, TRUE); } + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE); return TRUE; } @@ -126,15 +128,14 @@ LLDrawable *LLVOTextBubble::createDrawable(LLPipeline *pipeline) pipeline->allocDrawable(this); mDrawable->setLit(FALSE); mDrawable->setRenderType(LLPipeline::RENDER_TYPE_VOLUME); - LLDrawPool *poolp; + for (U32 i = 0; i < getNumTEs(); i++) { LLViewerImage *imagep; const LLTextureEntry *texture_entry = getTE(i); imagep = gImageList.getImage(texture_entry->getID()); - poolp = gPipeline.getPool(LLDrawPool::POOL_ALPHA); - mDrawable->addFace(poolp, imagep); + mDrawable->addFace((LLFacePool*) NULL, imagep); } return mDrawable; @@ -181,24 +182,65 @@ BOOL LLVOTextBubble::updateGeometry(LLDrawable *drawable) for (S32 i = 0; i < drawable->getNumFaces(); i++) { LLFace *face = drawable->getFace(i); - - if (i == 0) - { - face->setSize(0); - continue; - } - if (i == 2) - { - face->setSize(0); - continue; - } - - // Need to figure out how to readd logic to determine face dirty vs. entire object dirty. face->setTEOffset(i); - face->clearState(LLFace::GLOBAL); - face->genVolumeTriangles(*getVolume(), i, identity4, identity3); + face->setTexture(LLViewerImage::sSmokeImagep); + face->setState(LLFace::FULLBRIGHT); } + mVolumeChanged = FALSE; + mDrawable->movePartition(); return TRUE; } + +void LLVOTextBubble::updateFaceSize(S32 idx) +{ + LLFace* face = mDrawable->getFace(idx); + + if (idx == 0 || idx == 2) + { + face->setSize(0,0); + } + else + { + const LLVolumeFace& vol_face = getVolume()->getVolumeFace(idx); + face->setSize(vol_face.mVertices.size(), vol_face.mIndices.size()); + } +} + +void LLVOTextBubble::getGeometry(S32 idx, + LLStrider<LLVector3>& verticesp, + LLStrider<LLVector3>& normalsp, + LLStrider<LLVector2>& texcoordsp, + LLStrider<LLColor4U>& colorsp, + LLStrider<U32>& indicesp) +{ + if (idx == 0 || idx == 2) + { + return; + } + + const LLVolumeFace& face = getVolume()->getVolumeFace(idx); + + LLVector3 pos = getPositionAgent(); + LLColor4U color = LLColor4U(getTE(idx)->getColor()); + U32 offset = mDrawable->getFace(idx)->getGeomIndex(); + + for (U32 i = 0; i < face.mVertices.size(); i++) + { + *verticesp++ = face.mVertices[i].mPosition.scaledVec(getScale()) + pos; + *normalsp++ = face.mVertices[i].mNormal; + *texcoordsp++ = face.mVertices[i].mTexCoord; + *colorsp++ = color; + } + + for (U32 i = 0; i < face.mIndices.size(); i++) + { + *indicesp++ = face.mIndices[i] + offset; + } +} + +U32 LLVOTextBubble::getPartitionType() const +{ + return LLPipeline::PARTITION_PARTICLE; +} diff --git a/indra/newview/llvotextbubble.h b/indra/newview/llvotextbubble.h index 9fe6386a3b..a348a53c7c 100644 --- a/indra/newview/llvotextbubble.h +++ b/indra/newview/llvotextbubble.h @@ -12,7 +12,7 @@ #include "llviewerobject.h" #include "llframetimer.h" -class LLVOTextBubble : public LLViewerObject +class LLVOTextBubble : public LLAlphaObject { public: LLVOTextBubble(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp); @@ -25,6 +25,16 @@ public: /*virtual*/ LLDrawable* createDrawable(LLPipeline *pipeline); /*virtual*/ BOOL updateGeometry(LLDrawable *drawable); /*virtual*/ BOOL updateLOD(); + /*virtual*/ void updateFaceSize(S32 idx); + + /*virtual*/ void getGeometry(S32 idx, + LLStrider<LLVector3>& verticesp, + LLStrider<LLVector3>& normalsp, + LLStrider<LLVector2>& texcoordsp, + LLStrider<LLColor4U>& colorsp, + LLStrider<U32>& indicesp); + + virtual U32 getPartitionType() const; LLColor4 mColor; S32 mLOD; diff --git a/indra/newview/llvotree.cpp b/indra/newview/llvotree.cpp index a4b61f13bd..f67188ff05 100644 --- a/indra/newview/llvotree.cpp +++ b/indra/newview/llvotree.cpp @@ -10,6 +10,8 @@ #include "llvotree.h" +#include "lldrawpooltree.h" + #include "llviewercontrol.h" #include "lldir.h" #include "llprimitive.h" @@ -19,7 +21,6 @@ #include "object_flags.h" #include "llagent.h" -#include "llagparray.h" #include "llcylinder.h" #include "lldrawable.h" #include "llface.h" @@ -389,6 +390,10 @@ void LLVOTree::updateTextures(LLAgent &agent) F32 cos_angle = 1.f; if (mTreeImagep) { + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_AREA)) + { + setDebugText(llformat("%4.0f", fsqrtf(mPixelArea))); + } mTreeImagep->addTextureStats(mPixelArea, texel_area_ratio, cos_angle); } @@ -402,14 +407,12 @@ LLDrawable* LLVOTree::createDrawable(LLPipeline *pipeline) mDrawable->setRenderType(LLPipeline::RENDER_TYPE_TREE); - LLDrawPool *poolp = gPipeline.getPool(LLDrawPool::POOL_TREE, mTreeImagep); + LLDrawPoolTree *poolp = (LLDrawPoolTree*) gPipeline.getPool(LLDrawPool::POOL_TREE, mTreeImagep); // Just a placeholder for an actual object... - LLFace *facep = mDrawable->addFace(poolp, mTreeImagep, TRUE); + LLFace *facep = mDrawable->addFace(poolp, mTreeImagep); facep->setSize(1, 3); - gPipeline.markMaterialed(mDrawable); - updateRadius(); return mDrawable; @@ -422,6 +425,7 @@ const S32 LEAF_VERTICES = 16; BOOL LLVOTree::updateGeometry(LLDrawable *drawable) { + LLFastTimer ftm(LLFastTimer::FTM_UPDATE_TREE); U32 i, j; const S32 MAX_SLICES = 32; @@ -444,20 +448,6 @@ BOOL LLVOTree::updateGeometry(LLDrawable *drawable) face->mCenterAgent = getPositionAgent(); face->mCenterLocal = face->mCenterAgent; - LLDrawPool *poolp = face->getPool(); - - if (poolp->getVertexCount()) - { - return TRUE; - } - - if (!face->getDirty()) - { - return FALSE; - } - - poolp->setDirty(); - for (lod = 0; lod < 4; lod++) { slices = sLODSlices[lod]; @@ -472,10 +462,17 @@ BOOL LLVOTree::updateGeometry(LLDrawable *drawable) LLStrider<LLVector3> vertices; LLStrider<LLVector3> normals; LLStrider<LLVector2> tex_coords; - U32 *indicesp; + LLStrider<U32> indicesp; face->setSize(max_vertices, max_indices); + + face->mVertexBuffer = new LLVertexBuffer(LLDrawPoolTree::VERTEX_DATA_MASK, GL_STATIC_DRAW_ARB); + face->mVertexBuffer->allocateBuffer(max_vertices, max_indices, TRUE); + face->setGeomIndex(0); + face->setIndicesIndex(0); + face->getGeometry(vertices, normals, tex_coords, indicesp); + S32 vertex_count = 0; S32 index_count = 0; @@ -774,17 +771,13 @@ BOOL LLVOTree::updateGeometry(LLDrawable *drawable) return TRUE; } -void LLVOTree::drawBranchPipeline(LLDrawPool *draw_pool, S32 trunk_LOD, S32 stop_level, U16 depth, U16 trunk_depth, F32 scale, F32 twist, F32 droop, F32 branches, F32 alpha) +U32 LLVOTree::drawBranchPipeline(U32* indicesp, S32 trunk_LOD, S32 stop_level, U16 depth, U16 trunk_depth, F32 scale, F32 twist, F32 droop, F32 branches, F32 alpha) { + U32 ret = 0; // // Draws a tree by recursing, drawing branches and then a 'leaf' texture. // If stop_level = -1, simply draws the whole tree as a billboarded texture // - - if (!draw_pool->getIndexCount()) - { - return; // safety net - } static F32 constant_twist; static F32 width = 0; @@ -808,15 +801,15 @@ void LLVOTree::drawBranchPipeline(LLDrawPool *draw_pool, S32 trunk_LOD, S32 stop width = scale * length * aspect; glPushMatrix(); glScalef(width,width,scale * length); - //glDrawElements(GL_TRIANGLES, sLODIndexCount[trunk_LOD], GL_UNSIGNED_INT, draw_pool.getRawIndices() + sLODIndexOffset[trunk_LOD]); - glDrawRangeElements(GL_TRIANGLES, + glDrawElements(GL_TRIANGLES, sLODIndexCount[trunk_LOD], GL_UNSIGNED_INT, indicesp + sLODIndexOffset[trunk_LOD]); + /*glDrawRangeElements(GL_TRIANGLES, sLODVertexOffset[trunk_LOD], sLODVertexOffset[trunk_LOD] + sLODVertexCount[trunk_LOD]-1, sLODIndexCount[trunk_LOD], GL_UNSIGNED_INT, - draw_pool->getRawIndices() + sLODIndexOffset[trunk_LOD]); + indicesp + sLODIndexOffset[trunk_LOD]);*/ stop_glerror(); - draw_pool->addIndicesDrawn(sLODIndexCount[trunk_LOD]); + ret += sLODIndexCount[trunk_LOD]; glPopMatrix(); } @@ -828,7 +821,7 @@ void LLVOTree::drawBranchPipeline(LLDrawPool *draw_pool, S32 trunk_LOD, S32 stop glRotatef((constant_twist + ((i%2==0)?twist:-twist))*i, 0.f, 0.f, 1.f); glRotatef(droop, 0.f, 1.f, 0.f); glRotatef(20.f, 0.f, 0.f, 1.f); // rotate 20deg about axis of new branch to add some random variation - drawBranchPipeline(draw_pool, trunk_LOD, stop_level, depth - 1, 0, scale*mScaleStep, twist, droop, branches, alpha); + ret += drawBranchPipeline(indicesp, trunk_LOD, stop_level, depth - 1, 0, scale*mScaleStep, twist, droop, branches, alpha); glPopMatrix(); } // Recurse to continue trunk @@ -837,7 +830,7 @@ void LLVOTree::drawBranchPipeline(LLDrawPool *draw_pool, S32 trunk_LOD, S32 stop glPushMatrix(); glTranslatef(0.f, 0.f, scale * length); glRotatef(70.5f, 0.f, 0.f, 1.f); // rotate a bit around Z when ascending - drawBranchPipeline(draw_pool, trunk_LOD, stop_level, depth, trunk_depth-1, scale*mScaleStep, twist, droop, branches, alpha); + ret += drawBranchPipeline(indicesp, trunk_LOD, stop_level, depth, trunk_depth-1, scale*mScaleStep, twist, droop, branches, alpha); glPopMatrix(); } } @@ -852,15 +845,15 @@ void LLVOTree::drawBranchPipeline(LLDrawPool *draw_pool, S32 trunk_LOD, S32 stop //width = scale * (TREE_BRANCH_ASPECT + TREE_LEAF_ASPECT); glScalef(scale*mLeafScale, scale*mLeafScale, scale*mLeafScale); //glScalef(1.5f*width*mLeafScale,1,1.5f*scale*mLeafScale); -// glDrawElements(GL_TRIANGLES, LEAF_INDICES, GL_UNSIGNED_INT, draw_pool.getRawIndices()); - glDrawRangeElements(GL_TRIANGLES, + glDrawElements(GL_TRIANGLES, LEAF_INDICES, GL_UNSIGNED_INT, indicesp); + /*glDrawRangeElements(GL_TRIANGLES, 0, LEAF_VERTICES-1, LEAF_INDICES, GL_UNSIGNED_INT, - draw_pool->getRawIndices()); + indicesp);*/ stop_glerror(); - draw_pool->addIndicesDrawn(LEAF_INDICES); + ret += LEAF_INDICES; glPopMatrix(); } } @@ -878,21 +871,23 @@ void LLVOTree::drawBranchPipeline(LLDrawPool *draw_pool, S32 trunk_LOD, S32 stop { glPushMatrix(); glScalef(mBillboardScale*mBillboardRatio, mBillboardScale*mBillboardRatio, mBillboardScale); -// glDrawElements(GL_TRIANGLES, LEAF_INDICES, GL_UNSIGNED_INT, draw_pool.getRawIndices()); - glDrawRangeElements(GL_TRIANGLES, + glDrawElements(GL_TRIANGLES, LEAF_INDICES, GL_UNSIGNED_INT, indicesp); +/* glDrawRangeElements(GL_TRIANGLES, 0, LEAF_VERTICES-1, LEAF_INDICES, GL_UNSIGNED_INT, - draw_pool->getRawIndices()); + indicesp);*/ stop_glerror(); - draw_pool->addIndicesDrawn(LEAF_INDICES); + ret += LEAF_INDICES; glPopMatrix(); } glMatrixMode(GL_TEXTURE); glPopMatrix(); glMatrixMode(GL_MODELVIEW); } + + return ret; } void LLVOTree::updateRadius() @@ -904,3 +899,30 @@ void LLVOTree::updateRadius() mDrawable->setRadius(32.0f); } + +void LLVOTree::updateSpatialExtents(LLVector3& newMin, LLVector3& newMax) +{ + LLVector3 center = getRenderPosition(); + LLVector3 size = getScale(); + center.mV[2] += size.mV[2]; + + newMin.setVec(center-size); + newMax.setVec(center+size); + mDrawable->setPositionGroup((newMin + newMax) * 0.5f); +} + +U32 LLVOTree::getPartitionType() const +{ + return LLPipeline::PARTITION_TREE; +} + +LLTreePartition::LLTreePartition() +: LLSpatialPartition(0) +{ + mRenderByGroup = FALSE; + mDrawableType = LLPipeline::RENDER_TYPE_TREE; + mPartitionType = LLPipeline::PARTITION_TREE; + mSlopRatio = 0.f; + mLODPeriod = 1; +} + diff --git a/indra/newview/llvotree.h b/indra/newview/llvotree.h index f962516803..487dd706df 100644 --- a/indra/newview/llvotree.h +++ b/indra/newview/llvotree.h @@ -20,6 +20,14 @@ class LLDrawPool; class LLVOTree : public LLViewerObject { public: + enum + { + VERTEX_DATA_MASK = (1 << LLVertexBuffer::TYPE_VERTEX) | + (1 << LLVertexBuffer::TYPE_NORMAL) | + (1 << LLVertexBuffer::TYPE_TEXCOORD) + } + eVertexDataMask; + LLVOTree(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp); virtual ~LLVOTree(); @@ -40,10 +48,13 @@ public: /*virtual*/ LLDrawable* createDrawable(LLPipeline *pipeline); /*virtual*/ BOOL updateGeometry(LLDrawable *drawable); + /*virtual*/ void updateSpatialExtents(LLVector3 &min, LLVector3 &max); + + virtual U32 getPartitionType() const; void updateRadius(); - void drawBranchPipeline(LLDrawPool *draw_pool, S32 trunk_LOD, S32 stop_level, U16 depth, U16 trunk_depth, F32 scale, F32 twist, F32 droop, F32 branches, F32 alpha); + U32 drawBranchPipeline(U32* indicesp, S32 trunk_LOD, S32 stop_level, U16 depth, U16 trunk_depth, F32 scale, F32 twist, F32 droop, F32 branches, F32 alpha); void drawBranch(S32 stop_level, U16 depth, U16 trunk_depth, F32 scale, F32 twist, F32 droop, F32 branches, F32 alpha, BOOL draw_leaves); diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index c1cc5b9ecb..55445f21fe 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -23,7 +23,6 @@ #include "material_codes.h" #include "message.h" #include "object_flags.h" - #include "llagent.h" #include "lldrawable.h" #include "lldrawpoolsimple.h" @@ -45,14 +44,14 @@ #include "pipeline.h" const S32 MIN_QUIET_FRAMES_COALESCE = 30; - -//#define LLDEBUG_DISPLAY_LODS 1 +const F32 FORCE_SIMPLE_RENDER_AREA = 512.f; +const F32 FORCE_CULL_AREA = 8.f; BOOL gAnimateTextures = TRUE; +extern BOOL gHideSelectedObjects; F32 LLVOVolume::sLODFactor = 1.f; F32 LLVOVolume::sLODSlopDistanceFactor = 0.5f; //Changing this to zero, effectively disables the LOD transition slop -F32 LLVOVolume::sLODComplexityDistanceBias = 0.0f;//Changing this to zero makes all prims LOD equally regardless of complexity F32 LLVOVolume::sDistanceFactor = 1.0f; S32 LLVOVolume::sNumLODChanges = 0; @@ -65,12 +64,8 @@ LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *re mLOD = MIN_LOD; mInited = FALSE; - mAllTEsSame = FALSE; mTextureAnimp = NULL; mGlobalVolume = FALSE; - - mTextureAnimp = NULL; - mAllTEsSame = FALSE; mVObjRadius = LLVector3(1,1,0.5f).magVec(); mNumFaces = 0; } @@ -124,11 +119,17 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys, } } mTextureAnimp->unpackTAMessage(mesgsys, block_num); + gPipeline.markTextured(mDrawable); } else { - delete mTextureAnimp; - mTextureAnimp = NULL; + if (mTextureAnimp) + { + delete mTextureAnimp; + mTextureAnimp = NULL; + gPipeline.markTextured(mDrawable); + mFaceMappingChanged = TRUE; + } } // Unpack volume data @@ -239,52 +240,39 @@ BOOL LLVOVolume::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) if (mTextureAnimp && gAnimateTextures) { - F32 off_s, off_t, scale_s, scale_t, rot; + F32 off_s = 0.f, off_t = 0.f, scale_s = 1.f, scale_t = 1.f, rot = 0.f; S32 result; - if ((result = mTextureAnimp->animateTextures(off_s, off_t, scale_s, scale_t, rot))) + if (result = mTextureAnimp->animateTextures(off_s, off_t, scale_s, scale_t, rot)) { - U8 has_bump = 0; - if (mTextureAnimp->mFace <= -1) + mTexAnimMode = result | mTextureAnimp->mMode; + LLQuaternion quat; + LLVector3 scale(1,1,1); + + if (result & LLViewerTextureAnim::ROTATE) { - S32 face; - for (face = 0; face < getNumTEs(); face++) - { - if (result & LLViewerTextureAnim::TRANSLATE) - { - setTEOffset(face, off_s, off_t); - } - if (result & LLViewerTextureAnim::SCALE) - { - setTEScale(face, scale_s, scale_t); - } - if (result & LLViewerTextureAnim::ROTATE) - { - setTERotation(face, rot); - } - has_bump |= getTE(face)->getBumpmap(); - } + quat.setQuat(rot, 0, 0, -1); } - else if (mTextureAnimp->mFace < getNumTEs()) + + if (!(result & LLViewerTextureAnim::TRANSLATE)) { - if (result & LLViewerTextureAnim::TRANSLATE) - { - setTEOffset(mTextureAnimp->mFace, off_s, off_t); - } - if (result & LLViewerTextureAnim::SCALE) - { - setTEScale(mTextureAnimp->mFace, scale_s, scale_t); - } - if (result & LLViewerTextureAnim::ROTATE) - { - setTERotation(mTextureAnimp->mFace, rot); - } - has_bump |= getTE(mTextureAnimp->mFace)->getBumpmap(); + off_s = off_t = 0.f; } -// mFaceMappingChanged = TRUE; - if (mDrawable->isVisible()) + + LLVector3 trans(off_s+0.5f, off_t+0.5f, 0.f); + + mTextureMatrix.identity(); + mTextureMatrix.translate(LLVector3(-0.5f, -0.5f, 0.f)); + mTextureMatrix.rotate(quat); + + if (result & LLViewerTextureAnim::SCALE) { - gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD, TRUE); + scale.setVec(scale_s, scale_t, 1.f); + LLMatrix4 mat; + mat.initAll(scale, LLQuaternion(), LLVector3()); + mTextureMatrix *= mat; } + + mTextureMatrix.translate(trans); } } @@ -299,71 +287,40 @@ BOOL LLVOVolume::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) void LLVOVolume::updateTextures(LLAgent &agent) { - +// LLFastTimer t(LLFastTimer::FTM_TEMP6); + const F32 TEXTURE_AREA_REFRESH_TIME = 5.f; // seconds + if (mTextureUpdateTimer.getElapsedTimeF32() > TEXTURE_AREA_REFRESH_TIME) + { + if (mDrawable->isVisible()) + { + updateTextures(); + } + } } -//static -F32 LLVOVolume::getTextureVirtualSize(const LLFace* face) +void LLVOVolume::updateTextures() { - //LLVector2 tdim = face->mTexExtents[1] - face->mTexExtents[0]; - //F32 pixel_area = 1.f/llmin(llmax(tdim.mV[0] * tdim.mV[1], 1.f), 10.f); - LLVector3 cross_vec = (face->mExtents[1] - face->mExtents[0]); - - - LLVector3 lookAt = (face->getPositionAgent()-gCamera->getOrigin()); - F32 dist = lookAt.normVec(); + // Update the pixel area of all faces - F32 face_area; - - if (face->isState(LLFace::GLOBAL)) + if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_SIMPLE)) { - face_area = cross_vec.mV[0]*cross_vec.mV[1]*fabsf(lookAt.mV[2]) + - cross_vec.mV[1]*cross_vec.mV[2]*fabsf(lookAt.mV[0]) + - cross_vec.mV[0]*cross_vec.mV[2]*fabsf(lookAt.mV[1]); - } - else - { - face_area = cross_vec.mV[0]*cross_vec.mV[1] + - cross_vec.mV[1]*cross_vec.mV[2] + - cross_vec.mV[0]*cross_vec.mV[2]; - } - - if (face_area <= 0) - { - return 0.f; + return; } - - F32 view = llmax(lookAt*gCamera->getAtAxis(), 0.5f); - F32 dist_ramp = dist * view/face_area; - //ramp down distance for things closer than 16 m * lookAt - dist /= dist_ramp; - dist *= dist; - dist *= dist_ramp; - - F32 dist_ratio = face_area / llmax(dist, 0.1f); - F32 pixel_area = dist_ratio*gCamera->getScreenPixelArea(); - return view*pixel_area; -} - -void LLVOVolume::updateTextures(S32 lod) -{ - // Update the image levels of all textures... - // First we do some quick checks. - - // This doesn't take into account whether the object is in front - // or behind... - - if (LLViewerImage::sDontLoadVolumeTextures || mDrawable.isNull() || !mDrawable->isVisible()) + if (LLViewerImage::sDontLoadVolumeTextures || mDrawable.isNull()) // || !mDrawable->isVisible()) { return; } - - const S32 num_faces = mDrawable->getNumFaces(); + + mTextureUpdateTimer.reset(); + mPixelArea = 0.f; + const S32 num_faces = mDrawable->getNumFaces(); + + F32 min_vsize=999999999.f, max_vsize=0.f; for (S32 i = 0; i < num_faces; i++) { - const LLFace* face = mDrawable->getFace(i); + LLFace* face = mDrawable->getFace(i); const LLTextureEntry *te = face->getTextureEntry(); LLViewerImage *imagep = face->getTexture(); @@ -376,23 +333,77 @@ void LLVOVolume::updateTextures(S32 lod) if (isHUDAttachment()) { - vsize = (F32) (imagep->getWidth(0) * imagep->getHeight(0)); + F32 area = (F32) gCamera->getScreenPixelArea(); + vsize = area; imagep->setBoostLevel(LLViewerImage::BOOST_HUD); + face->setPixelArea(area); // treat as full screen } else { vsize = getTextureVirtualSize(face); } + mPixelArea = llmax(mPixelArea, face->getPixelArea()); + face->setVirtualSize(vsize); imagep->addTextureStats(vsize); - - - U8 bump = te->getBumpmap(); - if( te && bump) + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_AREA)) + { + if (vsize < min_vsize) min_vsize = vsize; + if (vsize > max_vsize) max_vsize = vsize; + } + else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY)) { - gBumpImageList.addTextureStats( bump, imagep->getID(), vsize, 1, 1); + F32 pri = imagep->getDecodePriority(); + if (pri < min_vsize) min_vsize = pri; + if (pri > max_vsize) max_vsize = pri; } + // U8 bump = te->getBumpmap(); + // if( te && bump) + // { + // gBumpImageList.addTextureStats( bump, imagep->getID(), vsize, 1, 1); + // } + } + + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_AREA)) + { + setDebugText(llformat("%.0f:%.0f", fsqrtf(min_vsize),fsqrtf(max_vsize))); + } + else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY)) + { + setDebugText(llformat("%.0f:%.0f", fsqrtf(min_vsize),fsqrtf(max_vsize))); + } +} + +F32 LLVOVolume::getTextureVirtualSize(LLFace* face) +{ + //get area of circle around face + LLVector3 center = face->getPositionAgent(); + LLVector3 size = //isFlexible() ? + // getScale()*3.f : + (face->mExtents[1] - face->mExtents[0]) * 0.5f; + + F32 face_area = LLPipeline::calcPixelArea(center, size, *gCamera); + + face->setPixelArea(face_area); + + if (face_area <= 0) + { + return 0.f; + } + + //get area of circle in texture space + LLVector2 tdim = face->mTexExtents[1] - face->mTexExtents[0]; + F32 texel_area = (tdim * 0.5f).magVecSquared()*3.14159f; + if (texel_area <= 0) + { + // Probably animated, use default + texel_area = 1.f; } + + //apply texel area to face area to get accurate ratio + face_area /= llclamp(texel_area, 1.f/64.f, 16.f); + + return face_area; } BOOL LLVOVolume::isActive() const @@ -436,7 +447,7 @@ void LLVOVolume::setScale(const LLVector3 &scale, BOOL damped) //since drawable transforms do not include scale, changing volume scale //requires an immediate rebuild of volume verts. - gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE); + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_POSITION, TRUE); } } @@ -444,16 +455,7 @@ LLFace* LLVOVolume::addFace(S32 f) { const LLTextureEntry* te = getTE(f); LLViewerImage* imagep = getTEImage(f); - LLDrawPool* poolp; - if (isHUDAttachment()) - { - poolp = gPipeline.getPool(LLDrawPool::POOL_HUD); - } - else - { - poolp = LLPipeline::getPoolFromTE(te, imagep); - } - return mDrawable->addFace(poolp, imagep); + return mDrawable->addFace(te, imagep); } LLDrawable *LLVOVolume::createDrawable(LLPipeline *pipeline) @@ -461,7 +463,7 @@ LLDrawable *LLVOVolume::createDrawable(LLPipeline *pipeline) pipeline->allocDrawable(this); mDrawable->setRenderType(LLPipeline::RENDER_TYPE_VOLUME); - S32 max_tes_to_set = calcAllTEsSame() ? 1 : getNumTEs(); + S32 max_tes_to_set = getNumTEs(); for (S32 i = 0; i < max_tes_to_set; i++) { LLFace* face = addFace(i); @@ -518,10 +520,6 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams &volume_params, const S32 detail } mGlobalVolume = (mVolumeImpl && mVolumeImpl->isVolumeGlobal()); - //MSMSM Recompute LOD here in case the object was just created, - // its LOD might be incorrectly set to minumum detail... - calcLOD(); - if (LLPrimitive::setVolume(volume_params, mLOD, (mVolumeImpl && mVolumeImpl->isVolumeUnique()))) { mFaceMappingChanged = TRUE; @@ -536,45 +534,12 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams &volume_params, const S32 detail return FALSE; } - -F32 LLVOVolume::computeLODProfilePathComplexityBias(){ - //compute a complexity cost from 0 to 1.0 where the 'simplest' prim has a cost of 0.0 - // and the 'heaviest' prim has a cost of 1.0 -// LLVolume* volume = getVolume(); - F32 complexity = 0.0f; -// const LLVolumeParams& params = volume->getParams(); -// U8 type = volume->getPathType(); -// U8 pcode = this->getPCode(); -// U8 proftype = volume->getProfileType(); - - //if(params.getHollow()>0.0f){// || (proftype == 1) || (proftype == 0)){ - //If it is hollow, or a cube/pyramid(subdivided), the complexity is roughly doubled - // complexity+=0.5f; - //} - - if(this->getVolume()->getProfile().mParams.getCurveType()==LL_PCODE_PROFILE_SQUARE && - this->getVolume()->getPath().mParams.getCurveType()==LL_PCODE_PATH_LINE) - { - //Object is a cube so bias it heavily since cubes are subdivided alot. -// this->setDebugText("CUBE"); - complexity += 1.0f; - } - -// if(params.getTwist() != params.getTwistBegin()){ - //if there is twist.. the complexity is bumped -// complexity+=0.25f; -// } -// if(type != LL_PCODE_PATH_LINE)//If the path is not a line it is more complex -// complexity+=0.2f; - return complexity * sLODComplexityDistanceBias; -} - S32 LLVOVolume::computeLODDetail(F32 distance, F32 radius) { S32 cur_detail; // We've got LOD in the profile, and in the twist. Use radius. F32 tan_angle = (LLVOVolume::sLODFactor*radius)/distance; - cur_detail = LLVolumeLODGroup::getDetailFromTan(tan_angle); + cur_detail = LLVolumeLODGroup::getDetailFromTan(llround(tan_angle, 0.01f)); return cur_detail; } @@ -584,62 +549,35 @@ BOOL LLVOVolume::calcLOD() { return FALSE; } + + //update textures here as well + updateTextures(); + S32 cur_detail = 0; - /*if (isHUDAttachment()) + + F32 radius = mVolumep->mLODScaleBias.scaledVec(getScale()).magVec(); + F32 distance = mDrawable->mDistanceWRTCamera; + distance *= sDistanceFactor; + + F32 rampDist = LLVOVolume::sLODFactor * 2; + + if (distance < rampDist) { - cur_detail = LLVolumeLODGroup::NUM_LODS-1; // max detail + // Boost LOD when you're REALLY close + distance *= 1.0f/rampDist; + distance *= distance; + distance *= rampDist; } - else*/ - { - F32 radius = (mVolumep->mLODScaleBias.scaledVec(getScale())).magVec(); - F32 distance = mDrawable->mDistanceWRTCamera; - distance *= sDistanceFactor; - - F32 rampDist = LLVOVolume::sLODFactor * 2; - - if (distance < rampDist) - { - // Boost LOD when you're REALLY close - distance *= 1.0f/rampDist; - distance *= distance; - distance *= rampDist; - } - else - { - //Now adjust the computed distance by some factor based on the geometric complexity of the primitive - distance += computeLODProfilePathComplexityBias(); - } - // Compensate for field of view changing on FOV zoom. - distance *= gCamera->getView(); - - cur_detail = computeLODDetail(distance, radius); - - //update textures with what the real LOD is - updateTextures(cur_detail); + + // DON'T Compensate for field of view changing on FOV zoom. + distance *= 3.14159f/3.f; - if(cur_detail != mLOD) - { - // Here we test whether the LOD is increasing or decreasing to introduce a slop factor - if(cur_detail < mLOD) - { - // Viewer is moving away from the object - // so bias our LOD by adding a fixed amount to the distance. - // This will reduce the problem of LOD twitching when the - // user makes slight movements near the LOD transition threshhold. - F32 test_distance = distance - (distance*sLODSlopDistanceFactor/(1.0f+sLODFactor)); - if(test_distance < 0.0f) test_distance = 0.0f; - S32 potential_detail = computeLODDetail( test_distance, radius ); - if(potential_detail >= mLOD ) - { //The LOD has truly not changed - cur_detail = mLOD; - } - } - } - } + cur_detail = computeLODDetail(llround(distance, 0.01f), + llround(radius, 0.01f)); if (cur_detail != mLOD) { - mAppAngle = (F32) atan2( mDrawable->getRadius(), mDrawable->mDistanceWRTCamera) * RAD_TO_DEG; + mAppAngle = llround((F32) atan2( mDrawable->getRadius(), mDrawable->mDistanceWRTCamera) * RAD_TO_DEG, 0.01f); mLOD = cur_detail; return TRUE; } @@ -657,17 +595,10 @@ BOOL LLVOVolume::updateLOD() } BOOL lod_changed = calcLOD(); - -#if LLDEBUG_DISPLAY_LODS - //MS Enable this to display LOD numbers on objects - std::ostringstream msg; - msg << cur_detail;//((cur_detail<mLOD)?"-":cur_detail==mLOD?"=":"+") << (int)cur_detail << " , " << mDrawable->mDistanceWRTCamera << " , " << ((LLVOVolume::sLODFactor*mVObjRadius)/mDrawable->mDistanceWRTCamera); - this->setDebugText(msg.str()); -#endif - + if (lod_changed) { - gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, FALSE); + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, FALSE); mLODChanged = TRUE; } @@ -684,8 +615,8 @@ BOOL LLVOVolume::setDrawableParent(LLDrawable* parentp) if (!mDrawable->isRoot()) { - // parent is dynamic, so I'll need to share its drawable, must rebuild to share drawables - gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, TRUE); + // rebuild vertices in parent relative space + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE); if (mDrawable->isActive() && !parentp->isActive()) { @@ -704,7 +635,7 @@ void LLVOVolume::updateFaceFlags() { for (S32 i = 0; i < getVolume()->getNumFaces(); i++) { - LLFace *face = mDrawable->getFace(i + mFaceIndexOffset); + LLFace *face = mDrawable->getFace(i); BOOL fullbright = getTE(i)->getFullbright(); face->clearState(LLFace::FULLBRIGHT | LLFace::HUD_RENDER | LLFace::LIGHT); @@ -720,10 +651,6 @@ void LLVOVolume::updateFaceFlags() { face->setState(LLFace::HUD_RENDER); } - if (getAllTEsSame()) - { - break; // only 1 face - } } } @@ -731,104 +658,74 @@ void LLVOVolume::updateFaceFlags() void LLVOVolume::regenFaces() { // remove existing faces - // use mDrawable->getVOVolume() in case of shared drawables - mDrawable->getVOVolume()->deleteFaces(this); - mFaceIndexOffset = mDrawable->getNumFaces(); + deleteFaces(); + // add new faces - mNumFaces = getAllTEsSame() ? 1 : getNumTEs(); + mNumFaces = getNumTEs(); for (S32 i = 0; i < mNumFaces; i++) { LLFace* facep = addFace(i); facep->setViewerObject(this); facep->setTEOffset(i); } - // Need to do this as texture entries may not correspond to faces any more! - mDrawable->updateTexture(); - gPipeline.markMaterialed(mDrawable); } -BOOL LLVOVolume::genTriangles(BOOL force_global) +BOOL LLVOVolume::genBBoxes(BOOL force_global) { BOOL res = TRUE; LLVector3 min,max; - if (getAllTEsSame()) + BOOL rebuild = mDrawable->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION); + + for (S32 i = 0; i < getVolume()->getNumFaces(); i++) { - setupSingleFace(mFaceIndexOffset); - LLFace *face = mDrawable->getFace(mFaceIndexOffset); - S32 num_faces = getVolume()->getNumFaces(); - res = face->genVolumeTriangles(*getVolume(), 0, num_faces-1, - mRelativeXform, mRelativeXformInvTrans, - mGlobalVolume | force_global); + LLFace *face = mDrawable->getFace(i); + res &= face->genVolumeBBoxes(*getVolume(), i, + mRelativeXform, mRelativeXformInvTrans, + mGlobalVolume | force_global); - if (mDrawable->isState(LLDrawable::REBUILD_VOLUME)) + if (rebuild) { - min = face->mExtents[0]; - max = face->mExtents[1]; - } - mWereAllTEsSame = TRUE; - } - else - { - for (S32 i = 0; i < getVolume()->getNumFaces(); i++) - { - LLFace *face = mDrawable->getFace(i + mFaceIndexOffset); - res &= face->genVolumeTriangles(*getVolume(), i, - mRelativeXform, mRelativeXformInvTrans, - mGlobalVolume | force_global); - - if (mDrawable->isState(LLDrawable::REBUILD_VOLUME)) + if (i == 0) { - if (i == 0) - { - min = face->mExtents[0]; - max = face->mExtents[1]; - } - else + min = face->mExtents[0]; + max = face->mExtents[1]; + } + else + { + for (U32 i = 0; i < 3; i++) { - for (U32 i = 0; i < 3; i++) + if (face->mExtents[0].mV[i] < min.mV[i]) { - if (face->mExtents[0].mV[i] < min.mV[i]) - { - min.mV[i] = face->mExtents[0].mV[i]; - } - if (face->mExtents[1].mV[i] > max.mV[i]) - { - max.mV[i] = face->mExtents[1].mV[i]; - } + min.mV[i] = face->mExtents[0].mV[i]; + } + if (face->mExtents[1].mV[i] > max.mV[i]) + { + max.mV[i] = face->mExtents[1].mV[i]; } } } } - mWereAllTEsSame = FALSE; } - - if (mDrawable->isState(LLDrawable::REBUILD_VOLUME)) + + if (rebuild) { mDrawable->setSpatialExtents(min,max); - if (!isVolumeGlobal()) - { - mDrawable->setPositionGroup((min+max)*0.5f); - } - else - { - mDrawable->setPositionGroup(getPosition()); - } - - updateRadius(); - mDrawable->updateBinRadius(); - mDrawable->movePartition(); + mDrawable->setPositionGroup((min+max)*0.5f); } - + + updateRadius(); + mDrawable->movePartition(); + return res; } -void LLVOVolume::updateRelativeXform(BOOL global_volume) +void LLVOVolume::updateRelativeXform() { if (mVolumeImpl) { - mVolumeImpl->updateRelativeXform(global_volume); + mVolumeImpl->updateRelativeXform(); return; } @@ -854,12 +751,25 @@ void LLVOVolume::updateRelativeXform(BOOL global_volume) LLVector4(y_axis, 0.f), LLVector4(z_axis, 0.f), LLVector4(delta_pos, 1.f)); - - x_axis.normVec(); - y_axis.normVec(); - z_axis.normVec(); + - mRelativeXformInvTrans.setRows(x_axis, y_axis, z_axis); + // compute inverse transpose for normals + // mRelativeXformInvTrans.setRows(x_axis, y_axis, z_axis); + // mRelativeXformInvTrans.invert(); + // mRelativeXformInvTrans.setRows(x_axis, y_axis, z_axis); + // grumble - invert is NOT a matrix invert, so we do it by hand: + + LLMatrix3 rot_inverse = LLMatrix3(~delta_rot); + + LLMatrix3 scale_inverse; + scale_inverse.setRows(LLVector3(1.0, 0.0, 0.0) / delta_scale.mV[VX], + LLVector3(0.0, 1.0, 0.0) / delta_scale.mV[VY], + LLVector3(0.0, 0.0, 1.0) / delta_scale.mV[VZ]); + + + mRelativeXformInvTrans = rot_inverse * scale_inverse; + + mRelativeXformInvTrans.transpose(); } else { @@ -886,34 +796,35 @@ void LLVOVolume::updateRelativeXform(BOOL global_volume) LLVector4(z_axis, 0.f), LLVector4(pos, 1.f)); - x_axis.normVec(); - y_axis.normVec(); - z_axis.normVec(); - - mRelativeXformInvTrans.setRows(x_axis, y_axis, z_axis); + // compute inverse transpose for normals + LLMatrix3 rot_inverse = LLMatrix3(~rot); + + LLMatrix3 scale_inverse; + scale_inverse.setRows(LLVector3(1.0, 0.0, 0.0) / scale.mV[VX], + LLVector3(0.0, 1.0, 0.0) / scale.mV[VY], + LLVector3(0.0, 0.0, 1.0) / scale.mV[VZ]); + + + mRelativeXformInvTrans = rot_inverse * scale_inverse; + + mRelativeXformInvTrans.transpose(); } } BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) { LLFastTimer t(LLFastTimer::FTM_UPDATE_PRIMITIVES); - + if (mVolumeImpl != NULL) { LLFastTimer t(LLFastTimer::FTM_GEN_FLEX); BOOL res = mVolumeImpl->doUpdateGeometry(drawable); updateFaceFlags(); - if (res) - { - drawable->clearState(LLDrawable::REBUILD_GEOMETRY); - } - return res; } BOOL compiled = FALSE; - BOOL change_shared = FALSE; - + updateRelativeXform(); if (mDrawable.isNull()) // Not sure why this is happening, but it is... @@ -921,28 +832,23 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) return TRUE; // No update to complete } - calcAllTEsSame(); - - if (mVolumeChanged || mFaceMappingChanged || change_shared) + if (mVolumeChanged || mFaceMappingChanged ) { compiled = TRUE; mInited = TRUE; + if (mVolumeChanged) { LLFastTimer ftm(LLFastTimer::FTM_GEN_VOLUME); LLVolumeParams volume_params = getVolume()->getParams(); setVolume(volume_params, 0); - } - drawable->setState(LLDrawable::REBUILD_GEOMETRY); - if (mVolumeChanged || change_shared) - { - drawable->setState(LLDrawable::REBUILD_LIGHTING); + drawable->setState(LLDrawable::REBUILD_VOLUME); } { LLFastTimer t(LLFastTimer::FTM_GEN_TRIANGLES); regenFaces(); - genTriangles(FALSE); + genBBoxes(FALSE); } } else if (mLODChanged) @@ -964,9 +870,9 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) if (new_lod != old_lod) { compiled = TRUE; - sNumLODChanges += (getAllTEsSame() ? 1 : getVolume()->getNumFaces()); + sNumLODChanges += getVolume()->getNumFaces(); - drawable->setState(LLDrawable::REBUILD_ALL); // for face->genVolumeTriangles() + drawable->setState(LLDrawable::REBUILD_VOLUME); // for face->genVolumeTriangles() { LLFastTimer t(LLFastTimer::FTM_GEN_TRIANGLES); @@ -974,7 +880,7 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) { regenFaces(); } - genTriangles(FALSE); + genBBoxes(FALSE); } } } @@ -984,7 +890,7 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) compiled = TRUE; // All it did was move or we changed the texture coordinate offset LLFastTimer t(LLFastTimer::FTM_GEN_TRIANGLES); - genTriangles(FALSE); + genBBoxes(FALSE); } // Update face flags @@ -999,11 +905,16 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) mLODChanged = FALSE; mFaceMappingChanged = FALSE; - drawable->clearState(LLDrawable::REBUILD_GEOMETRY); - return TRUE; } +void LLVOVolume::updateFaceSize(S32 idx) +{ + const LLVolumeFace& vol_face = getVolume()->getVolumeFace(idx); + LLFace* facep = mDrawable->getFace(idx); + facep->setSize(vol_face.mVertices.size(), vol_face.mIndices.size()); +} + BOOL LLVOVolume::isRootEdit() const { if (mParent && !((LLViewerObject*)mParent)->isAvatar()) @@ -1015,178 +926,121 @@ BOOL LLVOVolume::isRootEdit() const void LLVOVolume::setTEImage(const U8 te, LLViewerImage *imagep) { -// llinfos << "SetTEImage:" << llendl; BOOL changed = (mTEImages[te] != imagep); LLViewerObject::setTEImage(te, imagep); - if (mDrawable.notNull()) + if (changed) { - if (changed) - { - calcAllTEsSame(); - gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, TRUE); - mFaceMappingChanged = TRUE; - } + gPipeline.markTextured(mDrawable); + mFaceMappingChanged = TRUE; } } S32 LLVOVolume::setTETexture(const U8 te, const LLUUID &uuid) { - BOOL changed = (uuid != getTE(te)->getID() || (uuid == LLUUID::null)); - S32 res = LLViewerObject::setTETexture(te, uuid); - if (mDrawable.notNull()) + if (res) { - if (changed) - { - calcAllTEsSame(); - gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, TRUE); - mFaceMappingChanged = TRUE; - } + gPipeline.markTextured(mDrawable); + mFaceMappingChanged = TRUE; } return res; } S32 LLVOVolume::setTEColor(const U8 te, const LLColor4 &color) { - BOOL changed = (color != getTE(te)->getColor()); S32 res = LLViewerObject::setTEColor(te, color); - if (mDrawable.notNull()) + if (res) { - if (changed) - { - calcAllTEsSame(); -// mFaceMappingChanged = TRUE; - } + gPipeline.markTextured(mDrawable); + mFaceMappingChanged = TRUE; } return res; } S32 LLVOVolume::setTEBumpmap(const U8 te, const U8 bumpmap) { - BOOL changed = (bumpmap != getTE(te)->getBumpmap()); S32 res = LLViewerObject::setTEBumpmap(te, bumpmap); - if (mDrawable.notNull()) + if (res) { - if (changed) - { - calcAllTEsSame(); - mFaceMappingChanged = TRUE; - } + gPipeline.markTextured(mDrawable); + mFaceMappingChanged = TRUE; } return res; } S32 LLVOVolume::setTETexGen(const U8 te, const U8 texgen) { - BOOL changed = (texgen != getTE(te)->getTexGen()); S32 res = LLViewerObject::setTETexGen(te, texgen); - if (mDrawable.notNull()) + if (res) { - if (changed) - { - calcAllTEsSame(); - mFaceMappingChanged = TRUE; - } + gPipeline.markTextured(mDrawable); + mFaceMappingChanged = TRUE; } return res; } S32 LLVOVolume::setTEShiny(const U8 te, const U8 shiny) { - BOOL changed = (shiny != getTE(te)->getShiny()); S32 res = LLViewerObject::setTEShiny(te, shiny); - if (mDrawable.notNull()) + if (res) { - if (changed) - { - calcAllTEsSame(); - mFaceMappingChanged = TRUE; - } + gPipeline.markTextured(mDrawable); + mFaceMappingChanged = TRUE; } return res; } S32 LLVOVolume::setTEFullbright(const U8 te, const U8 fullbright) { - BOOL changed = (fullbright != getTE(te)->getFullbright()); S32 res = LLViewerObject::setTEFullbright(te, fullbright); - if (mDrawable.notNull()) + if (res) { - if (changed) - { - calcAllTEsSame(); - if (!mDrawable->isState(LLDrawable::REBUILD_VOLUME)) - { - updateFaceFlags(); - } - mFaceMappingChanged = TRUE; - } + gPipeline.markTextured(mDrawable); + mFaceMappingChanged = TRUE; } return res; } S32 LLVOVolume::setTEMediaFlags(const U8 te, const U8 media_flags) { - bool changed = (media_flags != getTE(te)->getMediaFlags()); S32 res = LLViewerObject::setTEMediaFlags(te, media_flags); - if (mDrawable.notNull()) + if (res) { - if (changed) - { - calcAllTEsSame(); - mFaceMappingChanged = TRUE; - } + gPipeline.markTextured(mDrawable); + mFaceMappingChanged = TRUE; } return res; } S32 LLVOVolume::setTEScale(const U8 te, const F32 s, const F32 t) { - F32 olds,oldt; - getTE(te)->getScale(&olds, &oldt); - bool changed = (s != olds || t != oldt); S32 res = LLViewerObject::setTEScale(te, s, t); - if (mDrawable.notNull()) + if (res) { - if (changed) - { - calcAllTEsSame(); - mFaceMappingChanged = TRUE; - } + gPipeline.markTextured(mDrawable); + mFaceMappingChanged = TRUE; } return res; } S32 LLVOVolume::setTEScaleS(const U8 te, const F32 s) { - F32 olds,oldt; - getTE(te)->getScale(&olds, &oldt); - bool changed = (s != olds); S32 res = LLViewerObject::setTEScaleS(te, s); - if (mDrawable.notNull()) + if (res) { - if (changed) - { - calcAllTEsSame(); - mFaceMappingChanged = TRUE; - } + gPipeline.markTextured(mDrawable); + mFaceMappingChanged = TRUE; } return res; } S32 LLVOVolume::setTEScaleT(const U8 te, const F32 t) { - F32 olds,oldt; - getTE(te)->getScale(&olds, &oldt); - bool changed = (t != oldt); S32 res = LLViewerObject::setTEScaleT(te, t); - if (mDrawable.notNull()) + if (res) { - if (changed) - { - calcAllTEsSame(); - mFaceMappingChanged = TRUE; - } + gPipeline.markTextured(mDrawable); + mFaceMappingChanged = TRUE; } return res; } @@ -1195,135 +1049,9 @@ void LLVOVolume::updateTEData() { if (mDrawable.notNull()) { - calcAllTEsSame(); - mFaceMappingChanged = TRUE; - gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, TRUE); - } -} - -BOOL LLVOVolume::calcAllTEsSame() -{ - BOOL is_alpha = FALSE; - BOOL was_same = mAllTEsSame; - BOOL all_same = TRUE; - S32 num_tes = getNumTEs(); - - LLViewerImage *first_texturep = getTEImage(0); - if (!first_texturep) - { - return FALSE; - } - - const LLTextureEntry *tep = getTE(0); - if (!tep) - { - llwarns << "Volume with zero textures!" << llendl; - return FALSE; - } - - if (tep->getColor().mV[3] != 1.f) - { - is_alpha = TRUE; - } - const LLColor4 first_color = tep->getColor(); - const U8 first_bump = tep->getBumpShinyFullbright(); - const U8 first_media_flags = tep->getMediaTexGen(); - - if (first_texturep->getComponents() == 4) - { - is_alpha = TRUE; - } - - F32 s_scale, t_scale; - tep->getScale(&s_scale, &t_scale); - - for (S32 f = 1; f < num_tes; f++) - { - LLViewerImage *texturep = getTEImage(f); - if (texturep != first_texturep) - { - all_same = FALSE; - break; - } - - tep = getTE(f); - - if( tep->getBumpShinyFullbright() != first_bump ) - { - all_same = FALSE; - break; - } - - if (first_bump) - { - F32 cur_s, cur_t; - tep->getScale(&cur_s, &cur_t); - if ((cur_s != s_scale) || (cur_t != t_scale)) - { - all_same = FALSE; - break; - } - } - - if ((texturep->getComponents() == 4) || (tep->getColor().mV[3] != 1.f)) - { - if (!is_alpha) - { - all_same = FALSE; - break; - } - } - else if (is_alpha) - { - all_same = FALSE; - break; - } - - if (tep->getColor() != first_color) - { - all_same = FALSE; - break; - } - - if (tep->getMediaTexGen() != first_media_flags) - { - all_same = FALSE; - break; - } - } - - mAllTEsSame = all_same; - if (was_same != all_same) - { - gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE); // rebuild NOW mFaceMappingChanged = TRUE; + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_MATERIAL, TRUE); } - return mAllTEsSame; -} - -void LLVOVolume::setupSingleFace(S32 face_offset) -{ - S32 num_indices = 0; - S32 num_vertices = 0; - - if (mDrawable.isNull()) - { - llerrs << "setupSingleFace called with NULL mDrawable" << llendl; - } - if (face_offset >= mDrawable->getNumFaces()) - { - llerrs << "setupSingleFace called with invalid face_offset" << llendl; - } - - const S32 num_faces = getVolume()->getNumFaces(); - for (S32 i = 0; i < num_faces; i++) - { - const LLVolumeFace &vf = getVolume()->getVolumeFace(i); - num_vertices += vf.mVertices.size(); - num_indices += vf.mIndices.size(); - } - LLFace *facep = mDrawable->getFace(face_offset); - facep->setSize(num_vertices, num_indices); } //---------------------------------------------------------------------------- @@ -1532,7 +1260,7 @@ F32 LLVOVolume::calcLightAtPoint(const LLVector3& pos, const LLVector3& norm, LL LLVector3 light_dir = light_pos - pos; F32 dist = light_dir.normVec(); F32 dp = norm * light_dir; - if ((gPipeline.getVertexShaderLevel(LLPipeline::SHADER_OBJECT) >= LLDrawPoolSimple::SHADER_LEVEL_LOCAL_LIGHTS)) + if ((gPipeline.getLightingDetail() > 2)) { if (dp <= 0) { @@ -1571,7 +1299,7 @@ F32 LLVOVolume::calcLightAtPoint(const LLVector3& pos, const LLVector3& norm, LL BOOL LLVOVolume::updateLighting(BOOL do_lighting) { LLMemType mt1(LLMemType::MTYPE_DRAWABLE); - +#if 0 if (mDrawable->isStatic()) { do_lighting = FALSE; @@ -1581,31 +1309,31 @@ BOOL LLVOVolume::updateLighting(BOOL do_lighting) const LLMatrix3& mat_normal = LLMatrix3(mDrawable->getWorldRotation()); LLVolume* volume = getVolume(); - if (getAllTEsSame()) + + for (S32 i = 0; i < volume->getNumFaces(); i++) { - LLFace *face = mDrawable->getFace(mFaceIndexOffset); - S32 num_faces = volume->getNumFaces(); + LLFace *face = mDrawable->getFace(i); if (face && face->getGeomCount()) { - face->genLighting(volume, mDrawable, 0, num_faces-1, mat_vert, mat_normal, do_lighting); - } - } - else - { - for (S32 i = 0; i < volume->getNumFaces(); i++) - { - LLFace *face = mDrawable->getFace(i + mFaceIndexOffset); - if (face && face->getGeomCount()) - { - face->genLighting(volume, mDrawable, i, i, mat_vert, mat_normal, do_lighting); - } + face->genLighting(volume, mDrawable, i, i, mat_vert, mat_normal, do_lighting); } } +#endif return TRUE; } //---------------------------------------------------------------------------- +U32 LLVOVolume::getVolumeInterfaceID() const +{ + if (mVolumeImpl) + { + return mVolumeImpl->getID(); + } + + return 0; +} + BOOL LLVOVolume::isFlexible() const { if (getParameterEntryInUse(LLNetworkData::PARAMS_FLEXIBLE)) @@ -1696,16 +1424,18 @@ void LLVOVolume::generateSilhouette(LLSelectNode* nodep, const LLVector3& view_p LLVector3 view_vector; view_vector = view_point; + //transform view vector into volume space + view_vector -= getRenderPosition(); + mDrawable->mDistanceWRTCamera = view_vector.magVec(); + LLQuaternion worldRot = getRenderRotation(); + view_vector = view_vector * ~worldRot; if (!isVolumeGlobal()) - { //transform view vector into volume space - view_vector -= getRenderPosition(); - LLQuaternion worldRot = getRenderRotation(); - view_vector = view_vector * ~worldRot; + { LLVector3 objScale = getScale(); LLVector3 invObjScale(1.f / objScale.mV[VX], 1.f / objScale.mV[VY], 1.f / objScale.mV[VZ]); view_vector.scaleVec(invObjScale); } - + updateRelativeXform(); volume->generateSilhouetteVertices(nodep->mSilhouetteVertices, nodep->mSilhouetteNormals, nodep->mSilhouetteSegments, view_vector, mRelativeXform, mRelativeXformInvTrans); @@ -1713,33 +1443,15 @@ void LLVOVolume::generateSilhouette(LLSelectNode* nodep, const LLVector3& view_p } } -void LLVOVolume::deleteFaces(LLVOVolume* childp) +void LLVOVolume::deleteFaces() { - S32 face_count = childp->mNumFaces; - S32 start_index = childp->mFaceIndexOffset; + S32 face_count = mNumFaces; if (mDrawable.notNull()) { - mDrawable->deleteFaces(start_index, face_count); - } - if (mFaceIndexOffset > start_index) - { - mFaceIndexOffset -= face_count; + mDrawable->deleteFaces(0, face_count); } - for (U32 i = 0; i < mChildList.size(); i++) - { - LLViewerObject* siblingp = mChildList[i]; - if (siblingp != childp) - { - if (siblingp->getPCode() == LL_PCODE_VOLUME && - ((LLVOVolume*)siblingp)->mFaceIndexOffset > start_index) - { - ((LLVOVolume*)siblingp)->mFaceIndexOffset -= face_count; - } - } - } - childp->mFaceIndexOffset = 0; - childp->mNumFaces = 0; + mNumFaces = 0; } void LLVOVolume::updateRadius() @@ -1787,7 +1499,8 @@ const LLMatrix4 LLVOVolume::getRenderMatrix() const 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) { - LLPointer<LLImageTGA> tga_image = new LLImageTGA; +#if 0 + LLImageTGA tga_image; if (mDrawable.isNull()) { @@ -1868,10 +1581,10 @@ void LLVOVolume::writeCAL3D(apr_file_t* fp, std::string& path, std::string& file llinfos << "No image data available for " << filename << llendl; continue; } - LLPointer<LLImageRaw> raw_image = new LLImageRaw; + LLImageRaw raw_image; imagep->readBackRaw(-1, raw_image); - BOOL success = tga_image->encode(raw_image); - success = tga_image->save(filename); + BOOL success = tga_image.encode(raw_image); + success = tga_image.save(filename); } material_info = new LLMaterialExportInfo(my_material, my_texture, face_color); @@ -1912,6 +1625,7 @@ void LLVOVolume::writeCAL3D(apr_file_t* fp, std::string& path, std::string& file { ((LLVOVolume*)(LLViewerObject*)mChildList[i])->writeCAL3D(fp, path, file_base, joint_num, final_pos, final_rot, material_index, texture_index, material_map); } +#endif } //static @@ -1942,10 +1656,62 @@ void LLVOVolume::parameterChanged(U16 param_type, LLNetworkData* data, BOOL in_u } } +void LLVOVolume::setSelected(BOOL sel) +{ + LLViewerObject::setSelected(sel); + if (mDrawable.notNull()) + { + mDrawable->movePartition(); + } +} + void LLVOVolume::updateSpatialExtents(LLVector3& newMin, LLVector3& newMax) { } +F32 LLVOVolume::getBinRadius() +{ + F32 radius; + + const LLVector3* ext = mDrawable->getSpatialExtents(); + + BOOL shrink_wrap = mDrawable->isAnimating(); + BOOL alpha_wrap = FALSE; + //if (!shrink_wrap) + { + for (S32 i = 0; i < mDrawable->getNumFaces(); i++) + { + if (mDrawable->getFace(i)->getPoolType() == LLDrawPool::POOL_ALPHA) + { + alpha_wrap = TRUE; + break; + } + } + } + + if (alpha_wrap) + { + LLVector3 bounds = getScale(); + radius = llmin(bounds.mV[1], bounds.mV[2]); + radius = llmin(radius, bounds.mV[0]); + radius *= 0.5f; + } + else if (shrink_wrap) + { + radius = (ext[1]-ext[0]).magVec()*0.5f; + } + else if (mDrawable->isStatic()) + { + radius = 32.f; + } + else + { + radius = 8.f; + } + + return llclamp(radius, 0.5f, 256.f); +} + const LLVector3 LLVOVolume::getPivotPositionAgent() const { if (mVolumeImpl) @@ -1961,6 +1727,8 @@ void LLVOVolume::onShift(const LLVector3 &shift_vector) { mVolumeImpl->onShift(shift_vector); } + + updateRelativeXform(); } const LLMatrix4& LLVOVolume::getWorldMatrix(LLXformMatrix* xform) const @@ -1974,14 +1742,9 @@ const LLMatrix4& LLVOVolume::getWorldMatrix(LLXformMatrix* xform) const LLVector3 LLVOVolume::agentPositionToVolume(const LLVector3& pos) const { - if (isVolumeGlobal()) - { - return pos; - } - LLVector3 ret = pos - getRenderPosition(); ret = ret * ~getRenderRotation(); - LLVector3 objScale = getScale(); + LLVector3 objScale = isVolumeGlobal() ? LLVector3(1,1,1) : getScale(); LLVector3 invObjScale(1.f / objScale.mV[VX], 1.f / objScale.mV[VY], 1.f / objScale.mV[VZ]); ret.scaleVec(invObjScale); @@ -1990,7 +1753,7 @@ LLVector3 LLVOVolume::agentPositionToVolume(const LLVector3& pos) const LLVector3 LLVOVolume::agentDirectionToVolume(const LLVector3& dir) const { - return isVolumeGlobal() ? dir : (dir * ~getRenderRotation()); + return dir * ~getRenderRotation(); } LLVector3 LLVOVolume::volumePositionToAgent(const LLVector3& dir) const @@ -2005,6 +1768,9 @@ LLVector3 LLVOVolume::volumePositionToAgent(const LLVector3& dir) const BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, LLVector3& end) const { + return FALSE; + +#if 0 // needs to be rewritten to use face extents instead of volume bounds LLVolume* volume = getVolume(); BOOL ret = FALSE; if (volume) @@ -2024,4 +1790,538 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, LLVector3& end) co } } return ret; +#endif +} + +U32 LLVOVolume::getPartitionType() const +{ + if (isHUDAttachment()) + { + return LLPipeline::PARTITION_HUD; + } + + return LLPipeline::PARTITION_VOLUME; +} + +LLVolumePartition::LLVolumePartition() +: LLSpatialPartition(LLVOVolume::VERTEX_DATA_MASK, FALSE) +{ + mLODPeriod = 16; + mDepthMask = FALSE; + mDrawableType = LLPipeline::RENDER_TYPE_VOLUME; + mPartitionType = LLPipeline::PARTITION_VOLUME; + mSlopRatio = 0.25f; + mBufferUsage = GL_DYNAMIC_DRAW_ARB; + mImageEnabled = TRUE; +} + +LLVolumeBridge::LLVolumeBridge(LLDrawable* drawablep) +: LLSpatialBridge(drawablep, LLVOVolume::VERTEX_DATA_MASK) +{ + mDepthMask = FALSE; + mLODPeriod = 16; + mDrawableType = LLPipeline::RENDER_TYPE_VOLUME; + mPartitionType = LLPipeline::PARTITION_BRIDGE; + + mBufferUsage = GL_DYNAMIC_DRAW_ARB; + + mSlopRatio = 0.25f; +} + +void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, U32 type) +{ + LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); + + if (facep->getViewerObject()->isSelected() && gHideSelectedObjects) + { + return; + } + + //add face to drawmap + std::vector<LLDrawInfo*>& draw_vec = group->mDrawMap[type]; + + S32 idx = draw_vec.size()-1; + + + BOOL fullbright = (type == LLRenderPass::PASS_FULLBRIGHT || + type == LLRenderPass::PASS_ALPHA) ? facep->isState(LLFace::FULLBRIGHT) : FALSE; + BOOL texanim = (type == LLRenderPass::PASS_SHINY) ? FALSE : facep->isState(LLFace::TEXTURE_ANIM); + U8 bump = (type == LLRenderPass::PASS_BUMP ? facep->getTextureEntry()->getBumpmap() : 0); + + const LLMatrix4* tex_mat = NULL; + if (texanim) + { + LLVOVolume* volume = (LLVOVolume*) facep->getViewerObject(); + tex_mat = volume->getTextureMatrix(); + } + + //LLViewerImage* tex = facep->mAppAngle < FORCE_SIMPLE_RENDER_ANGLE ? NULL : facep->getTexture(); + LLViewerImage* tex = facep->getTexture(); + + if (idx >= 0 && + draw_vec[idx]->mVertexBuffer == facep->mVertexBuffer && + draw_vec[idx]->mEnd == facep->getGeomIndex()-1 && + draw_vec[idx]->mTexture == tex && + //draw_vec[idx]->mEnd - draw_vec[idx]->mStart + facep->getGeomCount() <= (U32) gGLManager.mGLMaxVertexRange && + //draw_vec[idx]->mCount + facep->getIndicesCount() <= (U32) gGLManager.mGLMaxIndexRange && + draw_vec[idx]->mFullbright == fullbright && + draw_vec[idx]->mBump == bump && + draw_vec[idx]->mTextureMatrix == tex_mat) + { + draw_vec[idx]->mCount += facep->getIndicesCount(); + draw_vec[idx]->mEnd += facep->getGeomCount(); + draw_vec[idx]->mVSize = llmax(draw_vec[idx]->mVSize, facep->getVirtualSize()); + validate_draw_info(*draw_vec[idx]); + } + else + { + U32 start = facep->getGeomIndex(); + U32 end = start + facep->getGeomCount()-1; + U32 offset = facep->getIndicesStart(); + U32 count = facep->getIndicesCount(); + LLDrawInfo* draw_info = new LLDrawInfo(start,end,count,offset,tex, + facep->mVertexBuffer, fullbright, bump); + draw_info->mVSize = facep->getVirtualSize(); + draw_vec.push_back(draw_info); + draw_info->mReflectionMap = group->mReflectionMap; + draw_info->mTextureMatrix = tex_mat; + validate_draw_info(*draw_info); + } } + +void LLVolumeGeometryManager::getGeometry(LLSpatialGroup* group) +{ + +} + +void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) +{ + if (group->changeLOD()) + { + group->mLastUpdateDistance = group->mDistance; + } + + group->mLastUpdateViewAngle = group->mViewAngle; + + if (!group->isState(LLSpatialGroup::GEOM_DIRTY | + LLSpatialGroup::ALPHA_DIRTY)) + { + return; + } + + group->mBuilt = 1.f; + LLFastTimer ftm(LLFastTimer::FTM_REBUILD_VBO); + + LLFastTimer ftm2(LLFastTimer::FTM_REBUILD_VOLUME_VB); + + //find reflection map + if (group->mSpatialPartition->mImageEnabled) + { + if (group->mReflectionMap.isNull()) + { + LLSpatialGroup* parent = group->getParent(); + while (parent && group->mReflectionMap.isNull()) + { + group->mReflectionMap = parent->mReflectionMap; + parent = parent->getParent(); + } + } + } + + group->clearDrawMap(); + + mFaceList.clear(); + + std::vector<LLFace*> alpha_faces; + U32 vertex_count = 0; + U32 index_count = 0; + U32 useage = group->mSpatialPartition->mBufferUsage; + + //get all the faces into a list, putting alpha faces in their own list + for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter) + { + LLDrawable* drawablep = *drawable_iter; + + if (drawablep->isDead()) + { + continue; + } + + if (drawablep->isAnimating()) + { //fall back to stream draw for animating verts + useage = GL_STREAM_DRAW_ARB; + } + + LLVOVolume* vobj = drawablep->getVOVolume(); + + //for each face + for (S32 i = 0; i < drawablep->getNumFaces(); i++) + { + //sum up face verts and indices + drawablep->updateFaceSize(i); + LLFace* facep = drawablep->getFace(i); + if (facep->hasGeometry() && facep->mPixelArea > FORCE_CULL_AREA) + { + const LLTextureEntry* te = facep->getTextureEntry(); + LLViewerImage* tex = facep->getTexture(); + + BOOL force_simple = (facep->mPixelArea < FORCE_SIMPLE_RENDER_AREA); + U32 type = gPipeline.getPoolTypeFromTE(te, tex); + if (type != LLDrawPool::POOL_ALPHA && force_simple) + { + type = LLDrawPool::POOL_SIMPLE; + } + facep->setPoolType(type); + + if (vobj->isHUDAttachment()) + { + facep->setState(LLFace::FULLBRIGHT); + } + + if (vobj->mTextureAnimp) + { + if (vobj->mTextureAnimp->mFace <= -1) + { + S32 face; + for (face = 0; face < vobj->getNumTEs(); face++) + { + if (vobj->mTextureAnimp->mMode & LLViewerTextureAnim::ON) + { + drawablep->getFace(face)->setState(LLFace::TEXTURE_ANIM); + } + else + { + drawablep->getFace(face)->clearState(LLFace::TEXTURE_ANIM); + } + } + } + else if (vobj->mTextureAnimp->mFace < vobj->getNumTEs()) + { + drawablep->getFace(vobj->mTextureAnimp->mFace)->setState(LLFace::TEXTURE_ANIM); + } + } + + if (type == LLDrawPool::POOL_ALPHA) + { + vertex_count += facep->getGeomCount(); + index_count += facep->getIndicesCount(); + alpha_faces.push_back(facep); + } + else + { + if (drawablep->isState(LLDrawable::REBUILD_VOLUME)) + { + facep->mLastUpdateTime = gFrameTimeSeconds; + } + mFaceList.push_back(facep); + } + } + else + { //face has no renderable geometry + facep->mVertexBuffer = NULL; + facep->mLastVertexBuffer = NULL; + //don't alpha wrap drawables that have only tiny tiny alpha faces + facep->setPoolType(LLDrawPool::POOL_SIMPLE); + } + + vobj->updateTextures(); + } + } + + group->mVertexCount = vertex_count; + group->mIndexCount = index_count; + group->mBufferUsage = useage; + + LLStrider<LLVector3> vertices; + LLStrider<LLVector3> normals; + LLStrider<LLVector2> texcoords2; + LLStrider<LLVector2> texcoords; + LLStrider<LLColor4U> colors; + LLStrider<U32> indices; + + //PROCESS NON-ALPHA FACES + { + //sort faces by texture + std::sort(mFaceList.begin(), mFaceList.end(), LLFace::CompareTextureAndTime()); + + std::vector<LLFace*>::iterator face_iter = mFaceList.begin(); + + LLSpatialGroup::buffer_map_t buffer_map; + + while (face_iter != mFaceList.end()) + { + //pull off next face + LLFace* facep = *face_iter; + LLViewerImage* tex = facep->getTexture(); + + U32 index_count = facep->getIndicesCount(); + U32 geom_count = facep->getGeomCount(); + + //sum up vertices needed for this texture + std::vector<LLFace*>::iterator i = face_iter; + ++i; + while (i != mFaceList.end() && (*i)->getTexture() == tex) + { + facep = *i; + ++i; + index_count += facep->getIndicesCount(); + geom_count += facep->getGeomCount(); + } + + //create/delete/resize vertex buffer if needed + LLVertexBuffer* buffer = NULL; + LLSpatialGroup::buffer_map_t::iterator found_iter = group->mBufferMap.find(tex); + if (found_iter != group->mBufferMap.end()) + { + buffer = found_iter->second; + } + + if (!buffer) + { //create new buffer if needed + buffer = createVertexBuffer(group->mSpatialPartition->mVertexDataMask, + group->mBufferUsage); + buffer->allocateBuffer(geom_count, index_count, TRUE); + } + else + { + if (LLVertexBuffer::sEnableVBOs && buffer->getUsage() != group->mBufferUsage) + { + buffer = createVertexBuffer(group->mSpatialPartition->mVertexDataMask, + group->mBufferUsage); + buffer->allocateBuffer(geom_count, index_count, TRUE); + } + else + { + buffer->resizeBuffer(geom_count, index_count); + } + } + + BOOL clean = TRUE; + buffer_map[tex] = buffer; + + //add face geometry + + //get vertex buffer striders + buffer->getVertexStrider(vertices); + buffer->getNormalStrider(normals); + buffer->getTexCoordStrider(texcoords); + buffer->getTexCoord2Strider(texcoords2); + buffer->getColorStrider(colors); + buffer->getIndexStrider(indices); + + U32 indices_index = 0; + U32 index_offset = 0; + + while (face_iter < i) + { + facep = *face_iter; + LLDrawable* drawablep = facep->getDrawable(); + LLVOVolume* vobj = drawablep->getVOVolume(); + LLVolume* volume = vobj->getVolume(); + + U32 te_idx = facep->getTEOffset(); + facep->mIndicesIndex = indices_index; + facep->mGeomIndex = index_offset; + facep->mVertexBuffer = buffer; + { + if (facep->getGeometryVolume(*volume, te_idx, vertices, normals, texcoords, texcoords2, colors, indices, + vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), index_offset)) + { + clean = FALSE; + buffer->markDirty(facep->getGeomIndex(), facep->getGeomCount(), + facep->getIndicesStart(), facep->getIndicesCount()); + } + } + + indices_index += facep->mIndicesCount; + + BOOL force_simple = facep->mPixelArea < FORCE_SIMPLE_RENDER_AREA; + BOOL fullbright = facep->isState(LLFace::FULLBRIGHT); + const LLTextureEntry* te = facep->getTextureEntry(); + + if (tex->getPrimaryFormat() == GL_ALPHA) + { + registerFace(group, facep, LLRenderPass::PASS_INVISIBLE); + } + else if (fullbright) + { + registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT); + } + else + { + registerFace(group, facep, LLRenderPass::PASS_SIMPLE); + } + + facep->setPoolType(LLDrawPool::POOL_SIMPLE); + + if (te->getShiny()) + { + registerFace(group, facep, LLRenderPass::PASS_SHINY); + } + + if (!force_simple && te->getBumpmap()) + { + registerFace(group, facep, LLRenderPass::PASS_BUMP); + } + + ++face_iter; + } + + if (clean) + { + buffer->markClean(); + } + } + + group->mBufferMap.clear(); + for (LLSpatialGroup::buffer_map_t::iterator i = buffer_map.begin(); i != buffer_map.end(); ++i) + { + group->mBufferMap[i->first] = i->second; + } + } + + //PROCESS ALPHA FACES + if (!alpha_faces.empty()) + { + //sort alpha faces by distance + std::sort(alpha_faces.begin(), alpha_faces.end(), LLFace::CompareDistanceGreater()); + + //store alpha faces in root vertex buffer + if (group->mVertexBuffer.isNull() || (LLVertexBuffer::sEnableVBOs && group->mBufferUsage != group->mVertexBuffer->getUsage())) + { + group->mVertexBuffer = createVertexBuffer(group->mSpatialPartition->mVertexDataMask, + group->mBufferUsage); + group->mVertexBuffer->allocateBuffer(group->mVertexCount, group->mIndexCount, true); + stop_glerror(); + } + else + { + group->mVertexBuffer->resizeBuffer(group->mVertexCount, group->mIndexCount); + stop_glerror(); + } + + //get vertex buffer striders + LLVertexBuffer* buffer = group->mVertexBuffer; + + BOOL clean = TRUE; + + buffer->getVertexStrider(vertices); + buffer->getNormalStrider(normals); + buffer->getTexCoordStrider(texcoords); + buffer->getTexCoord2Strider(texcoords2); + buffer->getColorStrider(colors); + buffer->getIndexStrider(indices); + + U32 index_offset = 0; + U32 indices_index = 0; + + for (std::vector<LLFace*>::iterator i = alpha_faces.begin(); i != alpha_faces.end(); ++i) + { + LLFace* facep = *i; + LLDrawable* drawablep = facep->getDrawable(); + LLVOVolume* vobj = drawablep->getVOVolume(); + LLVolume* volume = vobj->getVolume(); + + U32 te_idx = facep->getTEOffset(); + facep->mIndicesIndex = indices_index; + facep->mGeomIndex = index_offset; + facep->mVertexBuffer = group->mVertexBuffer; + if (facep->getGeometryVolume(*volume, te_idx, vertices, normals, texcoords, texcoords2, colors, indices, + vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), index_offset)) + { + clean = FALSE; + buffer->markDirty(facep->getGeomIndex(), facep->getGeomCount(), + facep->getIndicesStart(), facep->getIndicesCount()); + } + + indices_index += facep->mIndicesCount; + + registerFace(group, facep, LLRenderPass::PASS_ALPHA); + } + + if (clean) + { + buffer->markClean(); + } + } + else + { + group->mVertexBuffer = NULL; + } + + //get all the faces into a list, putting alpha faces in their own list + for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter) + { + LLDrawable* drawablep = *drawable_iter; + drawablep->clearState(LLDrawable::REBUILD_ALL); + } + + group->mLastUpdateTime = gFrameTimeSeconds; + group->clearState(LLSpatialGroup::GEOM_DIRTY | LLSpatialGroup::MATRIX_DIRTY | + LLSpatialGroup::ALPHA_DIRTY); + + mFaceList.clear(); +} + +void LLGeometryManager::addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32 &index_count) +{ + //initialize to default usage for this partition + U32 usage = group->mSpatialPartition->mBufferUsage; + + //clear off any old faces + mFaceList.clear(); + + //for each drawable + for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter) + { + LLDrawable* drawablep = *drawable_iter; + + if (drawablep->isDead()) + { + continue; + } + + if (drawablep->isAnimating()) + { //fall back to stream draw for animating verts + usage = GL_STREAM_DRAW_ARB; + } + + //for each face + for (S32 i = 0; i < drawablep->getNumFaces(); i++) + { + //sum up face verts and indices + drawablep->updateFaceSize(i); + LLFace* facep = drawablep->getFace(i); + if (facep->hasGeometry() && facep->mPixelArea > FORCE_CULL_AREA) + { + vertex_count += facep->getGeomCount(); + index_count += facep->getIndicesCount(); + + //remember face (for sorting) + mFaceList.push_back(facep); + } + else + { + facep->mVertexBuffer = NULL; + facep->mLastVertexBuffer = NULL; + } + } + } + + group->mBufferUsage = usage; +} + +LLHUDPartition::LLHUDPartition() +{ + mPartitionType = LLPipeline::PARTITION_HUD; + mDrawableType = LLPipeline::RENDER_TYPE_HUD; + mSlopRatio = 0.f; + mLODPeriod = 16; +} + +void LLHUDPartition::shift(const LLVector3 &offset) +{ + //HUD objects don't shift with region crossing. That would be silly. +} + + diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index 26764d62c9..f36c367f52 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -10,6 +10,7 @@ #define LL_LLVOVOLUME_H #include "llviewerobject.h" +#include "llspatialpartition.h" #include "llviewerimage.h" #include "llframetimer.h" #include "llapr.h" @@ -41,7 +42,8 @@ public: virtual bool isVolumeGlobal() const = 0; // Are we in global space? virtual bool isActive() const = 0; // Is this object currently active? virtual const LLMatrix4& getWorldMatrix(LLXformMatrix* xform) const = 0; - virtual void updateRelativeXform(BOOL global_volume = FALSE) = 0; + virtual void updateRelativeXform() = 0; + virtual U32 getID() const = 0; }; // Class which embodies all Volume objects (with pcode LL_PCODE_VOLUME) @@ -50,17 +52,24 @@ class LLVOVolume : public LLViewerObject public: static void initClass(); static void preUpdateGeom(); - static F32 getTextureVirtualSize(const LLFace* face); - - BOOL mWereAllTEsSame; + enum + { + VERTEX_DATA_MASK = (1 << LLVertexBuffer::TYPE_VERTEX) | + (1 << LLVertexBuffer::TYPE_NORMAL) | + (1 << LLVertexBuffer::TYPE_TEXCOORD) | + (1 << LLVertexBuffer::TYPE_TEXCOORD2) | + (1 << LLVertexBuffer::TYPE_COLOR) + } + eVertexDataMask; + public: LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp); virtual ~LLVOVolume(); /*virtual*/ LLDrawable* createDrawable(LLPipeline *pipeline); - void deleteFaces(LLVOVolume* childp); + void deleteFaces(); /*virtual*/ BOOL idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time); @@ -71,12 +80,12 @@ public: void generateSilhouette(LLSelectNode* nodep, const LLVector3& view_point); - BOOL getAllTEsSame() const { return mAllTEsSame; } F32 getIndividualRadius() { return mRadius; } S32 getLOD() const { return mLOD; } const LLVector3 getPivotPositionAgent() const; const LLMatrix4& getRelativeXform() const { return mRelativeXform; } const LLMatrix3& getRelativeXformInvTrans() const { return mRelativeXformInvTrans; } + const LLMatrix4* getTextureMatrix() const { return &mTextureMatrix; } /*virtual*/ const LLMatrix4 getRenderMatrix() const; /*virtual*/ BOOL lineSegmentIntersect(const LLVector3& start, LLVector3& end) const; @@ -86,6 +95,7 @@ public: BOOL getVolumeChanged() const { return mVolumeChanged; } + F32 getTextureVirtualSize(LLFace* face); /*virtual*/ F32 getRadius() const { return mVObjRadius; }; const LLMatrix4& getWorldMatrix(LLXformMatrix* xform) const; @@ -101,6 +111,7 @@ public: U32 block_num, const EObjectUpdateType update_type, LLDataPacker *dp); + /*virtual*/ void setSelected(BOOL sel); /*virtual*/ BOOL setDrawableParent(LLDrawable* parentp); /*virtual*/ void setScale(const LLVector3 &scale, BOOL damped); @@ -121,17 +132,19 @@ public: void setTexture(const S32 face); /*virtual*/ BOOL setVolume(const LLVolumeParams &volume_params, const S32 detail, bool unique_volume = false); - void updateRelativeXform(BOOL global_volume = FALSE); + void updateRelativeXform(); /*virtual*/ BOOL updateGeometry(LLDrawable *drawable); + /*virtual*/ void updateFaceSize(S32 idx); /*virtual*/ BOOL updateLOD(); void updateRadius(); /*virtual*/ void updateTextures(LLAgent &agent); - void updateTextures(S32 lod); + void updateTextures(); void updateFaceFlags(); void regenFaces(); - BOOL genTriangles(BOOL force_global); + BOOL genBBoxes(BOOL force_global); virtual void updateSpatialExtents(LLVector3& min, LLVector3& max); + virtual F32 getBinRadius(); virtual void writeCAL3D(apr_file_t* fp, std::string& path, std::string& file_base, @@ -142,6 +155,9 @@ public: S32& texture_index, std::multimap<LLUUID, LLMaterialExportInfo*>& material_map); + + virtual U32 getPartitionType() const; + // For Lights void setIsLight(BOOL is_light); void setLightColor(const LLColor3& color); @@ -159,6 +175,7 @@ public: F32 getLightDistance(const LLVector3& pos) const; // returns < 0 if inside radius // Flexible Objects + U32 getVolumeInterfaceID() const; virtual BOOL isFlexible() const; BOOL isVolumeGlobal() const; BOOL canBeFlexible() const; @@ -169,27 +186,26 @@ public: BOOL updateLighting(BOOL do_lighting); protected: - F32 computeLODProfilePathComplexityBias(); S32 computeLODDetail(F32 distance, F32 radius); BOOL calcLOD(); - void setupSingleFace(S32 face_offset); // Set up the face for combined volumes. LLFace* addFace(S32 face_index); void updateTEData(); - BOOL calcAllTEsSame(); public: LLViewerTextureAnim *mTextureAnimp; + U8 mTexAnimMode; protected: friend class LLDrawable; - BOOL mAllTEsSame; // All TE's have the same pool/texture BOOL mFaceMappingChanged; BOOL mGlobalVolume; BOOL mInited; + LLFrameTimer mTextureUpdateTimer; S32 mLOD; BOOL mLODChanged; F32 mRadius; + LLMatrix4 mTextureMatrix; LLMatrix4 mRelativeXform; LLMatrix3 mRelativeXformInvTrans; BOOL mVolumeChanged; @@ -199,8 +215,6 @@ protected: // statics public: static F32 sLODSlopDistanceFactor;// Changing this to zero, effectively disables the LOD transition slop - static F32 sLODComplexityDistanceBias; // Changing this to zero makes all prims LOD at the same distance, - // regardless of complexity static F32 sLODFactor; // LOD scale factor static F32 sDistanceFactor; // LOD distance factor diff --git a/indra/newview/llvowater.cpp b/indra/newview/llvowater.cpp index 135873b5b8..abff230c4e 100644 --- a/indra/newview/llvowater.cpp +++ b/indra/newview/llvowater.cpp @@ -45,22 +45,8 @@ const F32 WAVE_STEP_INV = (1. / WAVE_STEP); const F32 g = 9.81f; // gravitational constant (m/s^2) -/////////////////////////////////// - -LLWaterSurface::LLWaterSurface() : - mInitialized(FALSE), - mWind(9, 0, 0), - mA(0.2f), - mVisc(0.001f), - mShininess(8.0f) -{} - - -LLWaterGrid *LLVOWater::sGrid = 0; - - LLVOWater::LLVOWater(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp) -: LLViewerObject(id, LL_VO_WATER, regionp) +: LLStaticViewerObject(id, LL_VO_WATER, regionp) { // Terrain must draw during selection passes so it can block objects behind it. mbCanSelect = FALSE; @@ -94,18 +80,6 @@ void LLVOWater::updateTextures(LLAgent &agent) { } -// virtual -void LLVOWater::updateDrawable(BOOL force_damped) -{ - // Force an immediate rebuild on any update - if (mDrawable.notNull()) - { - gPipeline.updateMoveNormalAsync(mDrawable); - gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE); - } - clearChanged(SHIFTED); -} - // Never gets called BOOL LLVOWater::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) { @@ -142,17 +116,13 @@ LLDrawable *LLVOWater::createDrawable(LLPipeline *pipeline) BOOL LLVOWater::updateGeometry(LLDrawable *drawable) { - return updateGeometryFlat(drawable); -} - - -BOOL LLVOWater::updateGeometryFlat(LLDrawable *drawable) -{ + LLFastTimer ftm(LLFastTimer::FTM_UPDATE_WATER); LLFace *face; if (drawable->getNumFaces() < 1) { - drawable->addFace(gPipeline.getPool(LLDrawPool::POOL_WATER), NULL); + LLDrawPoolWater *poolp = (LLDrawPoolWater*) gPipeline.getPool(LLDrawPool::POOL_WATER); + drawable->addFace(poolp, NULL); } face = drawable->getFace(0); @@ -161,15 +131,26 @@ BOOL LLVOWater::updateGeometryFlat(LLDrawable *drawable) LLStrider<LLVector3> verticesp, normalsp; LLStrider<LLVector2> texCoordsp; - U32 *indicesp; + LLStrider<U32> indicesp; S32 index_offset; S32 size = 16; - S32 num_quads = size*size; - - face->setPrimType(LLTriangles); - face->setSize(4*num_quads, 6*num_quads); + if (face->mVertexBuffer.isNull()) + { + S32 num_quads = size*size; + face->setSize(4*num_quads, 6*num_quads); + + face->mVertexBuffer = new LLVertexBuffer(LLDrawPoolWater::VERTEX_DATA_MASK, GL_DYNAMIC_DRAW_ARB); + face->mVertexBuffer->allocateBuffer(4*num_quads, 6*num_quads, TRUE); + face->setIndicesIndex(0); + face->setGeomIndex(0); + } + else + { + face->mVertexBuffer->resizeBuffer(face->getGeomCount(), face->getIndicesCount()); + } + index_offset = face->getGeometry(verticesp,normalsp,texCoordsp, indicesp); if (-1 == index_offset) { @@ -179,6 +160,7 @@ BOOL LLVOWater::updateGeometryFlat(LLDrawable *drawable) LLVector3 position_agent; position_agent = getPositionAgent(); face->mCenterAgent = position_agent; + face->mCenterLocal = position_agent; S32 x, y; F32 step_x = getScale().mV[0] / size; @@ -237,378 +219,20 @@ BOOL LLVOWater::updateGeometryFlat(LLDrawable *drawable) *indicesp++ = toffset + 2; } } - - - mDrawable->movePartition(); - LLPipeline::sCompiles++; - return TRUE; -} - - -BOOL LLVOWater::updateGeometryHeightFieldRoam(LLDrawable *drawable) -{ - LLVector3 position_agent = getPositionAgent(); - const LLVector3 region_size = getScale(); - const LLVector3 region_origin = position_agent - region_size * 0.5f; - - S32 patch_origx = llround(region_origin.mV[VX] - sGrid->mRegionOrigin.mV[VX]) / sGrid->mRegionWidth; - S32 patch_origy = llround(region_origin.mV[VY] - sGrid->mRegionOrigin.mV[VY]) / sGrid->mRegionWidth; - S32 patch_dimx = llround(region_size.mV[VX]) / sGrid->mRegionWidth; - S32 patch_dimy = llround(region_size.mV[VY]) / sGrid->mRegionWidth; - - static S32 res = (S32)sGrid->mPatchRes; - if (patch_origx < 0) - { - patch_dimx -= - patch_origx; - if (patch_dimx < 1) - { - return TRUE; - } - patch_origx = 0; - } - if (patch_origy < 0) - { - patch_dimy -= - patch_origy; - if (patch_dimy < 1) - { - return TRUE; - } - patch_origy = 0; - } - if (patch_origx >= res) - { - return TRUE; - } - if (patch_origy >= res) - { - return TRUE; - } - - patch_dimx = llmin<U32>(patch_dimx, res - patch_origx); - patch_dimy = llmin<U32>(patch_dimy, res - patch_origy); - - U32 num_of_tris = 0; - S32 px, py; - for (py = patch_origy; py < patch_origy + patch_dimy; py++) - { - for (px = patch_origx; px < patch_origx + patch_dimx; px++) - { - const U32 ind = py * sGrid->mPatchRes + px; - if (sGrid->mPatches[ind].visible() && sGrid->mTab[px][py] == 0) - { - num_of_tris += sGrid->mPatches[ind].numTris(); - sGrid->mTab[px][py] = this; - } - } - } - - if (num_of_tris == 0) - { - return TRUE; - } - - if (drawable->getNumFaces() < 1) - { - drawable->addFace((LLDrawPoolWater*) gPipeline.getPool(LLDrawPool::POOL_WATER), - gWorldp->getDefaultWaterTexture()); - } - - LLFace *face; - - face = drawable->getFace(0); - face->mCenterAgent = position_agent; - - LLStrider<LLVector3> verticesp, normalsp; - LLStrider<LLVector2> texCoordsp; - U32 *indicesp; - S32 index_offset; - - const F32 water_height = getRegion()->getWaterHeight(); - - face->setPrimType(LLTriangles); - face->setSize(3 * num_of_tris, 3 * num_of_tris); - index_offset = face->getGeometry(verticesp,normalsp,texCoordsp, indicesp); - if (-1 == index_offset) - { - return TRUE; - } - - U32 num_of_vtx = 0; - - for (py = patch_origy; py < patch_origy + patch_dimy; py++) - { - for (px = patch_origx; px < patch_origx + patch_dimx; px++) - { - for (U8 h = 0; h < 2; h++) - { - const U32 ind = py * sGrid->mPatchRes + px; - if (!sGrid->mPatches[ind].visible() || sGrid->mTab[px][py] != this) - continue; - LLWaterTri* half = (LLWaterTri*) sGrid->mPatches[ind].half(h); - for (const LLWaterTri* tri = (LLWaterTri*) half->getFirstLeaf(); - tri != NULL; - tri = (LLWaterTri*) tri->getNextLeaf()) - { - /////// check for coordinates - *(verticesp++) = sGrid->vtx(tri->Lvtx(), water_height); - *(verticesp++) = sGrid->vtx(tri->Rvtx(), water_height); - *(verticesp++) = sGrid->vtx(tri->Tvtx(), water_height); - - *(normalsp++) = sGrid->norm(tri->Lvtx()); - *(normalsp++) = sGrid->norm(tri->Rvtx()); - *(normalsp++) = sGrid->norm(tri->Tvtx()); - - *(indicesp++) = index_offset + num_of_vtx + 0; - *(indicesp++) = index_offset + num_of_vtx + 1; - *(indicesp++) = index_offset + num_of_vtx + 2; - num_of_vtx += 3; - } - } - } - } - - - LLPipeline::sCompiles++; - return TRUE; -} - - - -BOOL LLVOWater::updateGeometryHeightFieldSimple(LLDrawable *drawable) -{ - LLVector3 position_agent = getPositionAgent(); - const LLVector3 region_size = getScale(); - const LLVector3 region_origin = position_agent - region_size * 0.5f; - - S32 patch_origx = llround(region_origin.mV[VX] - sGrid->mRegionOrigin.mV[VX]) / sGrid->mRegionWidth; - S32 patch_origy = llround(region_origin.mV[VY] - sGrid->mRegionOrigin.mV[VY]) / sGrid->mRegionWidth; - S32 patch_dimx = llround(region_size.mV[VX]) / sGrid->mRegionWidth; - S32 patch_dimy = llround(region_size.mV[VY]) / sGrid->mRegionWidth; - - static S32 res = sGrid->mPatchRes; - if (patch_origx < 0) - { - patch_dimx -= - patch_origx; - if (patch_dimx < 1) - { - return TRUE; - } - patch_origx = 0; - } - if (patch_origy < 0) - { - patch_dimy -= - patch_origy; - if (patch_dimy < 1) - { - return TRUE; - } - patch_origy = 0; - } - if (patch_origx >= res) - { - return TRUE; - } - if (patch_origy >= res) - { - return TRUE; - } - - patch_dimx = llmin<U32>(patch_dimx, res - patch_origx); - patch_dimy = llmin<U32>(patch_dimy, res - patch_origy); - - - U32 num_of_regions = 0; - S32 px, py; - - for (py = patch_origy; py < patch_origy + patch_dimy; py++) - { - for (px = patch_origx; px < patch_origx + patch_dimx; px++) - { - // if (sGrid->mTab[px][py] != 0) - // bool stop = true; - if (sGrid->mPatches[py * sGrid->mPatchRes + px].visible() && sGrid->mTab[px][py] == 0) - { - num_of_regions++; - sGrid->mTab[px][py] = this; - } - } - } - - if (num_of_regions == 0) - { - return TRUE; - } - - if (drawable->getNumFaces() < 1) - { - drawable->addFace((LLDrawPoolWater*) gPipeline.getPool(LLDrawPool::POOL_WATER), - gWorldp->getDefaultWaterTexture()); - } - - LLFace *face; - - face = drawable->getFace(0); - face->mCenterAgent = position_agent; - - LLStrider<LLVector3> verticesp, normalsp; - LLStrider<LLVector2> texCoordsp; - U32 *indicesp; - S32 index_offset; - - const F32 water_height = getRegion()->getWaterHeight(); - - const U32 steps_in_region = sGrid->mStepsInRegion / sGrid->mResDecrease; - const U32 num_quads = steps_in_region * steps_in_region * num_of_regions; - - face->setPrimType(LLTriangles); - face->setSize(4*num_quads, 6*num_quads); - index_offset = face->getGeometry(verticesp,normalsp,texCoordsp, indicesp); - if (-1 == index_offset) - { - return TRUE; - } - - U32 num_of_vtx = 0; - - for (py = patch_origy; py < patch_origy + patch_dimy; py++) - { - for (px = patch_origx; px < patch_origx + patch_dimx; px++) - { - if (!sGrid->mPatches[py * sGrid->mPatchRes + px].visible() || sGrid->mTab[px][py] != this) - { - continue; - } - - U32 orig_indx = px * sGrid->mStepsInRegion; - U32 orig_indy = py * sGrid->mStepsInRegion; - - for (U32 qy = 0; qy < steps_in_region; qy++) - { - for (U32 qx = 0; qx < steps_in_region; qx++) - { - const S32 x0 = orig_indx + qx * sGrid->mResDecrease; - const S32 y0 = orig_indy + qy * sGrid->mResDecrease; - const S32 x1 = x0 + sGrid->mResDecrease; - const S32 y1 = y0 + sGrid->mResDecrease; - - sGrid->setVertex(x0, y1, water_height, *(verticesp)); - verticesp++; - sGrid->setVertex(x0, y0, water_height, *(verticesp)); - verticesp++; - sGrid->setVertex(x1, y1, water_height, *(verticesp)); - verticesp++; - sGrid->setVertex(x1, y0, water_height, *(verticesp)); - verticesp++; - /* - *(verticesp++) = sGrid->vtx(x0, y1, water_height); - *(verticesp++) = sGrid->vtx(x0, y0, water_height); - *(verticesp++) = sGrid->vtx(x1, y1, water_height); - *(verticesp++) = sGrid->vtx(x1, y0, water_height); - */ - *(normalsp++) = sGrid->norm(x0, y1); - *(normalsp++) = sGrid->norm(x0, y0); - *(normalsp++) = sGrid->norm(x1, y1); - *(normalsp++) = sGrid->norm(x1, y0); - - const S32 curr_index_offset = index_offset + num_of_vtx; - - *indicesp++ = curr_index_offset + 0; - *indicesp++ = curr_index_offset + 1; - *indicesp++ = curr_index_offset + 2; - - *indicesp++ = curr_index_offset + 1; - *indicesp++ = curr_index_offset + 3; - *indicesp++ = curr_index_offset + 2; - num_of_vtx += 4; - } - } - } - } - - + mDrawable->movePartition(); LLPipeline::sCompiles++; return TRUE; } void LLVOWater::initClass() { - sGrid = new LLWaterGrid; } void LLVOWater::cleanupClass() { - if (sGrid) - { - sGrid->cleanup(); - delete sGrid; - sGrid = 0; - } -} - - -LLWaterGrid::LLWaterGrid() : mResIncrease(1)//0.5) -{ - init(); } - -void LLWaterGrid::init() -{ - //mRegionOrigin = LLVector3(-2 * mRegionWidth, -2 * mRegionWidth, 0); - mRegionWidth = 256; - mPatchRes = 5; - mMaxGridSize = mPatchRes * mRegionWidth; - mMinStep = (U32)(WAVE_STEP * mResIncrease); - - LLWaterTri::sMinStep = mMinStep; - LLWaterTri::sQueues = &mRoam; - - setGridDim(mMaxGridSize / mMinStep); - - mVtx = new LLVector3[mGridDim1 * mGridDim1]; - mNorms = new LLVector3[mGridDim1 * mGridDim1]; - - mPatches = new LLWaterPatch[mPatchRes * mPatchRes]; - - mStepsInRegion = mRegionWidth / mMinStep; - const U32 max_div_level = 2 * (U32)(log((F32)mStepsInRegion) / log(2.0f)); - - for (U32 y = 0; y < mPatchRes; y++) - { - for (U32 x = 0; x < mPatchRes; x++) - { - LLVector3 patch_center(mRegionWidth * (x + 0.5f), mRegionWidth * (y + 0.5f), 0); - - mPatches[y * mPatchRes + x].set(x * mStepsInRegion, y * mStepsInRegion, - mStepsInRegion, mRegionWidth, patch_center, max_div_level); - if (x > 0) - { - mPatches[y * mPatchRes + x].left()->setRight(mPatches[y * mPatchRes + x - 1].right()); - mPatches[y * mPatchRes + x - 1].right()->setRight(mPatches[y * mPatchRes + x].left()); - } - if (y > 0) - { - mPatches[y * mPatchRes + x].left()->setLeft(mPatches[(y - 1) * mPatchRes + x].right()); - mPatches[(y - 1) * mPatchRes + x].right()->setLeft(mPatches[y * mPatchRes + x].left()); - } - } - } -} - -void LLWaterGrid::cleanup() -{ - delete[] mVtx; - mVtx = NULL; - - delete[] mNorms; - mNorms = NULL; - - delete[] mPatches; - mPatches = NULL; -} - - void setVecZ(LLVector3& v) { v.mV[VX] = 0; @@ -616,413 +240,31 @@ void setVecZ(LLVector3& v) v.mV[VZ] = 1; } -void LLWaterGrid::update() -{ - static LLViewerRegion* prev_region = gAgent.getRegion(); - LLViewerRegion* region = gAgent.getRegion(); - - mRegionOrigin = region->getOriginAgent(); - mRegionOrigin.mV[VX] -= 2 * mRegionWidth; - mRegionOrigin.mV[VY] -= 2 * mRegionWidth; - mRegionOrigin.mV[VZ] = 0; - - const F32 clip_far = gCamera->getFar() - 31; - const F32 clip_far2 = clip_far * clip_far; - - const LLVector3 camera_pos = gAgent.getCameraPositionAgent(); - const LLVector3 look_at = gCamera->getAtAxis(); - - - if (camera_pos.mV[VZ] > 200) - { - mResDecrease = 4; - } - else if (camera_pos.mV[VZ] > 100) - { - mResDecrease = 2; - } - else - { - mResDecrease = 1; - } - - - //U32 mResDecrease = res_decrease; - U32 res_decrease = 1; - - const F32 res_change = mResIncrease;// * res_decrease ; - - F32 height; - - // Set the grid - - //U32 fractions = 1; - U32 fractions_res = res_decrease; - if (res_change < 1) - { - //fractions = llround(1. / res_change); - fractions_res = llround(1.f / mResIncrease); - } - - - //const U32 fractions_res = fractions * res_decrease; - - LLVector3 cur_pos; - U32 x, y; - U32 ind = 0; - for (y = 0; y < mGridDim1; y += fractions_res) - { - const F32 dispy = (F32)(y * mMinStep);//step; - for (x = 0; x < mGridDim1; x += fractions_res) - { - const F32 dispx = (F32)(x * mMinStep);//step; - cur_pos = mRegionOrigin; - cur_pos.mV[VX] += dispx; - cur_pos.mV[VY] += dispy; - - const F32 x_dist = cur_pos.mV[VX] - camera_pos.mV[VX]; - const F32 y_dist = cur_pos.mV[VY] - camera_pos.mV[VY]; - - if (x_dist * look_at.mV[VX] + y_dist * look_at.mV[VY] < 0) - { - mVtx[ind] = cur_pos; - setVecZ(mNorms[ind]); - ind++; - continue; - } - - const F32 dist_to_vtx2 = x_dist * x_dist + y_dist * y_dist; - if (dist_to_vtx2 > .81 * clip_far2) - { - mVtx[ind] = cur_pos; - setVecZ(mNorms[ind]); - ind++; - continue; - } - - mWater.getIntegerHeightAndNormal(llround(WAVE_STEP_INV * dispx), - llround(WAVE_STEP_INV * dispy), height, mNorms[ind]); - - cur_pos.mV[VZ] += height; - mVtx[ind] = cur_pos; - ind++; - } - } - - if (res_change < 1) - { - U32 fractions = llround(1.f / mResIncrease); - for (y = 0; y < mGridDim1; y += fractions_res) - { - for (x = 0; x < mGridDim; x += fractions_res) - { - const U32 ind00 = index(x, y); - const U32 ind01 = ind00 + fractions_res; - for (U32 frx = 1; frx < fractions; frx += res_decrease) - { - const U32 ind = ind00 + frx; - mNorms[ind] = LERP(mNorms[ind00], mNorms[ind01], frx * res_change); - mVtx[ind] = LERP( mVtx[ind00], mVtx[ind01], frx * res_change); - } - } - } - for (x = 0; x < mGridDim1; x += res_decrease) - { - for (y = 0; y < mGridDim; y += fractions_res) - { - const U32 ind00 = index(x, y); - const U32 ind10 = ind00 + fractions_res * mGridDim1;//(y + fractions) * quad_resx1 + x; - for (U32 fry = 1; fry < fractions; fry += res_decrease) - { - const U32 ind = ind00 + fry * mGridDim1;//(y + fry) * quad_resx1 + x; - mNorms[ind] = LERP(mNorms[ind00], mNorms[ind10], fry * res_change); - mVtx[ind] = LERP( mVtx[ind00], mVtx[ind10], fry * res_change); - } - } - } - } - - if (gUseRoam) - { - updateTree(camera_pos, look_at, clip_far, prev_region != region); - } - else - { - updateVisibility(camera_pos, look_at, clip_far); - } - - prev_region = region; - - - //mTab[0][0] = 0; - for (y = 0; y < mPatchRes; y++) - { - for (x = 0; x < mPatchRes; x++) - mTab[x][y] = 0; - } - -} - -void LLWaterGrid::updateTree(const LLVector3 &camera_pos, const LLVector3 &look_at, F32 clip_far, - BOOL restart = FALSE) -{ - static S8 recalculate_frame = 0; - - if (restart) - { - recalculate_frame = 0; - } - - if (recalculate_frame == 0) - { - LLWaterTri::nextRound(); - setCamPosition(LLWaterTri::sCam, camera_pos); - LLWaterTri::sClipFar = clip_far; - - - const U32 step = (U32)(WAVE_STEP * mResIncrease * mResDecrease); - const U32 steps_in_region = mRegionWidth / step; - LLWaterTri::sMaxDivLevel = 2 * llround(log((F32)steps_in_region) / log(2.0f)); - - for (U32 y = 0; y < mPatchRes; y++) - { - for (U32 x = 0; x < mPatchRes; x++) - { - U32 patch_ind = y * mPatchRes + x; - mPatches[patch_ind].updateTree(camera_pos, look_at, mRegionOrigin); - } - } - - mRoam.process(); - - // debug - /* - for (y = 0; y < mPatchRes; y++) - { - for (U32 x = 0; x < mPatchRes; x++) - { - //mPatches[y * mPatchRes + x].checkUpToDate(); - //mPatches[y * mPatchRes + x].checkConsistensy(); - mPatches[y * mPatchRes + x].checkCount(); - } - } - */ - } - ++recalculate_frame; - recalculate_frame = recalculate_frame % 2; -} - -void LLWaterGrid::updateVisibility(const LLVector3 &camera_pos, const LLVector3 &look_at, F32 clip_far) -{ - for (U32 y = 0; y < mPatchRes; y++) - { - for (U32 x = 0; x < mPatchRes; x++) - { - mPatches[y * mPatchRes + x].updateVisibility(camera_pos, look_at, mRegionOrigin); - } - } -} - - void LLVOWater::setUseTexture(const BOOL use_texture) { mUseTexture = use_texture; } -F32 LLWaterSurface::agentDepth() const +void LLVOWater::updateSpatialExtents(LLVector3 &newMin, LLVector3& newMax) { - const LLViewerRegion* region = gAgent.getRegion(); - LLVector3 position_agent = region->getOriginAgent();// getPositionAgent(); - const LLVector3 region_origin = position_agent; - const LLVector3 camera_pos = gAgent.getCameraPositionAgent(); + LLVector3 pos = getPositionAgent(); + LLVector3 scale = getScale(); - F32 height; - LLVector3 normal; + newMin = pos - scale * 0.5f; + newMax = pos + scale * 0.5f; - getHeightAndNormal(WAVE_STEP_INV * camera_pos.mV[VX], - WAVE_STEP_INV * camera_pos.mV[VY], height, normal); - F32 agent_water_height = gAgent.getRegion()->getWaterHeight(); - return camera_pos.mV[VZ] - (agent_water_height + height); + mDrawable->setPositionGroup((newMin + newMax) * 0.5f); } -//////////////////////////////////////////////// - - -void LLWaterSurface::getHeightAndNormal(F32 i, F32 j, F32& wave_height, LLVector3& normal) const -{ - S32 i_ind = llfloor(i); - S32 j_ind = llfloor(j); - F32 i_fr = i - i_ind; - F32 j_fr = j - j_ind; - - i_ind = i_ind % N_RES; - j_ind = j_ind % N_RES; - - S32 i_ind_next = i_ind + 1; - S32 j_ind_next = j_ind + 1; - if (i_ind_next == (S32)N_RES) i_ind_next = 0; - if (j_ind_next == (S32)N_RES) j_ind_next = 0; - - const F32 i_fr1 = 1 - i_fr; - const F32 j_fr1 = 1 - j_fr; - - const F32 hi0 = i_fr1 * height(i_ind, j_ind) + i_fr * height(i_ind_next, j_ind); - const F32 hi1 = i_fr1 * height(i_ind, j_ind_next) + i_fr * height(i_ind_next, j_ind_next); - wave_height = j_fr1 * hi0 + j_fr * hi1; - - normal = i_fr1 * mNorms[i_ind][j_ind]; - normal += i_fr * mNorms[i_ind_next][j_ind]; - LLVector3 vi1 = i_fr1 * mNorms[i_ind][j_ind_next]; - vi1 += i_fr * mNorms[i_ind_next][j_ind_next]; - normal *= j_fr1; - normal += j_fr * vi1; - - //normal.normVec(); -} - -void LLWaterSurface::getIntegerHeightAndNormal(S32 i, S32 j, F32& wave_height, LLVector3& normal) const -{ - S32 i_ind = i % N_RES; - S32 j_ind = j % N_RES; - - wave_height = height(i_ind, j_ind); - normal = mNorms[i_ind][j_ind]; +U32 LLVOWater::getPartitionType() const +{ + return LLPipeline::PARTITION_WATER; } -F32 LLWaterSurface::phillips(const LLVector2& k, const LLVector2& wind_n, F32 L, F32 L_small) +LLWaterPartition::LLWaterPartition() +: LLSpatialPartition(0) { - F32 k2 = k * k; - F32 k_dot_wind = k * wind_n; - F32 spectrum = mA * (F32) exp(-1 / (L * L * k2)) / (k2 * k2) * (k_dot_wind * k_dot_wind / k2); - - if (k_dot_wind < 0) spectrum *= .25f; // scale down waves that move opposite to the wind - - F32 damp = (F32) exp(- k2 * L_small * L_small); - - return (spectrum * damp); + mRenderByGroup = FALSE; + mDrawableType = LLPipeline::RENDER_TYPE_WATER; + mPartitionType = LLPipeline::PARTITION_WATER; } - - - -void LLWaterSurface::initAmplitudes() -{ - U16 i, j; - LLVector2 k; - F32 sqrtPhillips; - - const LLVector2 wind(mWind.mV); - - LLVector2 wind_n = wind; - const F32 wind_vel = wind_n.normVec(); - - const F32 L = wind_vel * wind_vel / g; // largest wave arising from constant wind of speed wind_vel - - const F32 L_small = L / 70; // eliminate waves with very small length (L_small << L) - - - for (i = 0; i <= N_RES; i++) - { - k.mV[VX] = (- (S32)N_RES_HALF + i) * (F_TWO_PI / WIDTH); - for (j = 0; j <= N_RES; j++) - { - k.mV[VY] = (- (S32)N_RES_HALF + j) * (F_TWO_PI / WIDTH); - - const F32 k_mag = k.magVec(); - mOmega[i][j] = (F32) sqrt(g * k_mag); - - if (k_mag < F_APPROXIMATELY_ZERO) - sqrtPhillips = 0; - else - sqrtPhillips = (F32) sqrt(phillips(k, wind_n, L, L_small)); - - //const F32 r1 = rand() / (F32) RAND_MAX; - //const F32 r2 = rand() / (F32) RAND_MAX; - const F32 r1 = randGauss(0, 1); - const F32 r2 = randGauss(0, 1); - - mHtilda0[i][j].re = sqrtPhillips * r1 * OO_SQRT2; - mHtilda0[i][j].im = sqrtPhillips * r2 * OO_SQRT2; - - } - } - - mPlan.init(N_RES, N_RES); - mInitialized = 1; // initialization complete -} - -void LLWaterSurface::generateWaterHeightField(F64 t) -{ - S32 i, j; - S32 mi, mj; // -K indices - COMPLEX plus, minus; - - if (!mInitialized) initAmplitudes(); - - for (i = 0; i < (S32)N_RES_HALF; i++) - { - mi = N_RES - i; - for (j = 0; j < (S32)N_RES ; j++) - { - mj = N_RES - j; - - const F32 cos_wt = cosf(mOmega[i][j] * t); // = cos(-mOmega[i][j] * t) - const F32 sin_wt = sinf(mOmega[i][j] * t); // = -sin(-mOmega[i][j] * t) - plus.re = mHtilda0[i][j].re * cos_wt - mHtilda0[i][j].im * sin_wt; - plus.im = mHtilda0[i][j].re * sin_wt + mHtilda0[i][j].im * cos_wt; - minus.re = mHtilda0[mi][mj].re * cos_wt - mHtilda0[mi][mj].im * sin_wt; - minus.im = -mHtilda0[mi][mj].re * sin_wt - mHtilda0[mi][mj].im * cos_wt; - - // now sum the plus and minus waves to get the total wave amplitude h - mHtilda[i * N_RES + j].re = plus.re + minus.re; - mHtilda[i * N_RES + j].im = plus.im + minus.im; - if (mi < (S32)N_RES && mj < (S32)N_RES) - { - mHtilda[mi * N_RES + mj].re = plus.re + minus.re; - mHtilda[mi * N_RES + mj].im = -plus.im - minus.im; - } - } - } - - inverse_fft(mPlan, mHtilda, N_RES, N_RES); - - calcNormals(); -} - - -/* - * Computer normals by taking finite differences. - */ - -void LLWaterSurface::calcNormals() -{ - LLVector3 n; - - for (U32 i = 0; i < N_RES; i++) - { - for (U32 j = 0; j < N_RES; j++) - { - F32 px = heightWrapped(i + 1, j); - F32 mx = heightWrapped(i - 1, j); - F32 py = heightWrapped(i, j + 1); - F32 my = heightWrapped(i, j - 1); - F32 pxpy = heightWrapped(i + 1, j + 1); - F32 pxmy = heightWrapped(i + 1, j - 1); - F32 mxpy = heightWrapped(i - 1, j + 1); - F32 mxmy = heightWrapped(i - 1, j - 1); - - n.mV[VX] = -((2 * px + pxpy + pxmy) - (2 * mx + mxpy + mxmy)); - n.mV[VY] = -((2 * py + pxpy + mxpy) - (2 * my + pxmy + mxmy)); - n.mV[VZ] = 8 * WIDTH / (F32) N_RES; - n.normVec(); - - mNorms[i][j] = n; - } - } -} - -void LLVOWater::generateNewWaves(F64 time) -{ - getWaterSurface()->generateWaterHeightField(time); - sGrid->update(); -} - diff --git a/indra/newview/llvowater.h b/indra/newview/llvowater.h index 2b846dba20..74a5e81d8c 100644 --- a/indra/newview/llvowater.h +++ b/indra/newview/llvowater.h @@ -16,195 +16,25 @@ #include "llwaterpatch.h" - const U32 N_RES = 16; //32 // number of subdivisions of wave tile const U8 WAVE_STEP = 8; -/* -#define N_DET 32 // number of subdivisions of wave tile for details - -class LLWaterDetail -{ -protected: - S32 mResolution; - LLViewerImage *mTex; - U8 *mTexData; - -public: - LLWaterDetail() : mResolution(N_DET), mTex(0), mTexData(0) {init();} - void init(); - - ~LLWaterDetail() - { - delete[] mTexData; - mTexData = NULL; - } - - - //void initEmpty(); - - void setPixel(const LLVector3 &norm, const S32 i, const S32 j) - { - S32 offset = (i * mResolution + j) * 3; - mTexData[offset] = llround(norm.mV[VX] * 255); - mTexData[offset+1] = llround(norm.mV[VX] * 255); - mTexData[offset+2] = llround(norm.mV[VX] * 255); - } - void setPixel(F32 x, F32 y, F32 z, const S32 i, const S32 j) - { - S32 offset = (i * mResolution + j) * 3; - mTexData[offset] = llround(x * 255); - mTexData[offset+1] = llround(y * 255); - mTexData[offset+2] = llround(z * 255); - } - - S32 getResolution() { return mResolution; } - - void createDetailBumpmap(F32* u, F32* v); - void createTexture() const { mTex->createTexture(); } - void bindTexture() const { mTex->bindTexture(); } - LLViewerImage* getTexture() const { return mTex; } -}; -*/ - -class LLWaterSurface -{ -protected: - BOOL mInitialized; - LLVector3 mWind; - F32 mA; - F32 mVisc; // viscosity of the fluid - F32 mShininess; - - //LLWaterDetail* mDetail; - - LLFFTPlan mPlan; - F32 mOmega[N_RES+1][N_RES+1]; // wave frequency - COMPLEX mHtilda0[N_RES+1][N_RES+1]; // wave amplitudes and phases at time 0. - LLVector3 mNorms[N_RES][N_RES]; - COMPLEX mHtilda[N_RES * N_RES]; - -public: - LLWaterSurface(); - ~LLWaterSurface() {} - - //void initSpecularLookup(); - - F32 phillips(const LLVector2& k, const LLVector2& wind_n, F32 L, F32 L_small); - - void initAmplitudes(); - - F32 height(S32 i, S32 j) const { return mHtilda[i * N_RES + j].re; } - F32 heightWrapped(S32 i, S32 j) const - { - return height((i + N_RES) % N_RES, (j + N_RES) % N_RES); - } - - void generateWaterHeightField(F64 time); - void calcNormals(); - - void getHeightAndNormal(F32 i, F32 j, F32& height, LLVector3& normal) const; - void getIntegerHeightAndNormal(S32 i, S32 j, F32& height, LLVector3& normal) const; - F32 agentDepth() const; - -// const LLWaterHeightField* hField() const { return &mHeightField; } - - //void generateDetail(F64 t); - //void fluidSolver(F32* u, F32* v, F32* u0, F32* v0, F64 dt); - - const LLVector3& getWind() const { return mWind; } - void setWind(const LLVector3& w) { mWind = w; } // initialized = 0? - F32 A() const { return mA; } - void setA(F32 a) { mA = a; } - F32 getShininess() const { return mShininess; } - //LLViewerImage* getSpecularLookup() const { return mSpecularLookup; } - //LLViewerImage* getDetail() const { return mDetail->getTexture(); } -}; - -class LLVOWater; - -class LLWaterGrid -{ -public: - LLWaterGrid(); - - void init(); - void cleanup(); - - LLWaterSurface* getWaterSurface() { return &mWater; } - - void update(); - void updateTree(const LLVector3 &camera_pos, const LLVector3 &look_at, F32 clip_far, - BOOL restart); - void updateVisibility(const LLVector3 &camera_pos, const LLVector3 &look_at, F32 clip_far); - - LLVector3 mRegionOrigin; - - LLVector3* mVtx; - LLVector3* mNorms; - U32 mRegionWidth; - U32 mMaxGridSize; - U32 mPatchRes; - U32 mMinStep; - U32 mStepsInRegion; - LLWaterPatch* mPatches; - LLRoam mRoam; - F32 mResIncrease; - U32 mResDecrease; - - LLVOWater* mTab[5][5]; - - U32 gridDim() const { return mGridDim; } - U32 rowSize() const { return mGridDim1; } - void setGridDim(U32 gd) { mGridDim = gd; mGridDim1 = mGridDim + 1; } - U32 index(const LL2Coord& c) const { return c.y() * mGridDim1 + c.x(); } - U32 index(U32 x, U32 y) const { return y * mGridDim1 + x; } - - LLVector3 vtx(const LL2Coord& c, F32 raised) const - { - LLVector3 v = mVtx[index(c)]; - v.mV[VZ] += raised; - return v; - } - - LLVector3 vtx(U32 x, U32 y, F32 raised) const - { - LLVector3 v = mVtx[index(x, y)]; - v.mV[VZ] += raised; - return v; - } - - void setVertex(const U32 x, const U32 y, const F32 raised, LLVector3 &vertex) const - { - vertex = mVtx[index(x, y)]; - vertex.mV[VZ] += raised; - } - - void setCamPosition(LL2Coord& cam, const LLVector3& cam_pos) - { - cam.x() = llround((cam_pos.mV[VX] - mRegionOrigin.mV[VX]) / mMinStep); - cam.y() = llround((cam_pos.mV[VY] - mRegionOrigin.mV[VY]) / mMinStep); - } - - LLVector3 vtx(const LL2Coord& c) const { return mVtx[index(c)]; } - LLVector3 norm(const LL2Coord& c) const { return mNorms[index(c)]; } - LLVector3 vtx(U32 x, U32 y) const { return mVtx[index(x, y)]; } - LLVector3 norm(U32 x, U32 y) const { return mNorms[index(x, y)]; } - -protected: - LLWaterSurface mWater; - U32 mGridDim; - U32 mGridDim1; -}; - class LLSurface; class LLHeavenBody; class LLVOSky; class LLFace; -class LLVOWater : public LLViewerObject +class LLVOWater : public LLStaticViewerObject { public: + enum + { + VERTEX_DATA_MASK = (1 << LLVertexBuffer::TYPE_VERTEX) | + (1 << LLVertexBuffer::TYPE_NORMAL) | + (1 << LLVertexBuffer::TYPE_TEXCOORD) + } + eVertexDataMask; + LLVOWater(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp); virtual ~LLVOWater() {} @@ -217,24 +47,19 @@ public: /*virtual*/ BOOL idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time); /*virtual*/ LLDrawable* createDrawable(LLPipeline *pipeline); /*virtual*/ BOOL updateGeometry(LLDrawable *drawable); - BOOL updateGeometryFlat(LLDrawable *drawable); - BOOL updateGeometryHeightFieldSimple(LLDrawable *drawable); - BOOL updateGeometryHeightFieldRoam(LLDrawable *drawable); + /*virtual*/ void updateSpatialExtents(LLVector3& newMin, LLVector3& newMax); - /*virtual*/ void updateDrawable(BOOL force_damped); /*virtual*/ void updateTextures(LLAgent &agent); /*virtual*/ void setPixelAreaAndAngle(LLAgent &agent); // generate accurate apparent angle and area + virtual U32 getPartitionType() const; + /*virtual*/ BOOL isActive() const; // Whether this object needs to do an idleUpdate. void setUseTexture(const BOOL use_texture); - static void generateNewWaves(F64 time); - static LLWaterSurface* getWaterSurface() { return sGrid->getWaterSurface(); }//return &mWater; } - static const LLWaterGrid* getGrid() { return sGrid; } protected: BOOL mUseTexture; - static LLWaterGrid *sGrid; }; #endif // LL_VOSURFACEPATCH_H diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp index 813eb0c7ea..752d5a38c6 100644 --- a/indra/newview/llworld.cpp +++ b/indra/newview/llworld.cpp @@ -43,7 +43,6 @@ U32 gAgentPauseSerialNum = 0; // Constants // const S32 MAX_NUMBER_OF_CLOUDS = 750; -const F32 MIN_IDLE_UPDATE_TIME = 0.025f; const S32 WORLD_PATCH_SIZE = 16; extern LLColor4U MAX_WATER_COLOR; @@ -63,7 +62,6 @@ LLWorld::LLWorld(const U32 grids_per_region, const F32 meters_per_grid) mLastPacketsOut = 0; mLastPacketsLost = 0; mLandFarClip = DEFAULT_FAR_PLANE; - mIdleUpdateTime = MIN_IDLE_UPDATE_TIME; if (gNoRender) { @@ -616,31 +614,22 @@ void LLWorld::updateVisibilities() gCamera->setFar(cur_far_clip); } - -void LLWorld::updateRegions() +void LLWorld::updateRegions(F32 max_update_time) { LLViewerRegion *regionp; LLTimer update_timer; - + BOOL did_one = FALSE; + // Perform idle time updates for the regions (and associated surfaces) for (regionp = mRegionList.getFirstData(); regionp; regionp = mRegionList.getNextData()) { - update_timer.reset(); - if (!regionp->idleUpdate(update_timer, mIdleUpdateTime)) - { - // Didn't finish all the updates. Slightly increase the idle update time. - mIdleUpdateTime *= 1.05f; - } - else - { - mIdleUpdateTime *= 0.9f; - if (mIdleUpdateTime < MIN_IDLE_UPDATE_TIME) - { - mIdleUpdateTime = MIN_IDLE_UPDATE_TIME; - } - } + F32 max_time = max_update_time - update_timer.getElapsedTimeF32(); + if (did_one && max_time <= 0.f) + break; + max_time = llmin(max_time, max_update_time*.1f); + did_one |= regionp->idleUpdate(max_update_time); } } diff --git a/indra/newview/llworld.h b/indra/newview/llworld.h index 71d7a02322..0d0d1b3211 100644 --- a/indra/newview/llworld.h +++ b/indra/newview/llworld.h @@ -95,7 +95,7 @@ public: F32 getRegionMinHeight() const { return -mWidthInMeters; } F32 getRegionMaxHeight() const { return 3.f*mWidthInMeters; } - void updateRegions(); + void updateRegions(F32 max_update_time); void updateVisibilities(); void updateParticles(); void updateClouds(const F32 dt); @@ -140,7 +140,6 @@ private: const F32 mWidthInMeters; F32 mLandFarClip; // Far clip distance for land. - F32 mIdleUpdateTime; LLPatchVertexArray mLandPatch; S32 mLastPacketsIn; S32 mLastPacketsOut; diff --git a/indra/newview/llworldmapview.cpp b/indra/newview/llworldmapview.cpp index 10994d38d2..fde1411563 100644 --- a/indra/newview/llworldmapview.cpp +++ b/indra/newview/llworldmapview.cpp @@ -298,7 +298,6 @@ void LLWorldMapView::draw() { LLGLSNoTexture no_texture; - glMatrixMode(GL_MODELVIEW); // Clear the background alpha to 0 @@ -362,14 +361,12 @@ void LLWorldMapView::draw() current_image->setBoostLevel(LLViewerImage::BOOST_MAP_LAYER); current_image->setKnownDrawSize(llround(pix_width), llround(pix_height)); -#if 1 || LL_RELEASE_FOR_DOWNLOAD if (!current_image->getHasGLTexture()) { continue; // better to draw nothing than the default image } -#endif - LLTextureView::addDebugImage(current_image); +// LLTextureView::addDebugImage(current_image); // Draw using the texture. If we don't clamp we get artifact at // the edge. @@ -522,7 +519,7 @@ void LLWorldMapView::draw() overlayimage->setKnownDrawSize(draw_size, draw_size); } - LLTextureView::addDebugImage(simimage); +// LLTextureView::addDebugImage(simimage); if (sim_visible && info->mAlpha > 0.001f) { @@ -815,6 +812,39 @@ void LLWorldMapView::draw() updateVisibleBlocks(); } +//virtual +void LLWorldMapView::setVisible(BOOL visible) +{ + LLPanel::setVisible(visible); + if (!visible && gWorldMap) + { + for (S32 map = 0; map < MAP_SIM_IMAGE_TYPES; map++) + { + for (U32 layer_idx=0; layer_idx<gWorldMap->mMapLayers[map].size(); ++layer_idx) + { + if (gWorldMap->mMapLayers[map][layer_idx].LayerDefined) + { + LLWorldMapLayer *layer = &gWorldMap->mMapLayers[map][layer_idx]; + layer->LayerImage->setBoostLevel(0); + } + } + } + for (LLWorldMap::sim_info_map_t::iterator it = gWorldMap->mSimInfoMap.begin(); + it != gWorldMap->mSimInfoMap.end(); ++it) + { + LLSimInfo* info = (*it).second; + if (info->mCurrentImage.notNull()) + { + info->mCurrentImage->setBoostLevel(0); + } + if (info->mOverlayImage.notNull()) + { + info->mOverlayImage->setBoostLevel(0); + } + } + } +} + void LLWorldMapView::drawGenericItems(const LLWorldMap::item_info_list_t& items, LLPointer<LLViewerImage> image) { LLWorldMap::item_info_list_t::const_iterator e; diff --git a/indra/newview/llworldmapview.h b/indra/newview/llworldmapview.h index d0a6aeacb2..9b353efc72 100644 --- a/indra/newview/llworldmapview.h +++ b/indra/newview/llworldmapview.h @@ -47,12 +47,13 @@ public: virtual ~LLWorldMapView(); virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE ); + virtual void setVisible(BOOL visible); virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); virtual BOOL handleDoubleClick( S32 x, S32 y, MASK mask ); virtual BOOL handleHover( S32 x, S32 y, MASK mask ); - /*virtual*/ BOOL handleToolTip( S32 x, S32 y, LLString& msg, LLRect* sticky_rect_screen ); + virtual BOOL handleToolTip( S32 x, S32 y, LLString& msg, LLRect* sticky_rect_screen ); bool checkItemHit(S32 x, S32 y, LLItemInfo& item, LLUUID* id, bool track); void handleClick(S32 x, S32 y, MASK mask, S32* hit_type, LLUUID* id); diff --git a/indra/newview/macview_Prefix.h b/indra/newview/macview_Prefix.h index 60097bd422..06a2c1604b 100644 --- a/indra/newview/macview_Prefix.h +++ b/indra/newview/macview_Prefix.h @@ -111,17 +111,15 @@ #include "lldrawpoolalpha.h" #include "lldrawpoolavatar.h" #include "lldrawpooltree.h" -#include "lldrawpooltreenew.h" #include "lldrawpoolterrain.h" #include "lldrawpoolsky.h" #include "lldrawpoolwater.h" #include "lldrawpoolground.h" #include "lldrawpoolbump.h" -#include "llvotreenew.h" /////////////////// From llface.cpp #include "llgl.h" -#include "llviewerimagelist.h" +#include "llviewerimage.h" #include "llsky.h" #include "llvosky.h" #include "llcontrol.h" diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 445f8c6fbf..4108298dfd 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -13,12 +13,12 @@ // library includes #include "audioengine.h" // For MAX_BUFFERS for debugging. #include "imageids.h" -#include "llagpmempool.h" #include "llerror.h" #include "llviewercontrol.h" #include "llfasttimer.h" #include "llfontgl.h" #include "llmemory.h" +#include "llmemtype.h" #include "llnamevalue.h" #include "llprimitive.h" #include "llvolume.h" @@ -26,17 +26,17 @@ #include "timing.h" #include "v3color.h" #include "llui.h" +#include "llglheaders.h" // newview includes #include "llagent.h" -#include "llagparray.h" #include "lldrawable.h" #include "lldrawpoolalpha.h" #include "lldrawpoolavatar.h" #include "lldrawpoolground.h" #include "lldrawpoolsimple.h" +#include "lldrawpoolbump.h" #include "lldrawpooltree.h" -#include "lldrawpoolhud.h" #include "lldrawpoolwater.h" #include "llface.h" #include "llfeaturemanager.h" @@ -63,10 +63,13 @@ #include "llvosky.h" #include "llvotree.h" #include "llvovolume.h" +#include "llvosurfacepatch.h" +#include "llvowater.h" +#include "llvotree.h" +#include "llvopartgroup.h" #include "llworld.h" #include "viewer.h" -#include "llagpmempoolarb.h" -#include "llagparray.inl" +#include "llcubemap.h" #ifdef _DEBUG // Debug indices is disabled for now for debug performance - djs 4/24/02 @@ -75,6 +78,8 @@ //#define DEBUG_INDICES #endif +#define AGGRESSIVE_OCCLUSION 0 + const F32 BACKLIGHT_DAY_MAGNITUDE_AVATAR = 0.2f; const F32 BACKLIGHT_NIGHT_MAGNITUDE_AVATAR = 0.1f; const F32 BACKLIGHT_DAY_MAGNITUDE_OBJECT = 0.1f; @@ -98,10 +103,8 @@ extern S32 gBoxFrame; extern BOOL gRenderLightGlows; extern BOOL gHideSelectedObjects; - BOOL gAvatarBacklight = FALSE; -F32 gMinObjectDistance = MIN_NEAR_PLANE; S32 gTrivialAccepts = 0; BOOL gRenderForSelect = FALSE; @@ -157,6 +160,13 @@ const char* LLPipeline::sTerrainUniforms[] = U32 LLPipeline::sTerrainUniformCount = sizeof(LLPipeline::sTerrainUniforms)/sizeof(char*); +const char* LLPipeline::sShinyUniforms[] = +{ + "origin" +}; + +U32 LLPipeline::sShinyUniformCount = sizeof(LLPipeline::sShinyUniforms)/sizeof(char*); + const char* LLPipeline::sWaterUniforms[] = { "screenTex", @@ -173,8 +183,6 @@ const char* LLPipeline::sWaterUniforms[] = U32 LLPipeline::sWaterUniformCount = sizeof(LLPipeline::sWaterUniforms)/sizeof(char*); -// the SSE variable is dependent on software blending being enabled. - //---------------------------------------- void stamp(F32 x, F32 y, F32 xs, F32 ys) @@ -196,40 +204,35 @@ void stamp(F32 x, F32 y, F32 xs, F32 ys) //---------------------------------------- S32 LLPipeline::sCompiles = 0; -S32 LLPipeline::sAGPMaxPoolSize = 1 << 25; // 32MB + +BOOL LLPipeline::sShowHUDAttachments = TRUE; BOOL LLPipeline::sRenderPhysicalBeacons = FALSE; BOOL LLPipeline::sRenderScriptedBeacons = FALSE; BOOL LLPipeline::sRenderParticleBeacons = FALSE; BOOL LLPipeline::sRenderSoundBeacons = FALSE; +BOOL LLPipeline::sUseOcclusion = FALSE; +BOOL LLPipeline::sSkipUpdate = FALSE; +BOOL LLPipeline::sDynamicReflections = FALSE; LLPipeline::LLPipeline() : mVertexShadersEnabled(FALSE), mVertexShadersLoaded(0), mLastRebuildPool(NULL), mAlphaPool(NULL), + mAlphaPoolPostWater(NULL), mSkyPool(NULL), mStarsPool(NULL), - mCloudsPool(NULL), mTerrainPool(NULL), mWaterPool(NULL), mGroundPool(NULL), - mHUDPool(NULL), - mAGPMemPool(NULL), - mGlobalFence(0), - mBufferIndex(0), - mBufferCount(kMaxBufferCount), - mUseOcclusionCulling(FALSE), + mSimplePool(NULL), + mBumpPool(NULL), mLightMask(0), - mLightMovingMask(0) + mLightMovingMask(0), + mCubeBuffer(NULL), + mCubeList(0) { - for(S32 i = 0; i < kMaxBufferCount; i++) - { - mBufferMemory[i] = NULL; - } - for (S32 i = 0; i < kMaxBufferCount; i++) - { - mBufferFence[i] = 0; - } + } void LLPipeline::init() @@ -238,8 +241,25 @@ void LLPipeline::init() stop_glerror(); - mAGPBound = FALSE; - mObjectPartition = new LLSpatialPartition; + //create object partitions + //MUST MATCH declaration of eObjectPartitions + mObjectPartition.push_back(new LLVolumePartition()); //PARTITION_VOLUME + mObjectPartition.push_back(new LLBridgePartition()); //PARTITION_BRIDGE + mObjectPartition.push_back(new LLHUDPartition()); //PARTITION_HUD + mObjectPartition.push_back(new LLTerrainPartition()); //PARTITION_TERRAIN + mObjectPartition.push_back(new LLWaterPartition()); //PARTITION_WATER + mObjectPartition.push_back(new LLTreePartition()); //PARTITION_TREE + mObjectPartition.push_back(new LLParticlePartition()); //PARTITION_PARTICLE + mObjectPartition.push_back(new LLCloudPartition()); //PARTITION_CLOUD + mObjectPartition.push_back(new LLGrassPartition()); //PARTITION_GRASS + mObjectPartition.push_back(NULL); //PARTITION_NONE + + //create render pass pools + getPool(LLDrawPool::POOL_ALPHA); + getPool(LLDrawPool::POOL_ALPHA_POST_WATER); + getPool(LLDrawPool::POOL_SIMPLE); + getPool(LLDrawPool::POOL_BUMP); + mTrianglesDrawnStat.reset(); resetFrameStats(); @@ -248,43 +268,15 @@ void LLPipeline::init() mRenderFeatureMask = 0; // All features start off mRenderDebugMask = 0; // All debug starts off + mOldRenderDebugMask = mRenderDebugMask; + mBackfaceCull = TRUE; - // Disable AGP initially. - mRenderFeatureMask &= ~RENDER_FEATURE_AGP; - stop_glerror(); // Enable features - - mUseVBO = gSavedSettings.getBOOL("RenderUseVBO"); - - // Allocate the shared buffers for software skinning - for(S32 i=0; i < mBufferCount; i++) - { - mBufferMemory[i] = new LLAGPArray<U8>; - mBufferMemory[i]->reserve_block(AVATAR_VERTEX_BYTES*AVATAR_BUFFER_ELEMENTS); - } - - if (gFeatureManagerp->isFeatureAvailable("RenderAGP")) - { - setUseAGP(gSavedSettings.getBOOL("RenderUseAGP") && gGLManager.mHasAnyAGP); - } - else - { - setUseAGP(FALSE); - } - stop_glerror(); - - for(S32 i=0; i < mBufferCount; i++) - { - if (!mBufferMemory[i]->isAGP() && usingAGP()) - { - llwarns << "pipeline buffer memory is non-AGP when AGP available!" << llendl; - } - } - + setShaders(); } @@ -307,7 +299,17 @@ void LLPipeline::cleanup() { pool_set_t::iterator curiter = iter++; LLDrawPool* poolp = *curiter; - if (poolp->mReferences.empty()) + if (poolp->isFacePool()) + { + LLFacePool* face_pool = (LLFacePool*) poolp; + if (face_pool->mReferences.empty()) + { + mPools.erase(curiter); + removeFromQuickLookup( poolp ); + delete poolp; + } + } + else { mPools.erase(curiter); removeFromQuickLookup( poolp ); @@ -315,10 +317,6 @@ void LLPipeline::cleanup() } } - if (!mSimplePools.empty()) - { - llwarns << "Simple Pools not cleaned up" << llendl; - } if (!mTerrainPools.empty()) { llwarns << "Terrain Pools not cleaned up" << llendl; @@ -327,208 +325,107 @@ void LLPipeline::cleanup() { llwarns << "Tree Pools not cleaned up" << llendl; } - if (!mTreeNewPools.empty()) - { - llwarns << "TreeNew Pools not cleaned up" << llendl; - } - if (!mBumpPools.empty()) - { - llwarns << "Bump Pools not cleaned up" << llendl; - } + delete mAlphaPool; mAlphaPool = NULL; + delete mAlphaPoolPostWater; + mAlphaPoolPostWater = NULL; delete mSkyPool; mSkyPool = NULL; delete mStarsPool; mStarsPool = NULL; - delete mCloudsPool; - mCloudsPool = NULL; delete mTerrainPool; mTerrainPool = NULL; delete mWaterPool; mWaterPool = NULL; delete mGroundPool; mGroundPool = NULL; - delete mHUDPool; - mHUDPool = NULL; - - mBloomImagep = NULL; - mBloomImage2p = NULL; - mFaceSelectImagep = NULL; - mAlphaSizzleImagep = NULL; + delete mSimplePool; + mSimplePool = NULL; + delete mBumpPool; + mBumpPool = NULL; - for(S32 i=0; i < mBufferCount; i++) + if (mCubeBuffer) { - delete mBufferMemory[i]; - mBufferMemory[i] = NULL; + delete mCubeBuffer; + mCubeBuffer = NULL; } - delete mObjectPartition; - mObjectPartition = NULL; - - if (mAGPMemPool && mGlobalFence) + if (mCubeList) { - mAGPMemPool->deleteFence(mGlobalFence); - mGlobalFence = 0; + glDeleteLists(mCubeList, 1); + mCubeList = 0; } - delete mAGPMemPool; - mAGPMemPool = NULL; -} -//============================================================================ - -BOOL LLPipeline::initAGP() -{ - LLMemType mt(LLMemType::MTYPE_PIPELINE); - - mAGPMemPool = LLAGPMemPool::createPool(sAGPMaxPoolSize, mUseVBO); + mBloomImagep = NULL; + mBloomImage2p = NULL; + mFaceSelectImagep = NULL; + mAlphaSizzleImagep = NULL; - if (!mAGPMemPool) - { - llinfos << "Warning! Couldn't allocate AGP memory!" << llendl; - llinfos << "Disabling AGP!" << llendl; - mAGPMemPool = NULL; - mRenderFeatureMask &= ~RENDER_FEATURE_AGP; // Need to disable the using AGP flag - return FALSE; - } - else if (!mAGPMemPool->getSize()) + for (S32 i = 0; i < NUM_PARTITIONS-1; i++) { - llinfos << "Warning! Unable to allocate AGP memory! Disabling AGP" << llendl; - delete mAGPMemPool; - mAGPMemPool = NULL; - mRenderFeatureMask &= ~RENDER_FEATURE_AGP; // Need to disable the using AGP flag - return FALSE; - } - else - { - llinfos << "Allocated " << mAGPMemPool->getSize() << " bytes of AGP memory" << llendl; - mAGPMemPool->bind(); - - if (mAGPMemPool->getSize() < MIN_AGP_SIZE) - { - llwarns << "Not enough AGP memory!" << llendl; - delete mAGPMemPool; - mAGPMemPool = NULL; - mRenderFeatureMask &= ~RENDER_FEATURE_AGP; // Need to disable the using AGP flag - return FALSE; - } - - - if (mAGPMemPool) - { - // Create the fence that we use for global synchronization. - mGlobalFence = mAGPMemPool->createFence(); - } - return TRUE; + delete mObjectPartition[i]; } + mObjectPartition.clear(); + mGroupQ.clear(); + mVisibleList.clear(); + mVisibleGroups.clear(); + mDrawableGroups.clear(); + mActiveGroups.clear(); + mVisibleBridge.clear(); + mMovedBridge.clear(); + mOccludedBridge.clear(); + mAlphaGroups.clear(); + clearRenderMap(); } -void LLPipeline::cleanupAGP() -{ - int i; - for(i=0; i < mBufferCount; i++) - { - mBufferMemory[i]->deleteFence(mBufferFence[i]); - mBufferMemory[i]->setUseAGP(FALSE); - } - - flushAGPMemory(); - if (mAGPMemPool && mGlobalFence) - { - mAGPMemPool->deleteFence(mGlobalFence); - mGlobalFence = 0; - } - delete mAGPMemPool; - mAGPMemPool = NULL; -} +//============================================================================ -BOOL LLPipeline::usingAGP() const +void LLPipeline::destroyGL() { - return (mRenderFeatureMask & RENDER_FEATURE_AGP) ? TRUE : FALSE; -} + stop_glerror(); + unloadShaders(); + mHighlightFaces.clear(); + mGroupQ.clear(); + mVisibleList.clear(); + mVisibleGroups.clear(); + mDrawableGroups.clear(); + mActiveGroups.clear(); + mVisibleBridge.clear(); + mOccludedBridge.clear(); + mAlphaGroups.clear(); + clearRenderMap(); + resetVertexBuffers(); -void LLPipeline::setUseAGP(const BOOL use_agp) -{ - LLMemType mt(LLMemType::MTYPE_PIPELINE); - - if (use_agp == usingAGP()) + if (mCubeBuffer) { - return; + delete mCubeBuffer; + mCubeBuffer = NULL; } - else if (use_agp) - { - mRenderFeatureMask |= RENDER_FEATURE_AGP; - initAGP(); - // Forces us to allocate an AGP memory block immediately. - int i; - for(i=0; i < mBufferCount; i++) - { - mBufferMemory[i]->setUseAGP(use_agp); - mBufferMemory[i]->realloc(mBufferMemory[i]->getMax()); - mBufferFence[i] = mBufferMemory[i]->createFence(); - } - - // Must be done AFTER you initialize AGP - for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter) - { - LLDrawPool *poolp = *iter; - poolp->setUseAGP(use_agp); - } - } - else + if (mCubeList) { - unbindAGP(); - mRenderFeatureMask &= ~RENDER_FEATURE_AGP; - - // Must be done BEFORE you blow away AGP - for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter) - { - LLDrawPool *poolp = *iter; - poolp->setUseAGP(use_agp); - } - - int i; - for(i=0; i < mBufferCount; i++) - { - if (mBufferMemory[i]) - { - mBufferMemory[i]->setUseAGP(use_agp); - mBufferMemory[i]->deleteFence(mBufferFence[i]); - mBufferFence[i] = 0; - } - else - { - llerrs << "setUseAGP without buffer memory" << llendl; - } - } - - cleanupAGP(); + glDeleteLists(mCubeList, 1); + mCubeList = 0; } - -} - -//============================================================================ - -void LLPipeline::destroyGL() -{ - setUseAGP(FALSE); - stop_glerror(); - unloadShaders(); - mHighlightFaces.reset(); } void LLPipeline::restoreGL() { + resetVertexBuffers(); + if (mVertexShadersEnabled) { setShaders(); } - if (mObjectPartition) + for (U32 i = 0; i < mObjectPartition.size()-1; i++) { - mObjectPartition->restoreGL(); + if (mObjectPartition[i]) + { + mObjectPartition[i]->restoreGL(); + } } } @@ -596,7 +493,7 @@ GLhandleARB LLPipeline::loadShader(const LLString& filename, S32 cls, GLenum typ fname << gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "shaders/class"); fname << gpu_class << "/" << filename; - llinfos << "Looking in " << fname.str().c_str() << llendl; +// llinfos << "Looking in " << fname.str().c_str() << llendl; file = fopen(fname.str().c_str(), "r"); /* Flawfinder: ignore */ if (file) { @@ -771,6 +668,11 @@ BOOL LLPipeline::validateProgramObject(GLhandleARB obj) void LLPipeline::setShaders() { + sDynamicReflections = gSavedSettings.getBOOL("RenderDynamicReflections"); + + //hack to reset buffers that change behavior with shaders + resetVertexBuffers(); + if (gViewerWindow) { gViewerWindow->setCursor(UI_CURSOR_WAIT); @@ -789,6 +691,8 @@ void LLPipeline::setShaders() { S32 light_class = 2; S32 env_class = 2; + S32 obj_class = 0; + if (getLightingDetail() == 0) { light_class = 1; @@ -798,7 +702,11 @@ void LLPipeline::setShaders() mMaxVertexShaderLevel[SHADER_LIGHTING] = light_class; mVertexShaderLevel[SHADER_ENVIRONMENT] = env_class; mMaxVertexShaderLevel[SHADER_ENVIRONMENT] = env_class; + mVertexShaderLevel[SHADER_OBJECT] = obj_class; + mMaxVertexShaderLevel[SHADER_OBJECT] = obj_class; + BOOL loaded = loadShadersLighting(); + if (loaded) { mVertexShadersEnabled = TRUE; @@ -806,7 +714,7 @@ void LLPipeline::setShaders() // Load all shaders to set max levels loadShadersEnvironment(); - + loadShadersObject(); // Load max avatar shaders to set the max level mVertexShaderLevel[SHADER_AVATAR] = 3; mMaxVertexShaderLevel[SHADER_AVATAR] = 3; @@ -878,6 +786,7 @@ BOOL LLPipeline::canUseVertexShaders() void LLPipeline::unloadShaders() { mObjectSimpleProgram.unload(); + mObjectShinyProgram.unload(); mObjectBumpProgram.unload(); mObjectAlphaProgram.unload(); mWaterProgram.unload(); @@ -919,7 +828,8 @@ BOOL LLPipeline::loadShaders() light_class = 2; // Use medium lighting shader } mVertexShaderLevel[SHADER_LIGHTING] = light_class; - mVertexShaderLevel[SHADER_OBJECT] = llmin(mMaxVertexShaderLevel[SHADER_OBJECT], gSavedSettings.getS32("VertexShaderLevelObject")); + //mVertexShaderLevel[SHADER_OBJECT] = llmin(mMaxVertexShaderLevel[SHADER_OBJECT], gSavedSettings.getS32("VertexShaderLevelObject")); + mVertexShaderLevel[SHADER_OBJECT] = 0; mVertexShaderLevel[SHADER_AVATAR] = llmin(mMaxVertexShaderLevel[SHADER_AVATAR], gSavedSettings.getS32("VertexShaderLevelAvatar")); mVertexShaderLevel[SHADER_ENVIRONMENT] = llmin(mMaxVertexShaderLevel[SHADER_ENVIRONMENT], gSavedSettings.getS32("VertexShaderLevelEnvironment")); mVertexShaderLevel[SHADER_INTERFACE] = mMaxVertexShaderLevel[SHADER_INTERFACE]; @@ -1100,12 +1010,14 @@ BOOL LLPipeline::loadShadersObject() if (mVertexShaderLevel[SHADER_OBJECT] == 0) { + mObjectShinyProgram.unload(); mObjectSimpleProgram.unload(); mObjectBumpProgram.unload(); mObjectAlphaProgram.unload(); return FALSE; } - + +#if 0 if (success) { //load object (volume/tree) vertex shader @@ -1166,6 +1078,28 @@ BOOL LLPipeline::loadShadersObject() llwarns << "Failed to load " << alphavertex << llendl; } } +#endif + + if (success) + { + //load shiny vertex shader + std::string shinyvertex = "objects/shinyV.glsl"; + std::string shinyfragment = "objects/shinyF.glsl"; + mObjectShinyProgram.mProgramObject = glCreateProgramObjectARB(); + mObjectShinyProgram.attachObjects(baseObjects, baseCount); + mObjectShinyProgram.attachObject(loadShader(shinyvertex, SHADER_OBJECT, GL_VERTEX_SHADER_ARB)); + mObjectShinyProgram.attachObject(loadShader(shinyfragment, SHADER_OBJECT, GL_FRAGMENT_SHADER_ARB)); + + success = mObjectShinyProgram.mapAttributes(); + if (success) + { + success = mObjectShinyProgram.mapUniforms(LLPipeline::sShinyUniforms, LLPipeline::sShinyUniformCount); + } + if( !success ) + { + llwarns << "Failed to load " << shinyvertex << llendl; + } + } if( !success ) { @@ -1322,11 +1256,11 @@ void LLPipeline::enableShadows(const BOOL enable_shadows) S32 LLPipeline::getMaxLightingDetail() const { - if (mVertexShaderLevel[SHADER_OBJECT] >= LLDrawPoolSimple::SHADER_LEVEL_LOCAL_LIGHTS) + /*if (mVertexShaderLevel[SHADER_OBJECT] >= LLDrawPoolSimple::SHADER_LEVEL_LOCAL_LIGHTS) { return 3; } - else + else*/ { return 1; } @@ -1356,79 +1290,63 @@ S32 LLPipeline::setLightingDetail(S32 level) return mLightingDetail; } -LLAGPMemBlock *LLPipeline::allocAGPFromPool(const S32 bytes, const U32 target) +class LLOctreeDirtyTexture : public LLOctreeTraveler<LLDrawable> { - LLMemType mt(LLMemType::MTYPE_PIPELINE); - - if (!mAGPMemPool) - { - llwarns << "Attempting to allocate AGP memory when AGP disabled!" << llendl; - return NULL; - } - else +public: + const std::set<LLViewerImage*>& mTextures; + + LLOctreeDirtyTexture(const std::set<LLViewerImage*>& textures) : mTextures(textures) { } + + virtual void visit(const LLOctreeState<LLDrawable>* state) { - if (mUseVBO) + LLSpatialGroup* group = (LLSpatialGroup*) state->getNode()->getListener(0); + + if (!group->isState(LLSpatialGroup::GEOM_DIRTY) && !group->getData().empty()) { - return ((LLAGPMemPoolARB*) mAGPMemPool)->allocBlock(bytes, target); + for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i) + { + for (std::vector<LLDrawInfo*>::iterator j = i->second.begin(); j != i->second.end(); ++j) + { + LLDrawInfo* params = *j; + if (mTextures.find(params->mTexture) != mTextures.end()) + { + group->setState(LLSpatialGroup::GEOM_DIRTY); + gPipeline.markRebuild(group); + } + } + } } - else + + for (LLSpatialGroup::bridge_list_t::iterator i = group->mBridgeList.begin(); i != group->mBridgeList.end(); ++i) { - return mAGPMemPool->allocBlock(bytes); + LLSpatialBridge* bridge = *i; + traverse(bridge->mOctree); } } -} - - -void LLPipeline::unbindAGP() -{ - if (mAGPMemPool && mAGPBound) - { - mAGPMemPool->disable(); - mAGPBound = FALSE; - } -} - -void LLPipeline::bindAGP() -{ - LLMemType mt(LLMemType::MTYPE_PIPELINE); - - if (mAGPMemPool && !mAGPBound && usingAGP()) - { - mAGPMemPool->enable(); - mAGPBound = TRUE; - } -} - -U8* LLPipeline::bufferGetScratchMemory(void) -{ - LLMemType mt(LLMemType::MTYPE_PIPELINE); - return(mBufferMemory[mBufferIndex]->getScratchMemory()); -} - -void LLPipeline::bufferWaitFence(void) -{ - mBufferMemory[mBufferIndex]->waitFence(mBufferFence[mBufferIndex]); -} - -void LLPipeline::bufferSendFence(void) -{ - mBufferMemory[mBufferIndex]->sendFence(mBufferFence[mBufferIndex]); -} +}; -void LLPipeline::bufferRotate(void) +// Called when a texture changes # of channels (causes faces to move to alpha pool) +void LLPipeline::dirtyPoolObjectTextures(const std::set<LLViewerImage*>& textures) { - mBufferIndex++; - if(mBufferIndex >= mBufferCount) - mBufferIndex = 0; -} + // *TODO: This is inefficient and causes frame spikes; need a better way to do this + // Most of the time is spent in dirty.traverse. -// Called when a texture changes # of channels (rare, may cause faces to move to alpha pool) -void LLPipeline::dirtyPoolObjectTextures(const LLViewerImage *texturep) -{ for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter) { LLDrawPool *poolp = *iter; - poolp->dirtyTexture(texturep); + if (poolp->isFacePool()) + { + ((LLFacePool*) poolp)->dirtyTextures(textures); + } + } + + LLOctreeDirtyTexture dirty(textures); + for (U32 i = 0; i < mObjectPartition.size(); i++) + { + if (mObjectPartition[i]) + { + dirty.traverse(mObjectPartition[i]->mOctree); + } } } @@ -1438,33 +1356,29 @@ LLDrawPool *LLPipeline::findPool(const U32 type, LLViewerImage *tex0) switch( type ) { case LLDrawPool::POOL_SIMPLE: - poolp = get_if_there(mSimplePools, (uintptr_t)tex0, (LLDrawPool*)0 ); + poolp = mSimplePool; break; case LLDrawPool::POOL_TREE: poolp = get_if_there(mTreePools, (uintptr_t)tex0, (LLDrawPool*)0 ); break; - case LLDrawPool::POOL_TREE_NEW: - poolp = get_if_there(mTreeNewPools, (uintptr_t)tex0, (LLDrawPool*)0 ); - break; - case LLDrawPool::POOL_TERRAIN: poolp = get_if_there(mTerrainPools, (uintptr_t)tex0, (LLDrawPool*)0 ); break; case LLDrawPool::POOL_BUMP: - poolp = get_if_there(mBumpPools, (uintptr_t)tex0, (LLDrawPool*)0 ); - break; - - case LLDrawPool::POOL_MEDIA: - poolp = get_if_there(mMediaPools, (uintptr_t)tex0, (LLDrawPool*)0 ); + poolp = mBumpPool; break; case LLDrawPool::POOL_ALPHA: poolp = mAlphaPool; break; + case LLDrawPool::POOL_ALPHA_POST_WATER: + poolp = mAlphaPoolPostWater; + break; + case LLDrawPool::POOL_AVATAR: break; // Do nothing @@ -1476,10 +1390,6 @@ LLDrawPool *LLPipeline::findPool(const U32 type, LLViewerImage *tex0) poolp = mStarsPool; break; - case LLDrawPool::POOL_CLOUDS: - poolp = mCloudsPool; - break; - case LLDrawPool::POOL_WATER: poolp = mWaterPool; break; @@ -1488,10 +1398,6 @@ LLDrawPool *LLPipeline::findPool(const U32 type, LLViewerImage *tex0) poolp = mGroundPool; break; - case LLDrawPool::POOL_HUD: - poolp = mHUDPool; - break; - default: llassert(0); llerrs << "Invalid Pool Type in LLPipeline::findPool() type=" << type << llendl; @@ -1522,29 +1428,37 @@ LLDrawPool *LLPipeline::getPool(const U32 type, LLViewerImage *tex0) LLDrawPool* LLPipeline::getPoolFromTE(const LLTextureEntry* te, LLViewerImage* imagep) { LLMemType mt(LLMemType::MTYPE_PIPELINE); + U32 type = getPoolTypeFromTE(te, imagep); + return gPipeline.getPool(type, imagep); +} + +//static +U32 LLPipeline::getPoolTypeFromTE(const LLTextureEntry* te, LLViewerImage* imagep) +{ + LLMemType mt(LLMemType::MTYPE_PIPELINE); + + if (!te || !imagep) + { + return 0; + } + bool alpha = te->getColor().mV[3] < 0.999f; if (imagep) { alpha = alpha || (imagep->getComponents() == 4) || (imagep->getComponents() == 2); } -#if 0 // Not currently used - if (te->getMediaFlags() == LLTextureEntry::MF_WEB_PAGE) - { - return gPipeline.getPool(LLDrawPool::POOL_MEDIA, imagep); - } - else -#endif + if (alpha) { - return gPipeline.getPool(LLDrawPool::POOL_ALPHA); + return LLDrawPool::POOL_ALPHA; } else if ((te->getBumpmap() || te->getShiny())) { - return gPipeline.getPool(LLDrawPool::POOL_BUMP, imagep); + return LLDrawPool::POOL_BUMP; } else { - return gPipeline.getPool(LLDrawPool::POOL_SIMPLE, imagep); + return LLDrawPool::POOL_SIMPLE; } } @@ -1575,14 +1489,20 @@ void LLPipeline::allocDrawable(LLViewerObject *vobj) } -void LLPipeline::unlinkDrawable(LLDrawable *drawablep) +void LLPipeline::unlinkDrawable(LLDrawable *drawable) { LLFastTimer t(LLFastTimer::FTM_PIPELINE); + + LLPointer<LLDrawable> drawablep = drawable; // make sure this doesn't get deleted before we are done // Based on flags, remove the drawable from the queues that it's on. if (drawablep->isState(LLDrawable::ON_MOVE_LIST)) { - mMovedList.erase(drawablep); + LLDrawable::drawable_vector_t::iterator iter = std::find(mMovedList.begin(), mMovedList.end(), drawablep); + if (iter != mMovedList.end()) + { + mMovedList.erase(iter); + } } if (drawablep->getSpatialGroup()) @@ -1612,9 +1532,6 @@ U32 LLPipeline::addObject(LLViewerObject *vobj) llassert(drawablep); - //mCompleteSet.put(drawable); - //gResyncObjects = TRUE; - if (vobj->getParent()) { vobj->setDrawableParent(((LLViewerObject*)vobj->getParent())->mDrawable); // LLPipeline::addObject 1 @@ -1624,28 +1541,6 @@ U32 LLPipeline::addObject(LLViewerObject *vobj) vobj->setDrawableParent(NULL); // LLPipeline::addObject 2 } - - if ((!drawablep->getVOVolume()) && - (vobj->getPCode() != LLViewerObject::LL_VO_SKY) && - (vobj->getPCode() != LLViewerObject::LL_VO_STARS) && - (vobj->getPCode() != LLViewerObject::LL_VO_GROUND)) - { - drawablep->getSpatialPartition()->put(drawablep); - if (!drawablep->getSpatialGroup()) - { -#ifdef LL_RELEASE_FOR_DOWNLOAD - llwarns << "Failure adding drawable to object partition!" << llendl; -#else - llerrs << "Failure adding drawable to object partition!" << llendl; -#endif - } - } - else - { - markMoved(drawablep); - } - - markMaterialed(drawablep); markRebuild(drawablep, LLDrawable::REBUILD_ALL, TRUE); return 1; @@ -1654,11 +1549,27 @@ U32 LLPipeline::addObject(LLViewerObject *vobj) void LLPipeline::resetFrameStats() { + mCompilesStat.addValue(sCompiles); + mLightingChangesStat.addValue(mLightingChanges); + mGeometryChangesStat.addValue(mGeometryChanges); + mTrianglesDrawnStat.addValue(mTrianglesDrawn/1000.f); + mVerticesRelitStat.addValue(mVerticesRelit); + mNumVisibleFacesStat.addValue(mNumVisibleFaces); + mNumVisibleDrawablesStat.addValue((S32)mVisibleList.size()); + + mTrianglesDrawn = 0; sCompiles = 0; mVerticesRelit = 0; mLightingChanges = 0; mGeometryChanges = 0; mNumVisibleFaces = 0; + + if (mOldRenderDebugMask != mRenderDebugMask) + { + gObjectList.clearDebugText(); + mOldRenderDebugMask = mRenderDebugMask; + } + } //external functions for asynchronous updating @@ -1683,7 +1594,7 @@ void LLPipeline::updateMoveDampedAsync(LLDrawable* drawablep) // Put on move list so that EARLY_MOVE gets cleared if (!drawablep->isState(LLDrawable::ON_MOVE_LIST)) { - mMovedList.insert(drawablep); + mMovedList.push_back(drawablep); drawablep->setState(LLDrawable::ON_MOVE_LIST); } } @@ -1709,15 +1620,35 @@ void LLPipeline::updateMoveNormalAsync(LLDrawable* drawablep) // Put on move list so that EARLY_MOVE gets cleared if (!drawablep->isState(LLDrawable::ON_MOVE_LIST)) { - mMovedList.insert(drawablep); + mMovedList.push_back(drawablep); drawablep->setState(LLDrawable::ON_MOVE_LIST); } } +void LLPipeline::updateMovedList(LLDrawable::drawable_vector_t& moved_list) +{ + for (LLDrawable::drawable_vector_t::iterator iter = moved_list.begin(); + iter != moved_list.end(); ) + { + LLDrawable::drawable_vector_t::iterator curiter = iter++; + LLDrawable *drawablep = *curiter; + BOOL done = TRUE; + if (!drawablep->isDead() && (!drawablep->isState(LLDrawable::EARLY_MOVE))) + { + done = drawablep->updateMove(); + } + drawablep->clearState(LLDrawable::EARLY_MOVE | LLDrawable::MOVE_UNDAMPED); + if (done) + { + drawablep->clearState(LLDrawable::ON_MOVE_LIST); + iter = moved_list.erase(curiter); + } + } +} + void LLPipeline::updateMove() { - mObjectPartition->mOctree->validate(); - LLFastTimer t(LLFastTimer::FTM_UPDATE_MOVE); + //LLFastTimer t(LLFastTimer::FTM_UPDATE_MOVE); LLMemType mt(LLMemType::MTYPE_PIPELINE); if (gSavedSettings.getBOOL("FreezeTime")) @@ -1727,23 +1658,18 @@ void LLPipeline::updateMove() mMoveChangesStat.addValue((F32)mMovedList.size()); - for (LLDrawable::drawable_set_t::iterator iter = mMovedList.begin(); - iter != mMovedList.end(); ) + for (LLDrawable::drawable_set_t::iterator iter = mRetexturedList.begin(); + iter != mRetexturedList.end(); ++iter) { - LLDrawable::drawable_set_t::iterator curiter = iter++; - LLDrawable *drawablep = *curiter; - BOOL done = TRUE; - if (!drawablep->isDead() && (!drawablep->isState(LLDrawable::EARLY_MOVE))) - { - done = drawablep->updateMove(); - } - drawablep->clearState(LLDrawable::EARLY_MOVE | LLDrawable::MOVE_UNDAMPED); - if (done) + LLDrawable* drawablep = *iter; + if (drawablep && !drawablep->isDead()) { - mMovedList.erase(curiter); - drawablep->clearState(LLDrawable::ON_MOVE_LIST); + drawablep->updateTexture(); } } + mRetexturedList.clear(); + + updateMovedList(mMovedList); for (LLDrawable::drawable_set_t::iterator iter = mActiveQ.begin(); iter != mActiveQ.end(); ) @@ -1752,7 +1678,8 @@ void LLPipeline::updateMove() LLDrawable* drawablep = *curiter; if (drawablep && !drawablep->isDead()) { - if (drawablep->mQuietCount++ > MAX_ACTIVE_OBJECT_QUIET_FRAMES && + if (drawablep->isRoot() && + drawablep->mQuietCount++ > MAX_ACTIVE_OBJECT_QUIET_FRAMES && (!drawablep->getParent() || !drawablep->getParent()->isActive())) { drawablep->makeStatic(); // removes drawable and its children from mActiveQ @@ -1765,172 +1692,168 @@ void LLPipeline::updateMove() } } - for (LLDrawable::drawable_set_t::iterator iter = mRetexturedList.begin(); - iter != mRetexturedList.end(); ++iter) - { - LLDrawable* drawablep = *iter; - if (drawablep && !drawablep->isDead()) - { - drawablep->updateTexture(); - } - } - mRetexturedList.clear(); - - for (LLDrawable::drawable_set_t::iterator iter = mRematerialedList.begin(); - iter != mRematerialedList.end(); ++iter) + //balance octrees { - LLDrawable* drawablep = *iter; - if (drawablep && !drawablep->isDead()) + LLFastTimer ot(LLFastTimer::FTM_OCTREE_BALANCE); + for (U32 i = 0; i < mObjectPartition.size()-1; i++) { - drawablep->updateMaterial(); + if (mObjectPartition[i]) + { + mObjectPartition[i]->mOctree->balance(); + } } } - mRematerialedList.clear(); - - if (mObjectPartition->mOctree) - { - //balance octree - LLFastTimer ot(LLFastTimer::FTM_OCTREE_BALANCE); - mObjectPartition->mOctree->validate(); - mObjectPartition->mOctree->balance(); - mObjectPartition->mOctree->validate(); - } } ///////////////////////////////////////////////////////////////////////////// // Culling and occlusion testing ///////////////////////////////////////////////////////////////////////////// -void LLPipeline::updateCull() +//static +F32 LLPipeline::calcPixelArea(LLVector3 center, LLVector3 size, LLCamera &camera) { - LLFastTimer t(LLFastTimer::FTM_CULL); - LLMemType mt(LLMemType::MTYPE_PIPELINE); + LLVector3 lookAt = center - camera.getOrigin(); + LLVector3 cross_vec = size * 2.f; + F32 dist = lookAt.magVec(); - LLDrawable::incrementVisible(); - mVisibleList.resize(0); - mVisibleList.reserve(ESTIMATED_VISIBLE_OBJECT_COUNT); - - gTrivialAccepts = 0; - - if (mObjectPartition) + //ramp down distance for nearby objects + if (dist < 16.f) { - if (gSavedSettings.getBOOL("UseOcclusion") && gGLManager.mHasOcclusionQuery) - { - mObjectPartition->processOcclusion(gCamera); - stop_glerror(); - } - mObjectPartition->cull(*gCamera); + dist /= 16.f; + dist *= dist; + dist *= 16.f; } - - // Hack for avatars - warning - this is really FRAGILE! - djs 05/06/02 - LLVOAvatar::updateAllAvatarVisiblity(); - // If there are any other hacks here, make sure to add them to the - // standard pick code. - - gMinObjectDistance = llclamp(gMinObjectDistance, MIN_NEAR_PLANE, MAX_NEAR_PLANE); + //get area of circle around node + F32 app_angle = atanf((cross_vec*0.5f).magVec()/dist); + F32 radius = app_angle*LLDrawable::sCurPixelAngle; + return radius*radius * 3.14159f; +} - F32 water_height = gAgent.getRegion()->getWaterHeight(); - F32 camera_height = gAgent.getCameraPositionAgent().mV[2]; - if (fabs(camera_height - water_height) < 2.f) - { - gMinObjectDistance = MIN_NEAR_PLANE; - } +void LLPipeline::updateCull(LLCamera& camera) +{ + LLFastTimer t(LLFastTimer::FTM_CULL); + LLMemType mt(LLMemType::MTYPE_PIPELINE); - gCamera->setNear(gMinObjectDistance); + mVisibleList.clear(); + mVisibleGroups.clear(); + mDrawableGroups.clear(); + mActiveGroups.clear(); + gTrivialAccepts = 0; + mVisibleBridge.clear(); - // Disable near clip stuff for now... + processOcclusion(camera); - // now push it back out to max value - gMinObjectDistance = MIN_NEAR_PLANE; + for (U32 i = 0; i < mObjectPartition.size(); i++) + { + if (mObjectPartition[i] && hasRenderType(mObjectPartition[i]->mDrawableType)) + { + mObjectPartition[i]->cull(camera); + } + } + //do a terse update on some off-screen geometry + processGeometry(camera); + if (gSky.mVOSkyp.notNull() && gSky.mVOSkyp->mDrawable.notNull()) { // Hack for sky - always visible. - gSky.mVOSkyp->mDrawable->setVisible(*gCamera); - mVisibleList.push_back(gSky.mVOSkyp->mDrawable); - gSky.updateCull(); - stop_glerror(); + if (hasRenderType(LLPipeline::RENDER_TYPE_SKY)) + { + gSky.mVOSkyp->mDrawable->setVisible(camera); + mVisibleList.push_back(gSky.mVOSkyp->mDrawable); + gSky.updateCull(); + stop_glerror(); + } } else { llinfos << "No sky drawable!" << llendl; } - if (gSky.mVOGroundp.notNull() && gSky.mVOGroundp->mDrawable.notNull()) + if (hasRenderType(LLPipeline::RENDER_TYPE_GROUND) && gSky.mVOGroundp.notNull() && gSky.mVOGroundp->mDrawable.notNull()) { - gSky.mVOGroundp->mDrawable->setVisible(*gCamera); + gSky.mVOGroundp->mDrawable->setVisible(camera); mVisibleList.push_back(gSky.mVOGroundp->mDrawable); } +} - // add all HUD attachments - LLVOAvatar* my_avatarp = gAgent.getAvatarObject(); - if (my_avatarp && my_avatarp->hasHUDAttachment()) +void LLPipeline::markNotCulled(LLSpatialGroup* group, LLCamera& camera, BOOL active) +{ + if (group->getData().empty()) + { + return; + } + + if (!sSkipUpdate) { - for (LLViewerJointAttachment* attachmentp = my_avatarp->mAttachmentPoints.getFirstData(); - attachmentp; - attachmentp = my_avatarp->mAttachmentPoints.getNextData()) - { - if (attachmentp->getIsHUDAttachment() && attachmentp->getObject(0)) - { - LLViewerObject* objectp = attachmentp->getObject(0); - markVisible(objectp->mDrawable); - objectp->mDrawable->updateDistance(*gCamera); - for (S32 i = 0; i < (S32)objectp->mChildList.size(); i++) - { - LLViewerObject* childp = objectp->mChildList[i]; - if (childp->mDrawable.notNull()) - { - markVisible(childp->mDrawable); - childp->mDrawable->updateDistance(*gCamera); - } - } - } - } + group->updateDistance(camera); } -} + + const F32 MINIMUM_PIXEL_AREA = 16.f; -void LLPipeline::markNotCulled(LLDrawable* drawablep, LLCamera& camera) -{ - if (drawablep->isVisible()) + if (group->mPixelArea < MINIMUM_PIXEL_AREA) { return; } - // Tricky render mode to hide selected objects, but we definitely - // don't want to do any unnecessary pointer dereferences. JC - if (gHideSelectedObjects) - { - if (drawablep->getVObj() && drawablep->getVObj()->isSelected()) + group->mLastRenderTime = gFrameTimeSeconds; + if (!group->mSpatialPartition->mRenderByGroup) + { //render by drawable + mDrawableGroups.push_back(group); + for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i) { - return; + markVisible(*i, camera); } } - - if (drawablep && (hasRenderType(drawablep->mRenderType))) - { - if (!drawablep->isState(LLDrawable::INVISIBLE|LLDrawable::FORCE_INVISIBLE)) + else + { //render by group + if (active) { - mVisibleList.push_back(drawablep); - drawablep->setVisible(camera, NULL, FALSE); + mActiveGroups.push_back(group); } - else if (drawablep->isState(LLDrawable::CLEAR_INVISIBLE)) + else { - // clear invisible flag here to avoid single frame glitch - drawablep->clearState(LLDrawable::FORCE_INVISIBLE|LLDrawable::CLEAR_INVISIBLE); + mVisibleGroups.push_back(group); + for (LLSpatialGroup::bridge_list_t::iterator i = group->mBridgeList.begin(); i != group->mBridgeList.end(); ++i) + { + LLSpatialBridge* bridge = *i; + markVisible(bridge, camera); + } } } } -void LLPipeline::doOcclusion() +void LLPipeline::doOcclusion(LLCamera& camera) { - if (gSavedSettings.getBOOL("UseOcclusion") && gGLManager.mHasOcclusionQuery) + if (sUseOcclusion) { - mObjectPartition->doOcclusion(gCamera); + for (U32 i = 0; i < mObjectPartition.size(); i++) + { + if (mObjectPartition[i] && hasRenderType(mObjectPartition[i]->mDrawableType)) + { + mObjectPartition[i]->doOcclusion(&camera); + } + } + +#if AGGRESSIVE_OCCLUSION + for (LLSpatialBridge::bridge_vector_t::iterator i = mVisibleBridge.begin(); i != mVisibleBridge.end(); ++i) + { + LLSpatialBridge* bridge = *i; + if (!bridge->isDead() && hasRenderType(bridge->mDrawableType)) + { + glPushMatrix(); + glMultMatrixf((F32*)bridge->mDrawable->getRenderMatrix().mMatrix); + LLCamera trans = bridge->transformCamera(camera); + bridge->doOcclusion(&trans); + glPopMatrix(); + mOccludedBridge.push_back(bridge); + } + } +#endif } } - BOOL LLPipeline::updateDrawableGeom(LLDrawable* drawablep, BOOL priority) { BOOL update_complete = drawablep->updateGeometry(priority); @@ -1955,19 +1878,31 @@ void LLPipeline::updateGeom(F32 max_dtime) LLVOVolume::preUpdateGeom(); // Iterate through all drawables on the priority build queue, - for (LLDrawable::drawable_set_t::iterator iter = mBuildQ1.begin(); + for (LLDrawable::drawable_list_t::iterator iter = mBuildQ1.begin(); iter != mBuildQ1.end();) { - LLDrawable::drawable_set_t::iterator curiter = iter++; + LLDrawable::drawable_list_t::iterator curiter = iter++; LLDrawable* drawablep = *curiter; - BOOL update_complete = TRUE; if (drawablep && !drawablep->isDead()) { - update_complete = updateDrawableGeom(drawablep, TRUE); + if (drawablep->isState(LLDrawable::IN_REBUILD_Q2)) + { + drawablep->clearState(LLDrawable::IN_REBUILD_Q2); + LLDrawable::drawable_list_t::iterator find = std::find(mBuildQ2.begin(), mBuildQ2.end(), drawablep); + if (find != mBuildQ2.end()) + { + mBuildQ2.erase(find); + } + } + + if (updateDrawableGeom(drawablep, TRUE)) + { + drawablep->clearState(LLDrawable::IN_REBUILD_Q1); + mBuildQ1.erase(curiter); + } } - if (update_complete) + else { - drawablep->clearState(LLDrawable::IN_REBUILD_Q1); mBuildQ1.erase(curiter); } } @@ -1978,20 +1913,34 @@ void LLPipeline::updateGeom(F32 max_dtime) { min_count = mBuildQ2.size(); } - else - { - mBuildQ2.sort(LLDrawable::CompareDistanceGreaterVisibleFirst()); - } - + S32 count = 0; max_dtime = llmax(update_timer.getElapsedTimeF32()+0.001f, max_dtime); - + LLSpatialGroup* last_group = NULL; + LLSpatialBridge* last_bridge = NULL; + for (LLDrawable::drawable_list_t::iterator iter = mBuildQ2.begin(); iter != mBuildQ2.end(); ) { LLDrawable::drawable_list_t::iterator curiter = iter++; LLDrawable* drawablep = *curiter; + + LLSpatialBridge* bridge = drawablep->isRoot() ? drawablep->getSpatialBridge() : + drawablep->getParent()->getSpatialBridge(); + + if (drawablep->getSpatialGroup() != last_group && + (!last_bridge || bridge != last_bridge) && + (update_timer.getElapsedTimeF32() >= max_dtime) && count > min_count) + { + break; + } + + //make sure updates don't stop in the middle of a spatial group + //to avoid thrashing (objects are enqueued by group) + last_group = drawablep->getSpatialGroup(); + last_bridge = bridge; + BOOL update_complete = TRUE; if (drawablep && !drawablep->isDead()) { @@ -2003,14 +1952,12 @@ void LLPipeline::updateGeom(F32 max_dtime) drawablep->clearState(LLDrawable::IN_REBUILD_Q2); mBuildQ2.erase(curiter); } - if ((update_timer.getElapsedTimeF32() >= max_dtime) && count > min_count) - { - break; - } - } + } + + updateMovedList(mMovedBridge); } -void LLPipeline::markVisible(LLDrawable *drawablep) +void LLPipeline::markVisible(LLDrawable *drawablep, LLCamera& camera) { LLMemType mt(LLMemType::MTYPE_PIPELINE); if(!drawablep || drawablep->isDead()) @@ -2018,11 +1965,36 @@ void LLPipeline::markVisible(LLDrawable *drawablep) llwarns << "LLPipeline::markVisible called with NULL drawablep" << llendl; return; } - if (!drawablep->isVisible()) + + +#if LL_DEBUG + if (drawablep->isSpatialBridge()) + { + if (std::find(mVisibleBridge.begin(), mVisibleBridge.end(), (LLSpatialBridge*) drawablep) != + mVisibleBridge.end()) + { + llerrs << "Spatial bridge marked visible redundantly." << llendl; + } + } + else + { + if (std::find(mVisibleList.begin(), mVisibleList.end(), drawablep) != + mVisibleList.end()) + { + llerrs << "Drawable marked visible redundantly." << llendl; + } + } +#endif + + if (drawablep->isSpatialBridge()) + { + mVisibleBridge.push_back((LLSpatialBridge*) drawablep); + } + else { - drawablep->setVisible(*gCamera); mVisibleList.push_back(drawablep); } + drawablep->setVisible(camera); } void LLPipeline::markMoved(LLDrawable *drawablep, BOOL damped_motion) @@ -2046,10 +2018,17 @@ void LLPipeline::markMoved(LLDrawable *drawablep, BOOL damped_motion) markMoved(drawablep->getParent(), damped_motion); } - + if (!drawablep->isState(LLDrawable::ON_MOVE_LIST)) { - mMovedList.insert(drawablep); + if (drawablep->isSpatialBridge()) + { + mMovedBridge.push_back(drawablep); + } + else + { + mMovedList.push_back(drawablep); + } drawablep->setState(LLDrawable::ON_MOVE_LIST); } if (damped_motion == FALSE) @@ -2098,30 +2077,33 @@ void LLPipeline::shiftObjects(const LLVector3 &offset) } mShiftList.resize(0); - mObjectPartition->shift(offset); + for (U32 i = 0; i < mObjectPartition.size()-1; i++) + { + if (mObjectPartition[i]) + { + mObjectPartition[i]->shift(offset); + } + } } void LLPipeline::markTextured(LLDrawable *drawablep) { LLMemType mt(LLMemType::MTYPE_PIPELINE); - if (!drawablep->isDead()) + if (drawablep && !drawablep->isDead()) { mRetexturedList.insert(drawablep); } } -void LLPipeline::markMaterialed(LLDrawable *drawablep) +void LLPipeline::markRebuild(LLSpatialGroup* group) { - LLMemType mt(LLMemType::MTYPE_PIPELINE); - if (!drawablep->isDead()) - { - mRematerialedList.insert(drawablep); - } + mGroupQ.insert(group); } void LLPipeline::markRebuild(LLDrawable *drawablep, LLDrawable::EDrawableFlags flag, BOOL priority) { LLMemType mt(LLMemType::MTYPE_PIPELINE); + if (drawablep && !drawablep->isDead()) { if (!drawablep->isState(LLDrawable::BUILT)) @@ -2130,15 +2112,18 @@ void LLPipeline::markRebuild(LLDrawable *drawablep, LLDrawable::EDrawableFlags f } if (priority) { - mBuildQ1.insert(drawablep); - drawablep->setState(LLDrawable::IN_REBUILD_Q1); // flag is not needed, just for debugging + if (!drawablep->isState(LLDrawable::IN_REBUILD_Q1)) + { + mBuildQ1.push_back(drawablep); + drawablep->setState(LLDrawable::IN_REBUILD_Q1); // mark drawable as being in priority queue + } } else if (!drawablep->isState(LLDrawable::IN_REBUILD_Q2)) { mBuildQ2.push_back(drawablep); drawablep->setState(LLDrawable::IN_REBUILD_Q2); // need flag here because it is just a list } - if (flag & LLDrawable::REBUILD_VOLUME) + if (flag & (LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION)) { drawablep->getVObj()->setChanged(LLXform::SILHOUETTE); } @@ -2165,111 +2150,406 @@ void LLPipeline::markRelight(LLDrawable *drawablep, const BOOL priority) } } -void LLPipeline::stateSort() +void LLPipeline::stateSort(LLCamera& camera) { LLFastTimer ftm(LLFastTimer::FTM_STATESORT); LLMemType mt(LLMemType::MTYPE_PIPELINE); + for (LLSpatialGroup::sg_vector_t::iterator iter = mVisibleGroups.begin(); iter != mVisibleGroups.end(); ++iter) + { + stateSort(*iter, camera); + } + + for (LLSpatialBridge::bridge_vector_t::iterator i = mVisibleBridge.begin(); i != mVisibleBridge.end(); ++i) + { + LLSpatialBridge* bridge = *i; + if (!bridge->isDead()) + { + stateSort(bridge, camera); + } + } + for (LLDrawable::drawable_vector_t::iterator iter = mVisibleList.begin(); iter != mVisibleList.end(); iter++) { LLDrawable *drawablep = *iter; - if (drawablep->isDead()) + if (!drawablep->isDead()) { - continue; + stateSort(drawablep, camera); } + } + + for (LLSpatialGroup::sg_vector_t::iterator iter = mActiveGroups.begin(); iter != mActiveGroups.end(); ++iter) + { + stateSort(*iter, camera); + } + + postSort(camera); +} - if (!drawablep->isActive()) +void LLPipeline::stateSort(LLSpatialGroup* group, LLCamera& camera) +{ + LLMemType mt(LLMemType::MTYPE_PIPELINE); + if (!sSkipUpdate && group->changeLOD()) + { + for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i) { - drawablep->updateDistance(*gCamera); + LLDrawable* drawablep = *i; + stateSort(drawablep, camera); } + } + + if (gFrameTimeSeconds - group->mLastUpdateTime > 4.f) + { + group->makeStatic(); + } +} - /* - if (!drawablep->isState(LLDrawable::BUILT)) +void LLPipeline::stateSort(LLSpatialBridge* bridge, LLCamera& camera) +{ + LLMemType mt(LLMemType::MTYPE_PIPELINE); + if (!sSkipUpdate) + { + bridge->updateDistance(camera); + } +} + +void LLPipeline::stateSort(LLDrawable* drawablep, LLCamera& camera) +{ + LLMemType mt(LLMemType::MTYPE_PIPELINE); + LLFastTimer ftm(LLFastTimer::FTM_STATESORT_DRAWABLE); + + if (drawablep->isDead() || !hasRenderType(drawablep->getRenderType())) + { + return; + } + + if (gHideSelectedObjects) + { + if (drawablep->getVObj() && + drawablep->getVObj()->isSelected()) { - // This geometry hasn't been rebuilt but it's visible, make sure it gets put on the rebuild list. - llerrs << "Visible object " << drawablep << ":" << drawablep->getVObj()->getPCodeString(); - llcont << " visible but not built, put on rebuild" << llendl; - markRebuild(drawablep); - continue; + return; } - */ + } - for (LLDrawable::face_list_t::iterator iter = drawablep->mFaces.begin(); - iter != drawablep->mFaces.end(); iter++) + if (drawablep && (hasRenderType(drawablep->mRenderType))) + { + if (!drawablep->isState(LLDrawable::INVISIBLE|LLDrawable::FORCE_INVISIBLE)) { - LLFace* facep = *iter; - if (facep->hasGeometry()) + drawablep->setVisible(camera, NULL, FALSE); + } + else if (drawablep->isState(LLDrawable::CLEAR_INVISIBLE)) + { + // clear invisible flag here to avoid single frame glitch + drawablep->clearState(LLDrawable::FORCE_INVISIBLE|LLDrawable::CLEAR_INVISIBLE); + } + } + + if (!drawablep->isActive() && drawablep->isVisible()) + { + if (!sSkipUpdate) + { + drawablep->updateDistance(camera); + } + } + else if (drawablep->isAvatar() && drawablep->isVisible()) + { + LLVOAvatar* vobj = (LLVOAvatar*) drawablep->getVObj(); + vobj->updateVisibility(FALSE); + } + + for (LLDrawable::face_list_t::iterator iter = drawablep->mFaces.begin(); + iter != drawablep->mFaces.end(); iter++) + { + LLFace* facep = *iter; + + if (facep->hasGeometry()) + { + if (facep->getPool()) { facep->getPool()->enqueue(facep); } + else + { + break; + } } - - if (sRenderPhysicalBeacons) - { - // Only show the beacon on the root object. - LLViewerObject *vobj = drawablep->getVObj(); - if (vobj - && !vobj->isAvatar() - && !vobj->getParent() - && vobj->usePhysics()) + } + + + mNumVisibleFaces += drawablep->getNumFaces(); +} + + +void LLPipeline::forAllDrawables(LLSpatialGroup::sg_vector_t& groups, void (*func)(LLDrawable*)) +{ + for (LLSpatialGroup::sg_vector_t::iterator i = groups.begin(); i != groups.end(); ++i) + { + for (LLSpatialGroup::element_iter j = (*i)->getData().begin(); j != (*i)->getData().end(); ++j) + { + func(*j); + } + } +} + +void LLPipeline::forAllVisibleDrawables(void (*func)(LLDrawable*)) +{ + forAllDrawables(mDrawableGroups, func); + forAllDrawables(mVisibleGroups, func); + forAllDrawables(mActiveGroups, func); +} + +//function for creating scripted beacons +void renderScriptedBeacons(LLDrawable* drawablep) +{ + LLViewerObject *vobj = drawablep->getVObj(); + if (vobj + && !vobj->isAvatar() + && !vobj->getParent() + && vobj->flagScripted()) + { + gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", LLColor4(1.f, 0.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f)); + } +} + +void renderPhysicalBeacons(LLDrawable* drawablep) +{ + LLViewerObject *vobj = drawablep->getVObj(); + if (vobj + && !vobj->isAvatar() + && !vobj->getParent() + && vobj->usePhysics()) + { + gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", LLColor4(0.f, 1.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f)); + } +} + +void renderParticleBeacons(LLDrawable* drawablep) +{ + // Look for attachments, objects, etc. + LLViewerObject *vobj = drawablep->getVObj(); + if (vobj + && vobj->isParticleSource()) + { + LLColor4 light_blue(0.5f, 0.5f, 1.f, 0.5f); + gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", light_blue, LLColor4(1.f, 1.f, 1.f, 0.5f)); + } +} + +void LLPipeline::highlightPhysical(LLDrawable* drawablep) +{ + LLMemType mt(LLMemType::MTYPE_PIPELINE); + LLViewerObject *vobj; + vobj = drawablep->getVObj(); + if (vobj && !vobj->isAvatar()) + { + if (!vobj->isAvatar() && + (vobj->usePhysics() || vobj->flagHandleTouch())) + { + S32 face_id; + for (face_id = 0; face_id < drawablep->getNumFaces(); face_id++) { - gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", LLColor4(0.f, 1.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f)); + gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) ); } } + } +} + +void LLPipeline::postSort(LLCamera& camera) +{ + LLMemType mt(LLMemType::MTYPE_PIPELINE); + LLFastTimer ftm(LLFastTimer::FTM_STATESORT_POSTSORT); + //reset render data sets + clearRenderMap(); + mAlphaGroups.clear(); + mAlphaGroupsPostWater.clear(); + + if (!gSavedSettings.getBOOL("RenderRippleWater") && hasRenderType(LLDrawPool::POOL_ALPHA)) + { //turn off clip plane for non-ripple water + toggleRenderType(LLDrawPool::POOL_ALPHA); + } + + F32 water_height = gAgent.getRegion()->getWaterHeight(); + BOOL above_water = gCamera->getOrigin().mV[2] > water_height ? TRUE : FALSE; - if (sRenderScriptedBeacons) + //prepare occlusion geometry + if (sUseOcclusion) + { + for (U32 i = 0; i < mObjectPartition.size(); i++) { - // Only show the beacon on the root object. - LLViewerObject *vobj = drawablep->getVObj(); - if (vobj - && !vobj->isAvatar() - && !vobj->getParent() - && vobj->flagScripted()) + if (mObjectPartition[i] && hasRenderType(mObjectPartition[i]->mDrawableType)) { - gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", LLColor4(1.f, 0.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f)); + mObjectPartition[i]->buildOcclusion(); + } + } + +#if AGGRESSIVE_OCCLUSION + for (LLSpatialBridge::bridge_vector_t::iterator i = mVisibleBridge.begin(); i != mVisibleBridge.end(); ++i) + { + LLSpatialBridge* bridge = *i; + if (!bridge->isDead() && hasRenderType(bridge->mDrawableType)) + { + bridge->buildOcclusion(); } } +#endif + } + + + //rebuild offscreen geometry + if (!sSkipUpdate) + { + for (LLSpatialGroup::sg_set_t::iterator iter = mGroupQ.begin(); iter != mGroupQ.end(); ++iter) + { + LLSpatialGroup* group = *iter; + group->rebuildGeom(); + } + mGroupQ.clear(); + + //rebuild drawable geometry + for (LLSpatialGroup::sg_vector_t::iterator i = mDrawableGroups.begin(); i != mDrawableGroups.end(); ++i) + { + LLSpatialGroup* group = *i; + group->rebuildGeom(); + } + } - if (sRenderParticleBeacons) + //build render map + for (LLSpatialGroup::sg_vector_t::iterator i = mVisibleGroups.begin(); i != mVisibleGroups.end(); ++i) + { + LLSpatialGroup* group = *i; + if (!sSkipUpdate) + { + group->rebuildGeom(); + } + for (LLSpatialGroup::draw_map_t::iterator j = group->mDrawMap.begin(); j != group->mDrawMap.end(); ++j) { - // Look for attachments, objects, etc. - LLViewerObject *vobj = drawablep->getVObj(); - if (vobj - && vobj->isParticleSource()) + std::vector<LLDrawInfo*>& src_vec = j->second; + std::vector<LLDrawInfo*>& dest_vec = mRenderMap[j->first]; + + for (std::vector<LLDrawInfo*>::iterator k = src_vec.begin(); k != src_vec.end(); ++k) { - LLColor4 light_blue(0.5f, 0.5f, 1.f, 0.5f); - gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", light_blue, LLColor4(1.f, 1.f, 1.f, 0.5f)); + dest_vec.push_back(*k); } } + + LLSpatialGroup::draw_map_t::iterator alpha = group->mDrawMap.find(LLRenderPass::PASS_ALPHA); + + if (alpha != group->mDrawMap.end()) + { //store alpha groups for sorting + if (!sSkipUpdate) + { + group->updateDistance(camera); + } + + if (hasRenderType(LLDrawPool::POOL_ALPHA)) + { + BOOL above = group->mObjectBounds[0].mV[2] + group->mObjectBounds[1].mV[2] > water_height ? TRUE : FALSE; + BOOL below = group->mObjectBounds[0].mV[2] - group->mObjectBounds[1].mV[2] < water_height ? TRUE : FALSE; + + if (below == above_water || above == below) + { + mAlphaGroups.push_back(group); + } - // Draw physical objects in red. - if (gHUDManager->getShowPhysical()) + if (above == above_water || below == above) + { + mAlphaGroupsPostWater.push_back(group); + } + } + else + { + mAlphaGroupsPostWater.push_back(group); + } + } + } + + //store active alpha groups + for (LLSpatialGroup::sg_vector_t::iterator i = mActiveGroups.begin(); i != mActiveGroups.end(); ++i) + { + LLSpatialGroup* group = *i; + if (!sSkipUpdate) { - LLViewerObject *vobj; - vobj = drawablep->getVObj(); - if (vobj && !vobj->isAvatar()) + group->rebuildGeom(); + } + LLSpatialGroup::draw_map_t::iterator alpha = group->mDrawMap.find(LLRenderPass::PASS_ALPHA); + + if (alpha != group->mDrawMap.end()) + { + LLSpatialBridge* bridge = group->mSpatialPartition->asBridge(); + LLCamera trans_camera = bridge->transformCamera(camera); + if (!sSkipUpdate) { - if (!vobj->isAvatar() && - (vobj->usePhysics() || vobj->flagHandleTouch())) + group->updateDistance(trans_camera); + } + + if (hasRenderType(LLDrawPool::POOL_ALPHA)) + { + LLSpatialGroup* bridge_group = bridge->getSpatialGroup(); + BOOL above = bridge_group->mObjectBounds[0].mV[2] + bridge_group->mObjectBounds[1].mV[2] > water_height ? TRUE : FALSE; + BOOL below = bridge_group->mObjectBounds[0].mV[2] - bridge_group->mObjectBounds[1].mV[2] < water_height ? TRUE : FALSE; + + + if (below == above_water || above == below) { - if (!drawablep->isVisible()) - { - // Skip objects that aren't visible. - continue; - } - S32 face_id; - for (face_id = 0; face_id < drawablep->getNumFaces(); face_id++) - { - mHighlightFaces.put(drawablep->getFace(face_id) ); - } + mAlphaGroups.push_back(group); + } + + if (above == above_water || below == above) + { + mAlphaGroupsPostWater.push_back(group); } } + else + { + mAlphaGroupsPostWater.push_back(group); + } } + } - mNumVisibleFaces += drawablep->getNumFaces(); + //sort by texture or bump map + for (U32 i = 0; i < LLRenderPass::NUM_RENDER_TYPES; ++i) + { + if (!mRenderMap[i].empty()) + { + if (i == LLRenderPass::PASS_BUMP) + { + std::sort(mRenderMap[i].begin(), mRenderMap[i].end(), LLDrawInfo::CompareBump()); + } + else + { + std::sort(mRenderMap[i].begin(), mRenderMap[i].end(), LLDrawInfo::CompareTexturePtr()); + } + } } - + + std::sort(mAlphaGroups.begin(), mAlphaGroups.end(), LLSpatialGroup::CompareDepthGreater()); + std::sort(mAlphaGroupsPostWater.begin(), mAlphaGroupsPostWater.end(), LLSpatialGroup::CompareDepthGreater()); + + if (sRenderScriptedBeacons) + { + // Only show the beacon on the root object. + forAllVisibleDrawables(renderScriptedBeacons); + } + + if (sRenderPhysicalBeacons) + { + // Only show the beacon on the root object. + forAllVisibleDrawables(renderPhysicalBeacons); + } + + if (sRenderParticleBeacons) + { + forAllVisibleDrawables(renderParticleBeacons); + } + + // Draw physical objects in red. + if (gHUDManager->getShowPhysical()) + { + forAllVisibleDrawables(highlightPhysical); + } + // If god mode, also show audio cues if (sRenderSoundBeacons && gAudiop) { @@ -2292,7 +2572,7 @@ void LLPipeline::stateSort() LLFloaterTelehub::addBeacons(); } - mSelectedFaces.reset(); + mSelectedFaces.clear(); // Draw face highlights for selected faces. if (gSelectMgr->getTEMode()) @@ -2303,54 +2583,7 @@ void LLPipeline::stateSort() while (vobjp) { - LLDrawable *drawablep = vobjp->mDrawable; - if (!drawablep || drawablep->isDead() || (!vobjp->isHUDAttachment() && !drawablep->isVisible())) - { - llwarns << "Dead drawable on selected face list!" << llendl; - } - else - { - LLVOVolume *volp = drawablep->getVOVolume(); - if (volp) - { - if (volp->getAllTEsSame()) - { - SelectedFaceInfo* faceinfo = mSelectedFaces.reserve_block(1); - faceinfo->mFacep = drawablep->getFace(vobjp->getFaceIndexOffset()); - faceinfo->mTE = te; - } - else - { - // This is somewhat inefficient, but works correctly. - S32 face_id; - for (face_id = 0; face_id < vobjp->getVolume()->getNumFaces(); face_id++) - { - LLFace *facep = drawablep->getFace(face_id + vobjp->getFaceIndexOffset()); - if (te == facep->getTEOffset()) - { - SelectedFaceInfo* faceinfo = mSelectedFaces.reserve_block(1); - faceinfo->mFacep = facep; - faceinfo->mTE = -1; - } - } - } - } - else - { - // This is somewhat inefficient, but works correctly. - S32 face_id; - for (face_id = 0; face_id < drawablep->getNumFaces(); face_id++) - { - LLFace *facep = drawablep->getFace(face_id + vobjp->getFaceIndexOffset()); - if (te == facep->getTEOffset()) - { - SelectedFaceInfo* faceinfo = mSelectedFaces.reserve_block(1); - faceinfo->mFacep = facep; - faceinfo->mTE = -1; - } - } - } - } + mSelectedFaces.push_back(vobjp->mDrawable->getFace(te)); gSelectMgr->getSelection()->getNextTE(&vobjp,&te); } } @@ -2363,13 +2596,13 @@ static void render_hud_elements() gPipeline.disableLights(); gPipeline.renderDebug(); - + LLGLDisable fog(GL_FOG); LLGLSUIDefault gls_ui; if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) { - gViewerWindow->renderSelections(FALSE, FALSE, FALSE); // For HUD bersion in render_ui_3d() + gViewerWindow->renderSelections(FALSE, FALSE, FALSE); // For HUD version in render_ui_3d() // Draw the tracking overlays LLTracker::render3D(); @@ -2384,7 +2617,7 @@ static void render_hud_elements() gParcelMgr->render(); gParcelMgr->renderParcelCollision(); } - + // Render debugging beacons. gObjectList.renderObjectBeacons(); LLHUDObject::renderAll(); @@ -2395,11 +2628,15 @@ static void render_hud_elements() // This is only set when not rendering the UI, for parcel snapshots gParcelMgr->render(); } - + else if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD)) + { + LLHUDText::renderAllHUD(); + } } void LLPipeline::renderHighlights() { + LLMemType mt(LLMemType::MTYPE_PIPELINE); // Draw 3D UI elements here (before we clear the Z buffer in POOL_HUD) // Render highlighted faces. LLColor4 color(1.f, 1.f, 1.f, 0.5f); @@ -2421,48 +2658,15 @@ void LLPipeline::renderHighlights() } mFaceSelectImagep->addTextureStats((F32)MAX_IMAGE_AREA); - for (S32 i = 0; i < mSelectedFaces.count(); i++) + for (U32 i = 0; i < mSelectedFaces.size(); i++) { - LLFace *facep = mSelectedFaces[i].mFacep; + LLFace *facep = mSelectedFaces[i]; if (!facep || facep->getDrawable()->isDead()) { llerrs << "Bad face on selection" << llendl; } - LLDrawPool* poolp = facep->getPool(); - - if (!poolp->canUseAGP()) - { - unbindAGP(); - } - else if (usingAGP()) - { - bindAGP(); - } - - if (mSelectedFaces[i].mTE == -1) - { - // Yes, I KNOW this is stupid... - poolp->renderFaceSelected(facep, mFaceSelectImagep, color); - } - else - { - LLVOVolume *volp = (LLVOVolume *)facep->getViewerObject(); - // Do the special coalesced face mode. - S32 j; - S32 offset = 0; - S32 count = volp->getVolume()->getVolumeFace(0).mIndices.size(); - for (j = 0; j <= mSelectedFaces[i].mTE; j++) - { - count = volp->getVolume()->getVolumeFace(j).mIndices.size(); - if (j < mSelectedFaces[i].mTE) - { - offset += count; - } - } - - poolp->renderFaceSelected(facep, mFaceSelectImagep, color, offset, count); - } + facep->renderSelected(mFaceSelectImagep, color); } } @@ -2470,26 +2674,16 @@ void LLPipeline::renderHighlights() { // Paint 'em red! color.setVec(1.f, 0.f, 0.f, 0.5f); - for (S32 i = 0; i < mHighlightFaces.count(); i++) + for (U32 i = 0; i < mHighlightFaces.size(); i++) { LLFace* facep = mHighlightFaces[i]; - LLDrawPool* poolp = facep->getPool(); - if (!poolp->canUseAGP()) - { - unbindAGP(); - } - else if (usingAGP()) - { - bindAGP(); - } - - poolp->renderFaceSelected(facep, LLViewerImage::sNullImagep, color); + facep->renderSelected(LLViewerImage::sNullImagep, color); } } // Contains a list of the faces of objects that are physical or // have touch-handlers. - mHighlightFaces.reset(); + mHighlightFaces.clear(); if (mVertexShaderLevel[SHADER_INTERFACE] > 0) { @@ -2497,11 +2691,11 @@ void LLPipeline::renderHighlights() } } -void LLPipeline::renderGeom() +void LLPipeline::renderGeom(LLCamera& camera) { LLMemType mt(LLMemType::MTYPE_PIPELINE); LLFastTimer t(LLFastTimer::FTM_RENDER_GEOMETRY); - + if (!mAlphaSizzleImagep) { mAlphaSizzleImagep = gImageList.getImage(LLUUID(gViewerArt.getString("alpha_sizzle.tga")), MIPMAP_TRUE, TRUE); @@ -2513,6 +2707,8 @@ void LLPipeline::renderGeom() // // + glEnableClientState(GL_VERTEX_ARRAY); + stop_glerror(); gFrameStats.start(LLFrameStats::RENDER_SYNC); @@ -2520,6 +2716,7 @@ void LLPipeline::renderGeom() #ifndef LL_RELEASE_FOR_DOWNLOAD LLGLState::checkStates(); LLGLState::checkTextureChannels(); + LLGLState::checkClientArrays(); #endif if (mRenderDebugMask & RENDER_DEBUG_VERIFY) { @@ -2529,27 +2726,23 @@ void LLPipeline::renderGeom() } } - if (mAGPMemPool) { - mAGPMemPool->waitFence(mGlobalFence); + //LLFastTimer ftm(LLFastTimer::FTM_TEMP6); + LLVertexBuffer::startRender(); } - unbindAGP(); for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter) { LLDrawPool *poolp = *iter; if (hasRenderType(poolp->getType())) { poolp->prerender(); - poolp->syncAGP(); } } gFrameStats.start(LLFrameStats::RENDER_GEOM); // Initialize lots of GL state to "safe" values - mTrianglesDrawn = 0; - glMatrixMode(GL_TEXTURE); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); @@ -2557,13 +2750,13 @@ void LLPipeline::renderGeom() LLGLSPipeline gls_pipeline; LLGLState gls_color_material(GL_COLOR_MATERIAL, mLightingDetail < 2); - LLGLState normalize(GL_NORMALIZE, TRUE); + // LLGLState normalize(GL_NORMALIZE, TRUE); // Toggle backface culling for debugging LLGLEnable cull_face(mBackfaceCull ? GL_CULL_FACE : 0); // Set fog LLGLEnable fog_enable(hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_FOG) ? GL_FOG : 0); - + gSky.updateFog(camera.getFar()); LLViewerImage::sDefaultImagep->bind(0); LLViewerImage::sDefaultImagep->setClamp(FALSE, FALSE); @@ -2572,19 +2765,20 @@ void LLPipeline::renderGeom() // // Actually render all of the geometry // - // - + // stop_glerror(); - BOOL non_agp = FALSE; BOOL did_hud_elements = FALSE; - + BOOL occlude = sUseOcclusion; + U32 cur_type = 0; - S32 skipped_vertices = 0; + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_PICKING)) + { + gObjectList.renderObjectsForSelect(camera); + } + else { LLFastTimer t(LLFastTimer::FTM_POOLS); - BOOL occlude = TRUE; - calcNearbyLights(); pool_set_t::iterator iter1 = mPools.begin(); @@ -2594,80 +2788,27 @@ void LLPipeline::renderGeom() cur_type = poolp->getType(); - if (cur_type >= LLDrawPool::POOL_TREE && occlude) - { //all the occluders have been drawn, do occlusion queries - if (mVertexShadersEnabled) - { - glUseProgramObjectARB(0); - } - doOcclusion(); + if (occlude && cur_type > LLDrawPool::POOL_AVATAR) + { occlude = FALSE; + doOcclusion(camera); } - - if (cur_type >= LLDrawPool::POOL_HUD && !did_hud_elements) + + if (cur_type > LLDrawPool::POOL_ALPHA_POST_WATER && !did_hud_elements) { renderHighlights(); // Draw 3D UI elements here (before we clear the Z buffer in POOL_HUD) - if (mVertexShadersEnabled) - { - glUseProgramObjectARB(0); - } render_hud_elements(); did_hud_elements = TRUE; } pool_set_t::iterator iter2 = iter1; - if (hasRenderType(poolp->getType())) + if (hasRenderType(poolp->getType()) && poolp->getNumPasses() > 0) { LLFastTimer t(LLFastTimer::FTM_POOLRENDER); setupHWLights(poolp); - - if (mVertexShadersEnabled && poolp->getVertexShaderLevel() == 0) - { - glUseProgramObjectARB(0); - } - else if (mVertexShadersEnabled) - { - mMaterialIndex = mSpecularIndex = 0; - switch(cur_type) - { - case LLDrawPool::POOL_SKY: - case LLDrawPool::POOL_STARS: - case LLDrawPool::POOL_CLOUDS: - glUseProgramObjectARB(0); - break; - case LLDrawPool::POOL_TERRAIN: - mTerrainProgram.bind(); - break; - case LLDrawPool::POOL_GROUND: - mGroundProgram.bind(); - break; - case LLDrawPool::POOL_TREE: - case LLDrawPool::POOL_TREE_NEW: - case LLDrawPool::POOL_SIMPLE: - case LLDrawPool::POOL_MEDIA: - mObjectSimpleProgram.bind(); - break; - case LLDrawPool::POOL_BUMP: - mObjectBumpProgram.bind(); - break; - case LLDrawPool::POOL_AVATAR: - glUseProgramObjectARB(0); - break; - case LLDrawPool::POOL_WATER: - glUseProgramObjectARB(0); - break; - case LLDrawPool::POOL_ALPHA: - mObjectAlphaProgram.bind(); - break; - case LLDrawPool::POOL_HUD: - default: - glUseProgramObjectARB(0); - break; - } - } - + for( S32 i = 0; i < poolp->getNumPasses(); i++ ) { poolp->beginRenderPass(i); @@ -2678,33 +2819,19 @@ void LLPipeline::renderGeom() { break; } - if (p->getType() != LLDrawPool::POOL_AVATAR - && p->getType() != LLDrawPool::POOL_ALPHA - && p->getType() != LLDrawPool::POOL_HUD - && (!p->getIndexCount() || !p->getVertexCount())) - { - continue; - } - - if (p->canUseAGP() && usingAGP()) - { - bindAGP(); - } - else - { - //llinfos << "Rendering pool type " << p->getType() << " without AGP!" << llendl; - unbindAGP(); - non_agp = TRUE; - } - + p->resetTrianglesDrawn(); p->render(i); mTrianglesDrawn += p->getTrianglesDrawn(); - skipped_vertices += p->mSkippedVertices; - p->mSkippedVertices = 0; } poolp->endRenderPass(i); #ifndef LL_RELEASE_FOR_DOWNLOAD + GLint depth; + glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &depth); + if (depth > 3) + { + llerrs << "GL matrix stack corrupted!" << llendl; + } LLGLState::checkStates(); LLGLState::checkTextureChannels(); LLGLState::checkClientArrays(); @@ -2726,21 +2853,18 @@ void LLPipeline::renderGeom() iter1 = iter2; stop_glerror(); } - - if (occlude) - { - if (mVertexShadersEnabled) - { - glUseProgramObjectARB(0); - } - doOcclusion(); - } } - stop_glerror(); - - if (mVertexShadersEnabled) + +#ifndef LL_RELEASE_FOR_DOWNLOAD + LLGLState::checkStates(); + LLGLState::checkTextureChannels(); + LLGLState::checkClientArrays(); +#endif + + if (occlude) { - glUseProgramObjectARB(0); + doOcclusion(camera); + occlude = FALSE; } if (!did_hud_elements) @@ -2748,32 +2872,65 @@ void LLPipeline::renderGeom() renderHighlights(); render_hud_elements(); } + + stop_glerror(); - static S32 agp_mix_count = 0; - if (non_agp && usingAGP()) { - if (0 == agp_mix_count % 16) - { - lldebugs << "Mixing AGP and non-AGP pools, slow!" << llendl; - } - agp_mix_count++; + LLVertexBuffer::stopRender(); } - else + +#ifndef LL_RELEASE_FOR_DOWNLOAD + LLGLState::checkStates(); + LLGLState::checkTextureChannels(); + LLGLState::checkClientArrays(); +#endif + + // Contains a list of the faces of objects that are physical or + // have touch-handlers. + mHighlightFaces.clear(); +} + +void LLPipeline::processGeometry(LLCamera& camera) +{ + if (sSkipUpdate) { - agp_mix_count = 0; + return; } - // Contains a list of the faces of objects that are physical or - // have touch-handlers. - mHighlightFaces.reset(); + for (U32 i = 0; i < mObjectPartition.size(); i++) + { + if (mObjectPartition[i] && hasRenderType(mObjectPartition[i]->mDrawableType)) + { + mObjectPartition[i]->processGeometry(&camera); + } + } +} - // This wait is in case we try to do multiple renders of a frame, - // I don't know what happens when we send a fence multiple times without - // checking it. - if (mAGPMemPool) +void LLPipeline::processOcclusion(LLCamera& camera) +{ + //process occlusion (readback) + if (sUseOcclusion) { - mAGPMemPool->waitFence(mGlobalFence); - mAGPMemPool->sendFence(mGlobalFence); + for (U32 i = 0; i < mObjectPartition.size(); i++) + { + if (mObjectPartition[i] && hasRenderType(mObjectPartition[i]->mDrawableType)) + { + mObjectPartition[i]->processOcclusion(&camera); + } + } + +#if AGGRESSIVE_OCCLUSION + for (LLSpatialBridge::bridge_vector_t::iterator i = mOccludedBridge.begin(); i != mOccludedBridge.end(); ++i) + { + LLSpatialBridge* bridge = *i; + if (!bridge->isDead() && hasRenderType(bridge->mDrawableType)) + { + LLCamera trans = bridge->transformCamera(camera); + bridge->processOcclusion(&trans); + } + } +#endif + mOccludedBridge.clear(); } } @@ -2782,13 +2939,30 @@ void LLPipeline::renderDebug() LLMemType mt(LLMemType::MTYPE_PIPELINE); // Disable all client state - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); // Debug stuff. - mObjectPartition->renderDebug(); + for (U32 i = 0; i < mObjectPartition.size(); i++) + { + if (mObjectPartition[i] && hasRenderType(mObjectPartition[i]->mDrawableType)) + { + mObjectPartition[i]->renderDebug(); + } + } + + for (LLSpatialBridge::bridge_vector_t::iterator i = mVisibleBridge.begin(); i != mVisibleBridge.end(); ++i) + { + LLSpatialBridge* bridge = *i; + if (!bridge->isDead() && hasRenderType(bridge->mDrawableType)) + { + glPushMatrix(); + glMultMatrixf((F32*)bridge->mDrawable->getRenderMatrix().mMatrix); + bridge->renderDebug(); + glPopMatrix(); + } + } if (mRenderDebugMask & LLPipeline::RENDER_DEBUG_LIGHT_TRACE) { @@ -2835,81 +3009,6 @@ void LLPipeline::renderDebug() } } - mCompilesStat.addValue(sCompiles); - mLightingChangesStat.addValue(mLightingChanges); - mGeometryChangesStat.addValue(mGeometryChanges); - mTrianglesDrawnStat.addValue(mTrianglesDrawn/1000.f); - mVerticesRelitStat.addValue(mVerticesRelit); - mNumVisibleFacesStat.addValue(mNumVisibleFaces); - mNumVisibleDrawablesStat.addValue((S32)mVisibleList.size()); - - if (gRenderLightGlows) - { - displaySSBB(); - } - - /*if (mRenderDebugMask & RENDER_DEBUG_BBOXES) - { - LLGLSPipelineAlpha gls_pipeline_alpha; - LLGLSNoTexture no_texture; - - for (LLDrawable::drawable_vector_t::iterator iter = mVisibleList.begin(); iter != mVisibleList.end(); iter++) - { - LLDrawable *drawablep = *iter; - if (drawablep->isDead()) - { - continue; - } - LLVector3 min, max; - - if (drawablep->getVObj() && drawablep->getVObj()->getPCode() == LLViewerObject::LL_VO_SURFACE_PATCH) - { - // Render drawable bbox - drawablep->getBounds(min, max); - glColor4f(0.f, 1.f, 0.f, 0.25f); - render_bbox(min, max); - - // Render object bbox - LLVector3 scale = drawablep->getVObj()->getScale(); - LLVector3 pos = drawablep->getVObj()->getPositionAgent(); - min = pos - scale * 0.5f; - max = pos + scale * 0.5f; - glColor4f(1.f, 0.f, 0.f, 0.25f); - render_bbox(min, max); - } - } - }*/ - - /* - // Debugging code for parcel sound. - F32 x, y; - - LLGLSNoTexture gls_no_texture; - - glBegin(GL_POINTS); - if (gAgent.getRegion()) - { - // Draw the composition layer for the region that I'm in. - for (x = 0; x <= 260; x++) - { - for (y = 0; y <= 260; y++) - { - if (gParcelMgr->isSoundLocal(gAgent.getRegion()->getOriginGlobal() + LLVector3d(x, y, 0.f))) - { - glColor4f(1.f, 0.f, 0.f, 1.f); - } - else - { - glColor4f(0.f, 0.f, 1.f, 1.f); - } - - glVertex3f(x, y, gAgent.getRegion()->getLandHeightRegion(LLVector3(x, y, 0.f))); - } - } - } - glEnd(); - */ - if (mRenderDebugMask & RENDER_DEBUG_COMPOSITION) { // Debug composition layers @@ -2942,358 +3041,163 @@ void LLPipeline::renderDebug() } glEnd(); } - - if (mRenderDebugMask & RENDER_DEBUG_AGP_MEM) - { - displayAGP(); - } - - if (mRenderDebugMask & RENDER_DEBUG_POOLS) - { - displayPools(); - } - -// if (mRenderDebugMask & RENDER_DEBUG_QUEUES) -// { -// displayQueues(); -// } - - if (mRenderDebugMask & RENDER_DEBUG_MAP) - { - displayMap(); - } } - - - -BOOL compute_min_max(LLMatrix4& box, LLVector2& min, LLVector2& max) +void LLPipeline::renderForSelect(std::set<LLViewerObject*>& objects) { - min.setVec(1000,1000); - max.setVec(-1000,-1000); - - if (box.mMatrix[3][3] <= 0.0f) return FALSE; + LLMemType mt(LLMemType::MTYPE_PIPELINE); + + LLVertexBuffer::startRender(); + + glMatrixMode(GL_MODELVIEW); - const F32 vec[8][3] = { - { -0.5f,-0.5f,-0.5f }, - { -0.5f,-0.5f,+0.5f }, - { -0.5f,+0.5f,-0.5f }, - { -0.5f,+0.5f,+0.5f }, - { +0.5f,-0.5f,-0.5f }, - { +0.5f,-0.5f,+0.5f }, - { +0.5f,+0.5f,-0.5f }, - { +0.5f,+0.5f,+0.5f } }; - - LLVector4 v; + LLGLSDefault gls_default; + LLGLSObjectSelect gls_object_select; + LLGLDepthTest gls_depth(GL_TRUE,GL_TRUE); + disableLights(); + + glEnableClientState ( GL_VERTEX_ARRAY ); - for (S32 i=0;i<8;i++) + //for each drawpool +#ifndef LL_RELEASE_FOR_DOWNLOAD + LLGLState::checkStates(); + LLGLState::checkTextureChannels(); + LLGLState::checkClientArrays(); + U32 last_type = 0; +#endif + for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter) { - v.setVec(vec[i][0],vec[i][1],vec[i][2],1); - v = v * box; - F32 iw = 1.0f / v.mV[3]; - v.mV[0] *= iw; - v.mV[1] *= iw; - - min.mV[0] = llmin(min.mV[0],v.mV[0]); - max.mV[0] = llmax(max.mV[0],v.mV[0]); - - min.mV[1] = llmin(min.mV[1],v.mV[1]); - max.mV[1] = llmax(max.mV[1],v.mV[1]); + LLDrawPool *poolp = *iter; + if (poolp->isFacePool() && hasRenderType(poolp->getType())) + { + LLFacePool* face_pool = (LLFacePool*) poolp; + face_pool->renderForSelect(); + +#ifndef LL_RELEASE_FOR_DOWNLOAD + if (poolp->getType() != last_type) + { + last_type = poolp->getType(); + LLGLState::checkStates(); + LLGLState::checkTextureChannels(); + LLGLState::checkClientArrays(); + } +#endif + } } - /* - min.mV[0] = max.mV[0] = box.mMatrix[3][0]; - min.mV[1] = max.mV[1] = box.mMatrix[3][1]; - F32 iw = 1.0f / box.mMatrix[3][3]; - - F32 f0 = (fabs(box.mMatrix[0][0])+fabs(box.mMatrix[1][0])+fabs(box.mMatrix[2][0])) * 0.5f; - F32 f1 = (fabs(box.mMatrix[0][1])+fabs(box.mMatrix[1][1])+fabs(box.mMatrix[2][1])) * 0.5f; - F32 f2 = (fabs(box.mMatrix[0][2])+fabs(box.mMatrix[1][2])+fabs(box.mMatrix[2][2])) * 0.5f; - - min.mV[0] -= f0; - min.mV[1] -= f1; - - max.mV[0] += f0; - max.mV[1] += f1; - - min.mV[0] *= iw; - min.mV[1] *= iw; - - max.mV[0] *= iw; - max.mV[1] *= iw; - */ - return TRUE; -} - -void LLPipeline::displaySSBB() -{ - LLMatrix4 proj; - LLMatrix4 cfr(OGL_TO_CFR_ROTATION); - LLMatrix4 camera; - LLMatrix4 comb; - - gCamera->getMatrixToLocal(camera); - - if (!mBloomImagep) + LLGLEnable tex(GL_TEXTURE_2D); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + LLGLEnable alpha_test(GL_ALPHA_TEST); + if (gPickTransparent) { - mBloomImagep = gImageList.getImage(IMG_BLOOM1); + glAlphaFunc(GL_GEQUAL, 0.0f); + } + else + { + glAlphaFunc(GL_GREATER, 0.2f); } - // don't write to depth buffer with light glows so that chat bubbles can pop through - LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE); - LLViewerImage::bindTexture(mBloomImagep); - - glGetFloatv(GL_PROJECTION_MATRIX,(float*)proj.mMatrix); - - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE); - LLGLSPipelineAlpha gls_pipeline_alpha; + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PRIMARY_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR); - //glScalef(0.25,0.25,0.25); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA); - S32 sizex = gViewerWindow->getWindowWidth() / 2; - S32 sizey = gViewerWindow->getWindowHeight() / 2; + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_PRIMARY_COLOR_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB, GL_SRC_ALPHA); - F32 aspect = (float)sizey / (float)sizex; + U32 prim_mask = LLVertexBuffer::MAP_VERTEX | + LLVertexBuffer::MAP_TEXCOORD; - for (LLDrawable::drawable_set_t::iterator iter = mLights.begin(); - iter != mLights.end(); iter++) + for (std::set<LLViewerObject*>::iterator i = objects.begin(); i != objects.end(); ++i) { - LLDrawable *lightp = *iter; - if (lightp->isDead()) + LLViewerObject* vobj = *i; + LLDrawable* drawable = vobj->mDrawable; + if (vobj->isDead() || + vobj->isHUDAttachment() || + (gHideSelectedObjects && vobj->isSelected()) || + drawable->isDead() || + !hasRenderType(drawable->getRenderType())) { continue; } - - LLMatrix4 mat = lightp->mXform.getWorldMatrix(); - - mat *= camera; - mat *= cfr; - mat *= proj; - - U8 color[64]; - LLVector2 min,max; - if (mat.mMatrix[3][3] < 160 && compute_min_max(mat,min,max)) + for (S32 j = 0; j < drawable->getNumFaces(); ++j) { - F32 cx = (max.mV[0] + min.mV[0]) * 0.5f; - F32 cy = (max.mV[1] + min.mV[1]) * 0.5f; - F32 sx = (max.mV[0] - min.mV[0]) * 2.0f; - F32 sy = (max.mV[1] - min.mV[1]) * 2.0f; - S32 x = (S32)(cx * (F32)sizex) + sizex; - S32 y = (S32)(cy * (F32)sizey) + sizey; - - if (cx > -1 && cx < 1 && cy > -1 && cy < 1) + LLFace* facep = drawable->getFace(j); + if (!facep->getPool()) { - glReadPixels(x-2,y-2,4,4,GL_RGBA,GL_UNSIGNED_BYTE,&color[0]); - - S32 total = 0; - for (S32 i=0;i<64;i++) - { - total += color[i]; - } - total /= 64; - - sx = (sy = (sx + sy) * 0.5f * ((float)total/255.0f)) * aspect; - - - if (total > 60) - { - color[3+32] = total >> 1; - glBegin(GL_QUADS); - glColor4ubv(&color[32]); - glTexCoord2f(0,0); - glVertex3f(cx-sx,cy-sy,0); - glTexCoord2f(1,0); - glVertex3f(cx+sx,cy-sy,0); - glTexCoord2f(1,1); - glVertex3f(cx+sx,cy+sy,0); - glTexCoord2f(0,1); - glVertex3f(cx-sx,cy+sy,0); - glEnd(); - } + facep->renderForSelect(prim_mask); } } - } - // sun + // pick HUD objects + LLVOAvatar* avatarp = gAgent.getAvatarObject(); + if (avatarp && sShowHUDAttachments) { - LLVector4 sdir(gSky.getSunDirection() * 10000.0f + gAgent.getPositionAgent()); - sdir.mV[3] = 1.0f; - sdir = sdir * camera; - sdir = sdir * cfr; - sdir = sdir * proj; // todo: preconcat - - sdir.mV[0] /= sdir.mV[3]; - sdir.mV[1] /= sdir.mV[3]; - - U8 color[64]; + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); - if (sdir.mV[3] > 0) + setup_hud_matrices(TRUE); + LLViewerJointAttachment* attachmentp; + for (attachmentp = avatarp->mAttachmentPoints.getFirstData(); + attachmentp; + attachmentp = avatarp->mAttachmentPoints.getNextData()) { - F32 cx = sdir.mV[0]; - F32 cy = sdir.mV[1]; - F32 sx, sy; - S32 x = (S32)(cx * (F32)sizex) + sizex; - S32 y = (S32)(cy * (F32)sizey) + sizey; - - if (cx > -1 && cx < 1 && cy > -1 && cy < 1) + if (attachmentp->getIsHUDAttachment()) { - glReadPixels(x-2,y-2,4,4,GL_RGBA,GL_UNSIGNED_BYTE,&color[0]); - - S32 total = 0; - for (S32 i=0;i<64;i++) + LLViewerObject* objectp = attachmentp->getObject(); + if (objectp) { - total += color[i]; - } - total >>= 7; - - sx = (sy = ((float)total/255.0f)) * aspect; - - const F32 fix = -0.1f; + LLDrawable* drawable = objectp->mDrawable; + if (drawable->isDead()) + { + continue; + } - color[32] = (U8)(color[32] * 0.5f + 255 * 0.5f); - color[33] = (U8)(color[33] * 0.5f + 255 * 0.5f); - color[34] = (U8)(color[34] * 0.5f + 255 * 0.5f); + for (S32 j = 0; j < drawable->getNumFaces(); ++j) + { + LLFace* facep = drawable->getFace(j); + if (!facep->getPool()) + { + facep->renderForSelect(prim_mask); + } + } - if (total > 80) - { - color[32+3] = (U8)total; - glBegin(GL_QUADS); - glColor4ubv(&color[32]); - glTexCoord2f(0,0); - glVertex3f(cx-sx,cy-sy+fix,0); - glTexCoord2f(1,0); - glVertex3f(cx+sx,cy-sy+fix,0); - glTexCoord2f(1,1); - glVertex3f(cx+sx,cy+sy+fix,0); - glTexCoord2f(0,1); - glVertex3f(cx-sx,cy+sy+fix,0); - glEnd(); - } + //render child faces + for (U32 k = 0; k < drawable->getChildCount(); ++k) + { + LLDrawable* child = drawable->getChild(k); + for (S32 l = 0; l < child->getNumFaces(); ++l) + { + LLFace* facep = child->getFace(l); + if (!facep->getPool()) + { + facep->renderForSelect(prim_mask); + } + } + } + } } } - } - - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); -} - -void LLPipeline::displayMap() -{ - LLGLSPipelineAlpha gls_pipeline_alpha; - LLGLSNoTexture no_texture; - LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE); - - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - - glTranslatef(-1,-1,0); - glScalef(2,2,0); - - glColor4f(0,0,0,0.5); - glBegin(GL_QUADS); - glVertex3f(0,0,0); - glVertex3f(1,0,0); - glVertex3f(1,1,0); - glVertex3f(0,1,0); - glEnd(); - - static F32 totalW = 1.5f; - static F32 offset = 0.5f; - static F32 scale = 1.0f; - - S32 mousex = gViewerWindow->getCurrentMouseX(); - S32 mousey = gViewerWindow->getCurrentMouseY(); - S32 w = gViewerWindow->getWindowWidth(); - S32 h = gViewerWindow->getWindowHeight(); - - if (mousex < 20 && offset > 0) offset -= (20 - mousex) * 0.02f; - if (mousex > (w - 20)) offset += (20 - (w - mousex)) * 0.02f; - if (offset > (totalW-1)) offset = (totalW-1); - if (mousey < 20 && scale > 0.1) scale -= (20 - mousey) * 0.001f; - if (mousey > (h - 20) && scale < 1.0f) scale += (20 - (h - mousey)) * 0.001f; - - glScalef(scale*scale,scale,1); - glTranslatef(-offset,0,0); - //totalW = mStaticTree->render2D(0,0.8f/scale); - //mDynamicTree->render2D(0,0.4f/scale); - - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); -} - -void LLPipeline::renderForSelect() -{ - LLMemType mt(LLMemType::MTYPE_PIPELINE); - //for each drawpool - - glMatrixMode(GL_MODELVIEW); - - LLGLSDefault gls_default; - LLGLSObjectSelect gls_object_select; - LLGLDepthTest gls_depth(GL_TRUE); - disableLights(); - - glEnableClientState ( GL_VERTEX_ARRAY ); - glDisableClientState( GL_NORMAL_ARRAY ); - glDisableClientState( GL_TEXTURE_COORD_ARRAY ); - -#ifndef LL_RELEASE_FOR_DOWNLOAD - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - LLGLState::checkClientArrays(); - U32 last_type = 0; -#endif - for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter) - { - LLDrawPool *poolp = *iter; - if (poolp->canUseAGP() && usingAGP()) - { - bindAGP(); - } - else - { - //llinfos << "Rendering pool type " << p->getType() << " without AGP!" << llendl; - unbindAGP(); - } - poolp->renderForSelect(); -#ifndef LL_RELEASE_FOR_DOWNLOAD - if (poolp->getType() != last_type) - { - last_type = poolp->getType(); - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - LLGLState::checkClientArrays(); - } -#endif + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); } - // Disable all of the client state - glDisableClientState( GL_VERTEX_ARRAY ); - - if (mAGPMemPool) - { - mAGPMemPool->waitFence(mGlobalFence); - mAGPMemPool->sendFence(mGlobalFence); - } + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glDisableClientState( GL_TEXTURE_COORD_ARRAY ); + + LLVertexBuffer::stopRender(); } void LLPipeline::renderFaceForUVSelect(LLFace* facep) @@ -3305,7 +3209,6 @@ void LLPipeline::rebuildPools() { LLMemType mt(LLMemType::MTYPE_PIPELINE); S32 max_count = mPools.size(); - S32 num_rebuilds = 0; pool_set_t::iterator iter1 = mPools.upper_bound(mLastRebuildPool); while(max_count > 0 && mPools.size() > 0) // && num_rebuilds < MAX_REBUILDS) { @@ -3314,8 +3217,8 @@ void LLPipeline::rebuildPools() iter1 = mPools.begin(); } LLDrawPool* poolp = *iter1; - num_rebuilds += poolp->rebuild(); - if (poolp->mReferences.empty()) + + if (poolp->isDead()) { mPools.erase(iter1++); removeFromQuickLookup( poolp ); @@ -3345,27 +3248,35 @@ void LLPipeline::addToQuickLookup( LLDrawPool* new_poolp ) switch( new_poolp->getType() ) { case LLDrawPool::POOL_SIMPLE: - mSimplePools[ uintptr_t(new_poolp->getTexture()) ] = new_poolp ; + if (mSimplePool) + { + llassert(0); + llwarns << "Ignoring duplicate simple pool." << llendl; + } + else + { + mSimplePool = (LLRenderPass*) new_poolp; + } break; case LLDrawPool::POOL_TREE: mTreePools[ uintptr_t(new_poolp->getTexture()) ] = new_poolp ; break; - - case LLDrawPool::POOL_TREE_NEW: - mTreeNewPools[ uintptr_t(new_poolp->getTexture()) ] = new_poolp ; - break; case LLDrawPool::POOL_TERRAIN: mTerrainPools[ uintptr_t(new_poolp->getTexture()) ] = new_poolp ; break; case LLDrawPool::POOL_BUMP: - mBumpPools[ uintptr_t(new_poolp->getTexture()) ] = new_poolp ; - break; - - case LLDrawPool::POOL_MEDIA: - mMediaPools[ uintptr_t(new_poolp->getTexture()) ] = new_poolp ; + if (mBumpPool) + { + llassert(0); + llwarns << "Ignoring duplicate bump pool." << llendl; + } + else + { + mBumpPool = new_poolp; + } break; case LLDrawPool::POOL_ALPHA: @@ -3380,6 +3291,18 @@ void LLPipeline::addToQuickLookup( LLDrawPool* new_poolp ) } break; + case LLDrawPool::POOL_ALPHA_POST_WATER: + if( mAlphaPoolPostWater ) + { + llassert(0); + llwarns << "LLPipeline::addPool(): Ignoring duplicate Alpha pool" << llendl; + } + else + { + mAlphaPoolPostWater = new_poolp; + } + break; + case LLDrawPool::POOL_AVATAR: break; // Do nothing @@ -3406,19 +3329,7 @@ void LLPipeline::addToQuickLookup( LLDrawPool* new_poolp ) mStarsPool = new_poolp; } break; - - case LLDrawPool::POOL_CLOUDS: - if( mCloudsPool ) - { - llassert(0); - llwarns << "LLPipeline::addPool(): Ignoring duplicate Clouds pool" << llendl; - } - else - { - mCloudsPool = new_poolp; - } - break; - + case LLDrawPool::POOL_WATER: if( mWaterPool ) { @@ -3443,14 +3354,6 @@ void LLPipeline::addToQuickLookup( LLDrawPool* new_poolp ) } break; - case LLDrawPool::POOL_HUD: - if( mHUDPool ) - { - llerrs << "LLPipeline::addPool(): Duplicate HUD Pool!" << llendl; - } - mHUDPool = new_poolp; - break; - default: llassert(0); llwarns << "Invalid Pool Type in LLPipeline::addPool()" << llendl; @@ -3471,14 +3374,8 @@ void LLPipeline::removeFromQuickLookup( LLDrawPool* poolp ) switch( poolp->getType() ) { case LLDrawPool::POOL_SIMPLE: - #ifdef _DEBUG - { - BOOL found = mSimplePools.erase( (uintptr_t)poolp->getTexture() ); - llassert( found ); - } - #else - mSimplePools.erase( (uintptr_t)poolp->getTexture() ); - #endif + llassert(mSimplePool == poolp); + mSimplePool = NULL; break; case LLDrawPool::POOL_TREE: @@ -3492,17 +3389,6 @@ void LLPipeline::removeFromQuickLookup( LLDrawPool* poolp ) #endif break; - case LLDrawPool::POOL_TREE_NEW: - #ifdef _DEBUG - { - BOOL found = mTreeNewPools.erase( (uintptr_t)poolp->getTexture() ); - llassert( found ); - } - #else - mTreeNewPools.erase( (uintptr_t)poolp->getTexture() ); - #endif - break; - case LLDrawPool::POOL_TERRAIN: #ifdef _DEBUG { @@ -3515,32 +3401,20 @@ void LLPipeline::removeFromQuickLookup( LLDrawPool* poolp ) break; case LLDrawPool::POOL_BUMP: - #ifdef _DEBUG - { - BOOL found = mBumpPools.erase( (uintptr_t)poolp->getTexture() ); - llassert( found ); - } - #else - mBumpPools.erase( (uintptr_t)poolp->getTexture() ); - #endif - break; - - case LLDrawPool::POOL_MEDIA: - #ifdef _DEBUG - { - BOOL found = mMediaPools.erase( (uintptr_t)poolp->getTexture() ); - llassert( found ); - } - #else - mMediaPools.erase( (uintptr_t)poolp->getTexture() ); - #endif + llassert( poolp == mBumpPool ); + mBumpPool = NULL; break; - + case LLDrawPool::POOL_ALPHA: llassert( poolp == mAlphaPool ); mAlphaPool = NULL; break; + case LLDrawPool::POOL_ALPHA_POST_WATER: + llassert( poolp == mAlphaPoolPostWater ); + mAlphaPoolPostWater = NULL; + break; + case LLDrawPool::POOL_AVATAR: break; // Do nothing @@ -3554,11 +3428,6 @@ void LLPipeline::removeFromQuickLookup( LLDrawPool* poolp ) mStarsPool = NULL; break; - case LLDrawPool::POOL_CLOUDS: - llassert( poolp == mCloudsPool ); - mCloudsPool = NULL; - break; - case LLDrawPool::POOL_WATER: llassert( poolp == mWaterPool ); mWaterPool = NULL; @@ -3569,11 +3438,6 @@ void LLPipeline::removeFromQuickLookup( LLDrawPool* poolp ) mGroundPool = NULL; break; - case LLDrawPool::POOL_HUD: - llassert( poolp == mHUDPool ); - mHUDPool = NULL; - break; - default: llassert(0); llwarns << "Invalid Pool Type in LLPipeline::removeFromQuickLookup() type=" << poolp->getType() << llendl; @@ -3581,17 +3445,6 @@ void LLPipeline::removeFromQuickLookup( LLDrawPool* poolp ) } } -void LLPipeline::flushAGPMemory() -{ - LLMemType mt(LLMemType::MTYPE_PIPELINE); - - for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter) - { - LLDrawPool *poolp = *iter; - poolp->flushAGP(); - } -} - void LLPipeline::resetDrawOrders() { // Iterate through all of the draw pools and rebuild them. @@ -3602,346 +3455,6 @@ void LLPipeline::resetDrawOrders() } } -//------------------------------- - - -LLViewerObject *LLPipeline::nearestObjectAt(F32 yaw, F32 pitch) -{ - // Stub to find nearest Object at given yaw and pitch - - /* - LLEdge *vd = NULL; - - if (vd) - { - return (LLViewerObject*)vd->mDrawablep->getVObj(); - } - */ - - return NULL; -} - -void LLPipeline::printPools() -{ - /* - // Iterate through all of the draw pools and rebuild them. - for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter) - { - LLDrawPool *poolp = *iter; - if (pool->mTexturep[0]) - { - llinfos << "Op pool " << pool->mTexturep[0]->mID << llendflush; - } - else - { - llinfos << "Opaque pool NULL" << llendflush; - } - llinfos << " Vertices: \t" << pool->getVertexCount() << llendl; - } - - - for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter) - { - LLDrawPool *poolp = *iter; - llinfos << "Al pool " << pool; - llcont << " Vertices: \t" << pool->getVertexCount() << llendl; - } - - pool = mHighlightPools.getFirst(); - llinfos << "Si pool " << pool; - llcont << " Vertices: \t" << pool->getVertexCount() << llendl; - */ -} - - -void LLPipeline::displayPools() -{ - // Needs to be fixed to handle chained pools - djs - LLUI::setLineWidth(1.0); - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - - LLGLSPipelineAlpha gls_pipeline_alpha; - LLGLSNoTexture no_texture; - LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE); - - glScalef(2,2,1); - glTranslatef(-0.5f,-0.5f,0); - - F32 x = 0.0f, y = 0.05f; - F32 xs = 0.01f, ys = 0.01f; - F32 xs2 = xs*0.1f, ys2 = ys * 0.1f; - - for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter) - { - LLGLSTexture gls_texture; - LLDrawPool *poolp = *iter; - if (poolp->getDebugTexture()) - { - poolp->getDebugTexture()->bind(); - glColor4f(1,1,1,1); - stamp(x,y,xs*4,ys*4); - } - - LLGLSNoTexture no_texture; - - F32 a = 1.f - (F32)poolp->mRebuildTime / (F32)poolp->mRebuildFreq; - glColor4f(a,a,a,1); - stamp(x,y,xs,ys); - - x = (xs + xs2) * 4.0f; - - F32 h = ys * 0.5f; - - S32 total = 0; - - for (std::vector<LLFace*>::iterator iter = poolp->mReferences.begin(); - iter != poolp->mReferences.end(); iter++) - { - LLFace *face = *iter; - F32 w = xs; - - if (!face || !face->getDrawable()) - { - w = 16 / 3000.0f; - - stamp(x,y,w,h); - - if (x+w > 0.95f) - { - x = (xs + xs2) * 4.0f; - y += h + ys2; - } - else - { - if (w) x += w + xs2; - } - - continue; - } - - if (face->getDrawable()->isVisible()) - { - if (face->isState(LLFace::BACKLIST)) - { - glColor4f(1,0,1,1); - } - else if (total > poolp->getMaxVertices()) - { - glColor4f(1,0,0,1); - } - else - { - glColor4f(0,1,0,1); - total += face->getGeomCount(); - } - } - else - { - if (face->isState(LLFace::BACKLIST)) - { - glColor4f(0,0,1,1); - } - else - { - glColor4f(1,1,0,1); - } - } - - w = face->getGeomCount() / 3000.0f; - - stamp(x,y,w,h); - - if (x+w > 0.95f) - { - x = (xs + xs2) * 4.0f; - y += h + ys2; - } - else - { - if (w) x += w + xs2; - } - } - - y += ys + ys2; - x = 0; - } - - glPopMatrix(); - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); -} - -static F32 xs = 0.01f, ys = 0.01f; -static F32 xs2 = xs*0.1f, ys2 = ys * 0.1f; -static F32 winx, winy; - -void displayDrawable(F32 &x, F32 &y, LLDrawable *drawable, F32 alpha = 0.5f) -{ - F32 w = 0; - F32 h = ys * 0.5f; - - if (drawable && !drawable->isDead()) - { - for (S32 f=0;f < drawable->getNumFaces(); f++) - { - w += drawable->getFace(f)->getGeomCount() / 30000.0f; - } - w+=xs; - glColor4f(1,1,0, alpha); - } - else - { - w = 0.01f; - glColor4f(0,0,0,alpha); - } - -// const LLFontGL* font = gResMgr->getRes( LLFONT_SANSSERIF_SMALL ); - -// U8 pcode = drawable->getVObj()->getPCode(); - - //char *string = (char*)LLPrimitive::pCodeToString(pcode); - //if (pcode == 0x3e) string = "terrain"; - //else if (pcode == 0x2e) string = "cloud"; - //string[3] = 0; - - stamp(x * winx,y * winy,w * winx,h * winy); - - /* - glColor4f(0,0,0,1); - font->render(string,x*winx+1,y*winy+1); - LLGLSNoTexture no_texture; - */ - - if (x+w > 0.95f) - { - x = (xs + xs2) * 4.0f; - y += h + ys2; - } - else - { - if (w) x += w + xs2; - } - -} - -#if 0 // No longer up date - -void displayQueue(F32 &x, F32 &y, LLDynamicArray<LLDrawable*>& processed, LLDynamicQueuePtr<LLPointer<LLDrawable> >& remaining) -{ - S32 i; - for (i=0;i<processed.count();i++) - { - displayDrawable(x,y,processed[i],1); - } - - x += xs * 2; - - S32 count = remaining.count(); - for (i=0;i<count;i++) - { - LLDrawable* drawablep = remaining[(i + remaining.getFirst()) % remaining.getMax()]; - if (drawablep && !drawablep->isDead()) - { - displayDrawable(x,y,drawable,0.5); - } - } - - y += ys * 4; - x = (xs + xs2) * 4.0f; - -} - -void LLPipeline::displayQueues() -{ - LLUI::setLineWidth(1.0); - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - - LLGLSPipelineAlpha gls_pipeline_alpha; - LLGLSNoTexture no_texture; - LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE); - - glScalef(2,2,1); - glTranslatef(-0.5f,-0.5f,0); - - winx = (F32)gViewerWindow->getWindowWidth(); - winy = (F32)gViewerWindow->getWindowHeight(); - - glScalef(1.0f/winx,1.0f/winy,1); - - F32 x = (xs + xs2) * 4.0f; - F32 y = 0.1f; - - const LLFontGL* font = gResMgr->getRes( LLFONT_SANSSERIF ); - - font->renderUTF8("Build1", 0,0,(S32)(y*winy),LLColor4(1,1,1,1)); - displayQueue(x,y, gBuildProcessed, mBuildQ1); - - glPopMatrix(); - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - -} - -#endif - -// static -void render_bbox(const LLVector3 &min, const LLVector3 &max) -{ - S32 i; - LLVector3 verticesp[16]; - - verticesp[0].setVec(min.mV[0],min.mV[1],max.mV[2]); - verticesp[1].setVec(min.mV[0],min.mV[1],min.mV[2]); - verticesp[2].setVec(min.mV[0],max.mV[1],min.mV[2]); - verticesp[3].setVec(min.mV[0],max.mV[1],max.mV[2]); - verticesp[4].setVec(max.mV[0],max.mV[1],max.mV[2]); - verticesp[5].setVec(max.mV[0],max.mV[1],min.mV[2]); - verticesp[6].setVec(max.mV[0],min.mV[1],min.mV[2]); - verticesp[7].setVec(max.mV[0],min.mV[1],max.mV[2]); - verticesp[8 ] = verticesp[0]; - verticesp[9 ] = verticesp[1]; - verticesp[10] = verticesp[6]; - verticesp[11] = verticesp[7]; - verticesp[12] = verticesp[4]; - verticesp[13] = verticesp[5]; - verticesp[14] = verticesp[2]; - verticesp[15] = verticesp[3]; - - LLGLSNoTexture gls_no_texture; - { - LLUI::setLineWidth(1.f); - glBegin(GL_LINE_LOOP); - for (i = 0; i < 16; i++) - { - glVertex3fv(verticesp[i].mV); - } - glEnd(); - } - { - LLGLDepthTest gls_depth(GL_TRUE); - LLUI::setLineWidth(3.0f); - glBegin(GL_LINE_LOOP); - for (i = 0; i < 16; i++) - { - glVertex3fv(verticesp[i].mV); - } - glEnd(); - } - LLUI::setLineWidth(1.0f); -} - //============================================================================ // Once-per-frame setup of hardware lights, // including sun/moon, avatar backlight, and up to 6 local lights @@ -4153,8 +3666,6 @@ void LLPipeline::setupHWLights(LLDrawPool* pool) { const LLColor4 black(0,0,0,1); - setLightingDetail(-1); // update - // Ambient LLColor4 ambient = gSky.getTotalAmbientColor(); glLightModelfv(GL_LIGHT_MODEL_AMBIENT,ambient.mV); @@ -4410,16 +3921,6 @@ class LLVOBranch; class LLVOLeaf; class Foo; -template<> char* LLAGPArray<U8>::sTypeName = "U8 [AGP]"; -template<> char* LLAGPArray<U32>::sTypeName = "U32 [AGP]"; -template<> char* LLAGPArray<F32>::sTypeName = "F32 [AGP]"; -template<> char* LLAGPArray<LLColor4>::sTypeName = "LLColor4 [AGP]"; -template<> char* LLAGPArray<LLColor4U>::sTypeName = "LLColor4U [AGP]"; -template<> char* LLAGPArray<LLVector4>::sTypeName = "LLVector4 [AGP]"; -template<> char* LLAGPArray<LLVector3>::sTypeName = "LLVector3 [AGP]"; -template<> char* LLAGPArray<LLVector2>::sTypeName = "LLVector2 [AGP]"; -template<> char* LLAGPArray<LLFace*>::sTypeName = "LLFace* [AGP]"; - void scale_stamp(const F32 x, const F32 y, const F32 xs, const F32 ys) { stamp(0.25f + 0.5f*x, @@ -4461,221 +3962,6 @@ void drawBars(const F32 begin, const F32 end, const F32 height = 1.f) } } -void LLPipeline::displayAGP() -{ - LLUI::setLineWidth(1.0); - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - - LLGLSPipelineAlpha gls_alpha; - LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE); - - LLImageGL::unbindTexture(0, GL_TEXTURE_2D); - glScalef(2,2,1); - glTranslatef(-0.5f,-0.5f,0); - - glColor4f(0,0,0,0.5f); - scale_stamp(0,0,1,1); - - F32 x = 0.0f, y = 0.05f; - F32 xs = 0.015f, ys = 0.015f; - F32 xs2 = xs*0.1f, ys2 = ys * 0.1f; - F32 w = xs+xs2, h = ys + ys2; - S32 i=0; - - F32 agp_size = 1.f; - if (mAGPMemPool) - { - agp_size = (F32)mAGPMemPool->getSize(); - } - - x = (xs + xs2) * 4.0f; - - static float c = 0.0f; - c += 0.0001f; - - LLAGPMemBlock *blockp = mBufferMemory[mBufferIndex]->getAGPMemBlock(); - - pool_set_t::iterator iter = mPools.begin(); - LLDrawPool *poolp = *iter; - - // Dump the shared AGP buffer - if (blockp) - { - F32 begin = blockp->getOffset()/agp_size; - F32 end = begin + (blockp->getSize()/agp_size); - F32 used = begin + (poolp->mMemory.count()/agp_size); - - LLViewerImage::bindTexture(NULL); - glColor4f(0.5f, 0.5f, 0.5f, 0.5f); - drawBars(begin,end); - - LLViewerImage::bindTexture(NULL); - glColor4f(0.5f, 0.5f, 0.5f, 0.5f); - drawBars(begin,end); - - LLViewerImage::bindTexture(NULL); - glColor4f(0.5f, 0.5f, 0.5f, 0.5f); - drawBars(begin,used, 0.5f); - - glColor4f(0.5f, 0.5f, 0.5f, 0.5f); - drawBars(begin,end, 0.25f); - } - - S32 used_bytes = 0; - S32 total_bytes = 0; - while (iter != mPools.end()) - { - poolp = *iter++; - - BOOL synced = FALSE; - i++; - total_bytes += poolp->mMemory.getMax(); - used_bytes += poolp->mMemory.count(); - LLViewerImage *texturep = poolp->getDebugTexture(); - - - if (poolp->mMemory.mSynced) - { - poolp->mMemory.mSynced = FALSE; - synced = TRUE; - } - - LLAGPMemBlock *blockp = poolp->mMemory.getAGPMemBlock(); - if (blockp) - { - F32 begin = blockp->getOffset()/agp_size; - F32 end = begin + (blockp->getSize()/agp_size); - F32 used = begin + (poolp->mMemory.count()/agp_size); - - LLViewerImage::bindTexture(NULL); - glColor4f(1.f, 0.5f, 0.5f, 0.5f); - drawBars(begin,end); - - LLViewerImage::bindTexture(texturep); - glColor4f(1.f, 0.75f, 0.75f, 0.5f); - drawBars(begin,end); - - LLViewerImage::bindTexture(NULL); - glColor4f(1.f, 0.75f, 0.75f, 1.f); - drawBars(begin,used, 0.5f); - - glColor3fv(poolp->getDebugColor().mV); - drawBars(begin,end, 0.25f); - - if (synced) - { - LLViewerImage::bindTexture(NULL); - glColor4f(1.f, 1.f, 1.f, 0.4f); - drawBars(begin,end); - } - } - - synced = FALSE; - if (poolp->mWeights.mSynced) - { - poolp->mWeights.mSynced = FALSE; - synced = TRUE; - } - blockp = poolp->mWeights.getAGPMemBlock(); - if (blockp) - { - F32 begin = blockp->getOffset()/agp_size; - F32 end = begin + (blockp->getSize()/agp_size); - F32 used = begin + (poolp->mWeights.count()*sizeof(float)/agp_size); - - LLViewerImage::bindTexture(NULL); - glColor4f(0.0f, 0.f, 0.75f, 0.5f); - drawBars(begin,end); - - LLViewerImage::bindTexture(texturep); - glColor4f(0.0, 0.f, 0.75f, 0.5f); - drawBars(begin,end); - - LLViewerImage::bindTexture(NULL); - glColor4f(0.0, 0.f, 0.75f, 1.f); - drawBars(begin,used, 0.5f); - - LLViewerImage::bindTexture(NULL); - glColor3fv(poolp->getDebugColor().mV); - drawBars(begin,end, 0.25f); - - if (synced) - { - LLViewerImage::bindTexture(NULL); - glColor4f(1.f, 1.f, 1.f, 0.4f); - drawBars(begin,end); - } - } - - synced = FALSE; - if (poolp->mClothingWeights.mSynced) - { - poolp->mClothingWeights.mSynced = FALSE; - synced = TRUE; - } - blockp = poolp->mClothingWeights.getAGPMemBlock(); - if (blockp) - { - F32 begin = blockp->getOffset()/agp_size; - F32 end = begin + (blockp->getSize()/agp_size); - F32 used = begin + (poolp->mClothingWeights.count()*sizeof(LLVector4)/agp_size); - - LLViewerImage::bindTexture(NULL); - glColor4f(0.75f, 0.f, 0.75f, 0.5f); - drawBars(begin,end); - - LLViewerImage::bindTexture(texturep); - glColor4f(0.75f, 0.f, 0.75f, 0.5f); - drawBars(begin,end); - - LLViewerImage::bindTexture(NULL); - glColor4f(0.75f, 0.f, 0.75f, 0.5f); - drawBars(begin,used, 0.5f); - - LLViewerImage::bindTexture(NULL); - glColor3fv(poolp->getDebugColor().mV); - drawBars(begin,end, 0.25f); - - if (synced) - { - LLViewerImage::bindTexture(NULL); - glColor4f(1.f, 1.f, 1.f, 0.5f); - drawBars(begin,end); - } - } - - // - // Stamps on bottom of screen - // - LLViewerImage::bindTexture(texturep); - glColor4f(1.f, 1.f, 1.f, 1.f); - stamp(x,y,xs,ys); - - LLViewerImage::bindTexture(NULL); - glColor3fv(poolp->getDebugColor().mV); - stamp(x,y,xs, ys*0.25f); - if (x+w > 0.95f) - { - x = (xs + xs2) * 4.0f; - y += h; - } - else - { - x += w + xs2; - } - } - - glPopMatrix(); - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); -} - void LLPipeline::findReferences(LLDrawable *drawablep) { if (std::find(mVisibleList.begin(), mVisibleList.end(), drawablep) != mVisibleList.end()) @@ -4686,7 +3972,7 @@ void LLPipeline::findReferences(LLDrawable *drawablep) { llinfos << "In mLights" << llendl; } - if (mMovedList.find(drawablep) != mMovedList.end()) + if (std::find(mMovedList.begin(), mMovedList.end(), drawablep) != mMovedList.end()) { llinfos << "In mMovedList" << llendl; } @@ -4698,18 +3984,14 @@ void LLPipeline::findReferences(LLDrawable *drawablep) { llinfos << "In mRetexturedList" << llendl; } - if (mRematerialedList.find(drawablep) != mRematerialedList.end()) - { - llinfos << "In mRematerialedList" << llendl; - } - + if (mActiveQ.find(drawablep) != mActiveQ.end()) { llinfos << "In mActiveQ" << llendl; } - if (mBuildQ1.find(drawablep) != mBuildQ1.end()) + if (std::find(mBuildQ1.begin(), mBuildQ1.end(), drawablep) != mBuildQ1.end()) { - llinfos << "In mBuildQ2" << llendl; + llinfos << "In mBuildQ1" << llendl; } if (std::find(mBuildQ2.begin(), mBuildQ2.end(), drawablep) != mBuildQ2.end()) { @@ -4717,19 +3999,7 @@ void LLPipeline::findReferences(LLDrawable *drawablep) } S32 count; - /* - count = mStaticTree->count(drawablep); - if (count) - { - llinfos << "In mStaticTree: " << count << " references" << llendl; - } - - count = mDynamicTree->count(drawablep); - if (count) - { - llinfos << "In mStaticTree: " << count << " references" << llendl; - } - */ + count = gObjectList.findReferences(drawablep); if (count) { @@ -4756,53 +4026,6 @@ BOOL LLPipeline::verify() return ok; } -S32 LLPipeline::getAGPMemUsage() -{ - if (mAGPMemPool) - { - return mAGPMemPool->getSize(); - } - else - { - return 0; - } -} - -S32 LLPipeline::getMemUsage(const BOOL print) -{ - S32 mem_usage = 0; - - if (mAGPMemPool) - { - S32 agp_usage = 0; - agp_usage = mAGPMemPool->getSize(); - if (print) - { - llinfos << "AGP Mem: " << agp_usage << llendl; - llinfos << "AGP Mem used: " << mAGPMemPool->getTotalAllocated() << llendl; - } - mem_usage += agp_usage; - } - - - S32 pool_usage = 0; - for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter) - { - LLDrawPool *poolp = *iter; - pool_usage += poolp->getMemUsage(print); - } - - if (print) - { - llinfos << "Pool Mem: " << pool_usage << llendl; - } - - mem_usage += pool_usage; - - return mem_usage; - -} - ////////////////////////////// // // Collision detection @@ -4913,8 +4136,8 @@ void LLPipeline::setLight(LLDrawable *drawablep, BOOL is_light) } else { - mLights.erase(drawablep); drawablep->clearState(LLDrawable::LIGHT); + mLights.erase(drawablep); } markRelight(drawablep); } @@ -4933,9 +4156,16 @@ void LLPipeline::setActive(LLDrawable *drawablep, BOOL active) } //static -void LLPipeline::toggleRenderType(void* data) +void LLPipeline::toggleRenderType(U32 type) { - S32 type = (S32)(intptr_t)data; + U32 bit = (1<<type); + gPipeline.mRenderTypeMask ^= bit; +} + +//static +void LLPipeline::toggleRenderTypeControl(void* data) +{ + U32 type = (U32)(intptr_t)data; U32 bit = (1<<type); if (gPipeline.hasRenderType(type)) { @@ -4945,13 +4175,13 @@ void LLPipeline::toggleRenderType(void* data) { llinfos << "Toggling render type mask " << std::hex << bit << " on" << std::dec << llendl; } - gPipeline.mRenderTypeMask ^= bit; + gPipeline.toggleRenderType(type); } //static -BOOL LLPipeline::toggleRenderTypeControl(void* data) +BOOL LLPipeline::hasRenderTypeControl(void* data) { - S32 type = (S32)(intptr_t)data; + U32 type = (U32)(intptr_t)data; return gPipeline.hasRenderType(type); } @@ -4990,14 +4220,6 @@ BOOL LLPipeline::toggleRenderDebugControl(void* data) void LLPipeline::toggleRenderDebugFeature(void* data) { U32 bit = (U32)(intptr_t)data; - if (gPipeline.hasRenderDebugFeatureMask(bit)) - { - llinfos << "Toggling render debug feature mask " << std::hex << bit << " off" << std::dec << llendl; - } - else - { - llinfos << "Toggling render debug feature mask " << std::hex << bit << " on" << std::dec << llendl; - } gPipeline.mRenderDebugFeatureMask ^= bit; } @@ -5310,8 +4532,375 @@ void LLGLSLShader::vertexAttrib4fv(U32 index, GLfloat* v) LLViewerObject* LLPipeline::pickObject(const LLVector3 &start, const LLVector3 &end, LLVector3 &collision) { - LLDrawable* drawable = mObjectPartition->pickDrawable(start, end, collision); + LLDrawable* drawable = mObjectPartition[PARTITION_VOLUME]->pickDrawable(start, end, collision); return drawable ? drawable->getVObj() : NULL; } +LLSpatialPartition* LLPipeline::getSpatialPartition(LLViewerObject* vobj) +{ + if (vobj) + { + return getSpatialPartition(vobj->getPartitionType()); + } + return NULL; +} + +LLSpatialPartition* LLPipeline::getSpatialPartition(U32 type) +{ + if (type < mObjectPartition.size()) + { + return mObjectPartition[type]; + } + return NULL; +} + +void LLPipeline::clearRenderMap() +{ + for (U32 i = 0; i < LLRenderPass::NUM_RENDER_TYPES; i++) + { + mRenderMap[i].clear(); + } +} + + +void LLPipeline::resetVertexBuffers(LLDrawable* drawable) +{ + for (S32 i = 0; i < drawable->getNumFaces(); i++) + { + LLFace* facep = drawable->getFace(i); + facep->mVertexBuffer = NULL; + facep->mLastVertexBuffer = NULL; + } +} + +void LLPipeline::resetVertexBuffers() +{ + for (U32 i = 0; i < mObjectPartition.size(); ++i) + { + if (mObjectPartition[i]) + { + mObjectPartition[i]->resetVertexBuffers(); + } + } + + resetDrawOrders(); + + if (gSky.mVOSkyp.notNull()) + { + resetVertexBuffers(gSky.mVOSkyp->mDrawable); + resetVertexBuffers(gSky.mVOGroundp->mDrawable); + resetVertexBuffers(gSky.mVOStarsp->mDrawable); + markRebuild(gSky.mVOSkyp->mDrawable, LLDrawable::REBUILD_ALL, TRUE); + markRebuild(gSky.mVOGroundp->mDrawable, LLDrawable::REBUILD_ALL, TRUE); + markRebuild(gSky.mVOStarsp->mDrawable, LLDrawable::REBUILD_ALL, TRUE); + } + + if (LLVertexBuffer::sGLCount > 0) + { + LLVertexBuffer::cleanupClass(); + } +} + +void LLPipeline::renderObjects(U32 type, U32 mask, BOOL texture) +{ + mSimplePool->renderStatic(type, mask, texture); + mSimplePool->renderActive(type, mask, texture); +} + +void LLPipeline::setUseVBO(BOOL use_vbo) +{ + if (use_vbo != LLVertexBuffer::sEnableVBOs) + { + if (use_vbo) + { + llinfos << "Enabling VBO." << llendl; + } + else + { + llinfos << "Disabling VBO." << llendl; + } + + resetVertexBuffers(); + LLVertexBuffer::initClass(use_vbo); + } +} + +void apply_cube_face_rotation(U32 face) +{ + switch (face) + { + case 0: + glRotatef(90.f, 0, 1, 0); + glRotatef(180.f, 1, 0, 0); + break; + case 2: + glRotatef(-90.f, 1, 0, 0); + break; + case 4: + glRotatef(180.f, 0, 1, 0); + glRotatef(180.f, 0, 0, 1); + break; + case 1: + glRotatef(-90.f, 0, 1, 0); + glRotatef(180.f, 1, 0, 0); + break; + case 3: + glRotatef(90, 1, 0, 0); + break; + case 5: + glRotatef(180, 0, 0, 1); + break; + } +} +void LLPipeline::generateReflectionMap(LLCubeMap* cube_map, LLCamera& cube_cam, GLsizei res) +{ + //render dynamic cube map + U32 type_mask = gPipeline.getRenderTypeMask(); + BOOL use_occlusion = LLPipeline::sUseOcclusion; + LLPipeline::sUseOcclusion = FALSE; + LLPipeline::sSkipUpdate = TRUE; + static GLuint blur_tex = 0; + if (!blur_tex) + { + glGenTextures(1, &blur_tex); + } + + BOOL toggle_ui = gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI); + if (toggle_ui) + { + gPipeline.toggleRenderDebugFeature((void*) LLPipeline::RENDER_DEBUG_FEATURE_UI); + } + + U32 cube_mask = (1 << LLPipeline::RENDER_TYPE_SIMPLE) | + (1 << LLPipeline::RENDER_TYPE_WATER) | + (1 << LLPipeline::RENDER_TYPE_BUMP) | + (1 << LLPipeline::RENDER_TYPE_ALPHA) | + (1 << LLPipeline::RENDER_TYPE_TREE) | + (1 << LLDrawPool::POOL_ALPHA_POST_WATER) | + //(1 << LLPipeline::RENDER_TYPE_PARTICLES) | + (1 << LLPipeline::RENDER_TYPE_CLOUDS) | + //(1 << LLPipeline::RENDER_TYPE_STARS) | + //(1 << LLPipeline::RENDER_TYPE_AVATAR) | + (1 << LLPipeline::RENDER_TYPE_GRASS) | + (1 << LLPipeline::RENDER_TYPE_VOLUME) | + (1 << LLPipeline::RENDER_TYPE_TERRAIN) | + (1 << LLPipeline::RENDER_TYPE_SKY) | + (1 << LLPipeline::RENDER_TYPE_GROUND); + LLDrawPoolWater::sSkipScreenCopy = TRUE; + cube_mask = cube_mask & type_mask; + gPipeline.setRenderTypeMask(cube_mask); + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + + glViewport(0,0,res,res); + + glClearColor(0,0,0,0); + + U32 cube_face[] = + { + GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB, + GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB, + GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB, + GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB, + GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB, + GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB, + }; + + LLVector3 origin = cube_cam.getOrigin(); + + gPipeline.calcNearbyLights(); + + for (S32 i = 0; i < 6; i++) + { + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(90.f, 1.f, 0.1f, 1024.f); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + apply_cube_face_rotation(i); + + + glTranslatef(-origin.mV[0], -origin.mV[1], -origin.mV[2]); + cube_cam.setOrigin(origin); + LLViewerCamera::updateFrustumPlanes(cube_cam); + cube_cam.setOrigin(gCamera->getOrigin()); + gPipeline.updateCull(cube_cam); + gPipeline.stateSort(cube_cam); + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + gPipeline.renderGeom(cube_cam); + + cube_map->enable(0); + cube_map->bind(); + glCopyTexImage2D(cube_face[i], 0, GL_RGB, 0, 0, res, res, 0); + cube_map->disable(); + } + + cube_cam.setOrigin(origin); + gPipeline.resetDrawOrders(); + gPipeline.mShinyOrigin.setVec(cube_cam.getOrigin(), cube_cam.getFar()*2.f); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + + gPipeline.setRenderTypeMask(type_mask); + LLPipeline::sUseOcclusion = use_occlusion; + LLPipeline::sSkipUpdate = FALSE; + + if (toggle_ui) + { + gPipeline.toggleRenderDebugFeature((void*)LLPipeline::RENDER_DEBUG_FEATURE_UI); + } + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + LLDrawPoolWater::sSkipScreenCopy = FALSE; +} + +//send cube map vertices and texture coordinates +void render_cube_map() +{ + if (gPipeline.mCubeList == 0) + { + gPipeline.mCubeList = glGenLists(1); + glNewList(gPipeline.mCubeList, GL_COMPILE); + + U32 idx[36]; + + idx[0] = 1; idx[1] = 0; idx[2] = 2; //front + idx[3] = 3; idx[4] = 2; idx[5] = 0; + + idx[6] = 4; idx[7] = 5; idx[8] = 1; //top + idx[9] = 0; idx[10] = 1; idx[11] = 5; + + idx[12] = 5; idx[13] = 4; idx[14] = 6; //back + idx[15] = 7; idx[16] = 6; idx[17] = 4; + + idx[18] = 6; idx[19] = 7; idx[20] = 3; //bottom + idx[21] = 2; idx[22] = 3; idx[23] = 7; + + idx[24] = 0; idx[25] = 5; idx[26] = 3; //left + idx[27] = 6; idx[28] = 3; idx[29] = 5; + + idx[30] = 4; idx[31] = 1; idx[32] = 7; //right + idx[33] = 2; idx[34] = 7; idx[35] = 1; + + LLVector3 vert[8]; + LLVector3 r = LLVector3(1,1,1); + + vert[0] = r.scaledVec(LLVector3(-1,1,1)); // 0 - left top front + vert[1] = r.scaledVec(LLVector3(1,1,1)); // 1 - right top front + vert[2] = r.scaledVec(LLVector3(1,-1,1)); // 2 - right bottom front + vert[3] = r.scaledVec(LLVector3(-1,-1,1)); // 3 - left bottom front + + vert[4] = r.scaledVec(LLVector3(1,1,-1)); // 4 - left top back + vert[5] = r.scaledVec(LLVector3(-1,1,-1)); // 5 - right top back + vert[6] = r.scaledVec(LLVector3(-1,-1,-1)); // 6 - right bottom back + vert[7] = r.scaledVec(LLVector3(1,-1,-1)); // 7 -left bottom back + + glBegin(GL_TRIANGLES); + for (U32 i = 0; i < 36; i++) + { + glTexCoord3fv(vert[idx[i]].mV); + glVertex3fv(vert[idx[i]].mV); + } + glEnd(); + + glEndList(); + } + + glCallList(gPipeline.mCubeList); + +} + +void LLPipeline::blurReflectionMap(LLCubeMap* cube_in, LLCubeMap* cube_out, U32 res) +{ + LLGLEnable cube(GL_TEXTURE_CUBE_MAP_ARB); + LLGLDepthTest depth(GL_FALSE); + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + gluPerspective(90.f+45.f/res, 1.f, 0.1f, 1024.f); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + + glViewport(0, 0, res, res); + LLGLEnable blend(GL_BLEND); + + S32 kernel = 2; + F32 step = 90.f/res; + F32 alpha = 1.f/((kernel*2+1)); + + glColor4f(1,1,1,alpha); + + S32 x = 0; + + U32 cube_face[] = + { + GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB, + GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB, + GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB, + GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB, + GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB, + GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB, + }; + + LLVector3 axis[] = + { + LLVector3(1,0,0), + LLVector3(0,1,0), + LLVector3(0,0,1) + }; + + + glBlendFunc(GL_SRC_ALPHA_SATURATE, GL_ONE); + //3-axis blur + for (U32 j = 0; j < 3; j++) + { + glViewport(0,0,res, res*6); + glClear(GL_COLOR_BUFFER_BIT); + if (j == 0) + { + cube_in->bind(); + } + + for (U32 i = 0; i < 6; i++) + { + glViewport(0,i*res, res, res); + glLoadIdentity(); + apply_cube_face_rotation(i); + for (x = -kernel; x <= kernel; ++x) + { + glPushMatrix(); + glRotatef(x*step, axis[j].mV[0], axis[j].mV[1], axis[j].mV[2]); + render_cube_map(); + glPopMatrix(); + } + } + + //readback + if (j == 0) + { + cube_out->bind(); + } + for (U32 i = 0; i < 6; i++) + { + glCopyTexImage2D(cube_face[i], 0, GL_RGB, 0, i*res, res, res, 0); + } + } + + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +} + + diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index f4144b6afa..af772fd60d 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -9,7 +9,6 @@ #ifndef LL_PIPELINE_H #define LL_PIPELINE_H -#include "llagparray.h" #include "lldarrayptr.h" #include "lldqueueptr.h" #include "llstat.h" @@ -31,8 +30,7 @@ class LLAgent; class LLDisplayPrimitive; class LLTextureEntry; class LLRenderFunc; -class LLAGPMemPool; -class LLAGPMemBlock; +class LLCubeMap; typedef enum e_avatar_skinning_method { @@ -43,6 +41,7 @@ typedef enum e_avatar_skinning_method BOOL compute_min_max(LLMatrix4& box, LLVector2& min, LLVector2& max); // Shouldn't be defined here! bool LLRayAABB(const LLVector3 ¢er, const LLVector3 &size, const LLVector3& origin, const LLVector3& dir, LLVector3 &coord, F32 epsilon = 0); BOOL LLLineSegmentAABB(const LLVector3& start, const LLVector3& end, const LLVector3& center, const LLVector3& size); +BOOL setup_hud_matrices(BOOL for_select); class LLGLSLShader { @@ -72,7 +71,6 @@ public: void bind(); void unbind(); - GLhandleARB mProgramObject; std::vector<GLint> mAttribute; std::vector<GLint> mUniform; @@ -88,6 +86,11 @@ public: void destroyGL(); void restoreGL(); + void resetVertexBuffers(); + void resetVertexBuffers(LLDrawable* drawable); + void setUseVBO(BOOL use_vbo); + void generateReflectionMap(LLCubeMap* cube_map, LLCamera& camera, GLsizei res); + void blurReflectionMap(LLCubeMap* cube_in, LLCubeMap* cube_out, U32 res); void init(); void cleanup(); @@ -102,6 +105,7 @@ public: /// @brief Figures out draw pool type from texture entry. Creates pool if necessary. static LLDrawPool* getPoolFromTE(const LLTextureEntry* te, LLViewerImage* te_image); + static U32 getPoolTypeFromTE(const LLTextureEntry* te, LLViewerImage* imagep); void addPool(LLDrawPool *poolp); // Only to be used by LLDrawPool classes for splitting pools! void removePool( LLDrawPool* poolp ); @@ -111,28 +115,26 @@ public: void unlinkDrawable(LLDrawable*); // Object related methods - void markVisible(LLDrawable *drawablep); - void doOcclusion(); - void markNotCulled(LLDrawable* drawablep, LLCamera& camera); + void markVisible(LLDrawable *drawablep, LLCamera& camera); + void doOcclusion(LLCamera& camera); + void markNotCulled(LLSpatialGroup* group, LLCamera &camera, BOOL active = FALSE); void markMoved(LLDrawable *drawablep, BOOL damped_motion = FALSE); void markShift(LLDrawable *drawablep); void markTextured(LLDrawable *drawablep); - void markMaterialed(LLDrawable *drawablep); void markRebuild(LLDrawable *drawablep, LLDrawable::EDrawableFlags flag = LLDrawable::REBUILD_ALL, BOOL priority = FALSE); + void markRebuild(LLSpatialGroup* groupp); void markRelight(LLDrawable *drawablep, const BOOL now = FALSE); //get the object between start and end that's closest to start. Return the point of collision in collision. LLViewerObject* pickObject(const LLVector3 &start, const LLVector3 &end, LLVector3 &collision); - - void dirtyPoolObjectTextures(const LLViewerImage *texture); // Something about this texture has changed. Dirty it. + + // Something about these textures has changed. Dirty them. + void dirtyPoolObjectTextures(const std::set<LLViewerImage*>& textures); void resetDrawOrders(); U32 addObject(LLViewerObject *obj); - BOOL usingAGP() const; - void setUseAGP(const BOOL use_agp); // Attempt to use AGP; - void enableShadows(const BOOL enable_shadows); // void setLocalLighting(const BOOL local_lighting); @@ -155,61 +157,43 @@ public: BOOL validateProgramObject(GLhandleARB obj); GLhandleARB loadShader(const LLString& filename, S32 cls, GLenum type); - void setUseOcclusionCulling(BOOL b) { mUseOcclusionCulling = b; } - BOOL getUseOcclusionCulling() const { return mUseOcclusionCulling; } - - BOOL initAGP(); - void cleanupAGP(); - LLAGPMemBlock *allocAGPFromPool(const S32 bytes, const U32 target); // Static flag is ignored for now. - void flushAGPMemory(); // Clear all AGP memory blocks (to pack & reduce fragmentation) - // phases void resetFrameStats(); void updateMoveDampedAsync(LLDrawable* drawablep); void updateMoveNormalAsync(LLDrawable* drawablep); + void updateMovedList(LLDrawable::drawable_vector_t& move_list); void updateMove(); - void updateCull(); + void updateCull(LLCamera& camera); void updateGeom(F32 max_dtime); - void stateSort(); + //calculate pixel area of given box from vantage point of given camera + static F32 calcPixelArea(LLVector3 center, LLVector3 size, LLCamera& camera); - void renderGeom(); + void stateSort(LLCamera& camera); + void stateSort(LLSpatialGroup* group, LLCamera& camera); + void stateSort(LLSpatialBridge* bridge, LLCamera& camera); + void stateSort(LLDrawable* drawablep, LLCamera& camera); + void postSort(LLCamera& camera); + void forAllDrawables(LLSpatialGroup::sg_vector_t& groups, void (*func)(LLDrawable*)); + void forAllVisibleDrawables(void (*func)(LLDrawable*)); + static void highlightPhysical(LLDrawable* drawablep); + + void renderObjects(U32 type, U32 mask, BOOL texture = TRUE); + + void renderGeom(LLCamera& camera); void renderHighlights(); void renderDebug(); + void processGeometry(LLCamera& camera); + void processOcclusion(LLCamera& camera); - void renderForSelect(); + void renderForSelect(std::set<LLViewerObject*>& objects); void renderFaceForUVSelect(LLFace* facep); void rebuildPools(); // Rebuild pools - // bindAGP and unbindAGP are used to bind AGP memory. - // AGP should never be bound if you're writing/copying data to AGP. - // bindAGP will do the correct thing if AGP rendering has been disabled globally. - void bindAGP(); - void unbindAGP(); - inline BOOL isAGPBound() const { return mAGPBound; } - - void setupVisibility(); - void computeVisibility(); - - LLViewerObject *nearestObjectAt(F32 yaw, F32 pitch); // CCW yaw from +X = 0 radians, pitch down from +Y = 0 radians, NULL if no object - - void displayPools(); - void displayAGP(); - void displayMap(); - void displaySSBB(); - void displayQueues(); - void printPools(); - void findReferences(LLDrawable *drawablep); // Find the lists which have references to this object BOOL verify(); // Verify that all data in the pipeline is "correct" - // just the AGP part - S32 getAGPMemUsage(); - - // all pools - S32 getMemUsage(const BOOL print = FALSE); - S32 getVisibleCount() const { return mVisibleList.size(); } S32 getLightCount() const { return mLights.size(); } @@ -234,18 +218,15 @@ public: BOOL hasRenderDebugFeatureMask(const U32 mask) const { return (mRenderDebugFeatureMask & mask) ? TRUE : FALSE; } BOOL hasRenderFeatureMask(const U32 mask) const { return (mRenderFeatureMask & mask) ? TRUE : FALSE; } BOOL hasRenderDebugMask(const U32 mask) const { return (mRenderDebugMask & mask) ? TRUE : FALSE; } - - // Vertex buffer stuff? - U8* bufferGetScratchMemory(void); - void bufferWaitFence(void); - void bufferSendFence(void); - void bufferRotate(void); + void setRenderTypeMask(const U32 mask) { mRenderTypeMask = mask; } + U32 getRenderTypeMask() const { return mRenderTypeMask; } + static void toggleRenderType(U32 type); // For UI control of render features - static void toggleRenderType(void* data); + static BOOL hasRenderTypeControl(void* data); static void toggleRenderDebug(void* data); static void toggleRenderDebugFeature(void* data); - static BOOL toggleRenderTypeControl(void* data); + static void toggleRenderTypeControl(void* data); static BOOL toggleRenderTypeControlNegated(void* data); static BOOL toggleRenderDebugControl(void* data); static BOOL toggleRenderDebugFeatureControl(void* data); @@ -295,20 +276,17 @@ public: RENDER_TYPE_GROUND = LLDrawPool::POOL_GROUND, RENDER_TYPE_TERRAIN = LLDrawPool::POOL_TERRAIN, RENDER_TYPE_SIMPLE = LLDrawPool::POOL_SIMPLE, - RENDER_TYPE_MEDIA = LLDrawPool::POOL_MEDIA, RENDER_TYPE_BUMP = LLDrawPool::POOL_BUMP, RENDER_TYPE_AVATAR = LLDrawPool::POOL_AVATAR, RENDER_TYPE_TREE = LLDrawPool::POOL_TREE, - RENDER_TYPE_TREE_NEW = LLDrawPool::POOL_TREE_NEW, RENDER_TYPE_WATER = LLDrawPool::POOL_WATER, - RENDER_TYPE_CLOUDS = LLDrawPool::POOL_CLOUDS, RENDER_TYPE_ALPHA = LLDrawPool::POOL_ALPHA, - RENDER_TYPE_HUD = LLDrawPool::POOL_HUD, - // Following are object types (only used in drawable mRenderType) + RENDER_TYPE_HUD = LLDrawPool::NUM_POOL_TYPES, RENDER_TYPE_VOLUME, RENDER_TYPE_GRASS, RENDER_TYPE_PARTICLES, + RENDER_TYPE_CLOUDS, }; enum LLRenderDebugFeatureMask @@ -322,13 +300,12 @@ public: RENDER_DEBUG_FEATURE_FOG = 0x0020, RENDER_DEBUG_FEATURE_PALETTE = 0x0040, RENDER_DEBUG_FEATURE_FR_INFO = 0x0080, - RENDER_DEBUG_FEATURE_CHAIN_FACES = 0x0100 + RENDER_DEBUG_FEATURE_FOOT_SHADOWS = 0x0100, }; enum LLRenderFeatureMask { - RENDER_FEATURE_AGP = 0x01, -// RENDER_FEATURE_LOCAL_LIGHTING = 0x02, + RENDER_FEATURE_LOCAL_LIGHTING = 0x02, RENDER_FEATURE_OBJECT_BUMP = 0x04, RENDER_FEATURE_AVATAR_BUMP = 0x08, // RENDER_FEATURE_SHADOWS = 0x10, @@ -337,26 +314,44 @@ public: enum LLRenderDebugMask { - RENDER_DEBUG_LIGHT_TRACE = 0x0001, - RENDER_DEBUG_POOLS = 0x0002, - RENDER_DEBUG_MAP = 0x0004, - RENDER_DEBUG_AGP_MEM = 0x0008, - RENDER_DEBUG_QUEUES = 0x0010, - RENDER_DEBUG_COMPOSITION = 0x0020, - RENDER_DEBUG_SSBB = 0x0040, - RENDER_DEBUG_VERIFY = 0x0080, - RENDER_DEBUG_SHADOW_MAP = 0x0100, - RENDER_DEBUG_BBOXES = 0x0200, - RENDER_DEBUG_OCTREE = 0x0400, - RENDER_DEBUG_FACE_CHAINS = 0x0800, - RENDER_DEBUG_OCCLUSION = 0x1000, - RENDER_DEBUG_POINTS = 0x2000, - RENDER_DEBUG_TEXTURE_PRIORITY = 0x4000, + RENDER_DEBUG_LIGHT_TRACE = 0x00001, + RENDER_DEBUG_COMPOSITION = 0x00020, + RENDER_DEBUG_VERIFY = 0x00080, + RENDER_DEBUG_SHADOW_MAP = 0x00100, + RENDER_DEBUG_BBOXES = 0x00200, + RENDER_DEBUG_OCTREE = 0x00400, + RENDER_DEBUG_PICKING = 0x00800, + RENDER_DEBUG_OCCLUSION = 0x01000, + RENDER_DEBUG_POINTS = 0x02000, + RENDER_DEBUG_TEXTURE_PRIORITY = 0x04000, + RENDER_DEBUG_TEXTURE_AREA = 0x08000, + RENDER_DEBUG_PARTICLES = 0x10000, }; LLPointer<LLViewerImage> mAlphaSizzleImagep; - LLSpatialPartition *mObjectPartition; + //MUST MATCH THE ORDER OF DECLARATION IN LLPipeline::init() + typedef enum + { + PARTITION_VOLUME = 0, + PARTITION_BRIDGE, + PARTITION_HUD, + PARTITION_TERRAIN, + PARTITION_WATER, + PARTITION_TREE, + PARTITION_PARTICLE, + PARTITION_CLOUD, + PARTITION_GRASS, + PARTITION_NONE, + NUM_PARTITIONS + } eObjectPartitions; + +private: + std::vector<LLSpatialPartition*> mObjectPartition; +public: + + LLSpatialPartition* getSpatialPartition(LLViewerObject* vobj); + LLSpatialPartition* getSpatialPartition(U32 index); BOOL mBackfaceCull; S32 mTrianglesDrawn; @@ -375,10 +370,16 @@ public: LLStat mNumVisibleFacesStat; LLStat mNumVisibleDrawablesStat; - static S32 sAGPMaxPoolSize; static S32 sCompiles; - BOOL mUseVBO; // Use ARB vertex buffer objects, if available + static BOOL sShowHUDAttachments; + static BOOL sUseOcclusion; + static BOOL sSkipUpdate; //skip lod updates + static BOOL sDynamicReflections; + + //cube map for anti-aliasing reflections + LLCubeMap* mCubeBuffer; + GLuint mCubeList; class LLScatterShader { @@ -413,15 +414,25 @@ public: GLSL_SPECULAR_MAP, GLSL_BUMP_MAP, GLSL_ENVIRONMENT_MAP, - GLSL_SCATTER_MAP, GLSL_END_RESERVED_UNIFORMS } eGLSLReservedUniforms; + static const char* sShinyUniforms[]; + static U32 sShinyUniformCount; + + typedef enum + { + GLSL_SHINY_ORIGIN = GLSL_END_RESERVED_UNIFORMS + } eShinyUniforms; + + LLVector4 mShinyOrigin; + //object shaders LLGLSLShader mObjectSimpleProgram; LLGLSLShader mObjectAlphaProgram; LLGLSLShader mObjectBumpProgram; - + LLGLSLShader mObjectShinyProgram; + //water parameters static const char* sWaterUniforms[]; static U32 sWaterUniformCount; @@ -496,15 +507,17 @@ public: LLColor4 mSunDiffuse; LLVector3 mSunDir; + + LLSpatialGroup::sg_vector_t mActiveGroups; + std::vector<LLDrawInfo*> mRenderMap[LLRenderPass::NUM_RENDER_TYPES]; + std::vector<LLSpatialGroup* > mAlphaGroups; + std::vector<LLSpatialGroup* > mAlphaGroupsPostWater; + LLSpatialGroup::sg_vector_t mVisibleGroups; + LLSpatialGroup::sg_vector_t mDrawableGroups; + + void clearRenderMap(); protected: - class SelectedFaceInfo - { - public: - LLFace *mFacep; - S32 mTE; - }; - BOOL mVertexShadersEnabled; S32 mVertexShadersLoaded; // 0 = no, 1 = yes, -1 = failed S32 mVertexShaderLevel[SHADER_COUNT]; @@ -515,12 +528,16 @@ protected: U32 mRenderDebugFeatureMask; U32 mRenderDebugMask; + U32 mOldRenderDebugMask; + ///////////////////////////////////////////// // // LLDrawable::drawable_vector_t mVisibleList; - LLDrawable::drawable_set_t mMovedList; - + LLSpatialBridge::bridge_vector_t mVisibleBridge; + LLSpatialBridge::bridge_vector_t mOccludedBridge; + LLDrawable::drawable_vector_t mMovedList; + LLDrawable::drawable_vector_t mMovedBridge; LLDrawable::drawable_vector_t mShiftList; ///////////////////////////////////////////// @@ -559,13 +576,13 @@ protected: // // Different queues of drawables being processed. // - LLDrawable::drawable_set_t mBuildQ1; // priority + LLDrawable::drawable_list_t mBuildQ1; // priority LLDrawable::drawable_list_t mBuildQ2; // non-priority + LLSpatialGroup::sg_set_t mGroupQ; //spatial groups LLDrawable::drawable_set_t mActiveQ; LLDrawable::drawable_set_t mRetexturedList; - LLDrawable::drawable_set_t mRematerialedList; ////////////////////////////////////////////////// // @@ -598,45 +615,27 @@ protected: LLDrawPool* mLastRebuildPool; // For quick-lookups into mPools (mapped by texture pointer) - std::map<uintptr_t, LLDrawPool*> mSimplePools; std::map<uintptr_t, LLDrawPool*> mTerrainPools; std::map<uintptr_t, LLDrawPool*> mTreePools; - std::map<uintptr_t, LLDrawPool*> mTreeNewPools; - std::map<uintptr_t, LLDrawPool*> mBumpPools; - std::map<uintptr_t, LLDrawPool*> mMediaPools; LLDrawPool* mAlphaPool; + LLDrawPool* mAlphaPoolPostWater; LLDrawPool* mSkyPool; LLDrawPool* mStarsPool; - LLDrawPool* mCloudsPool; LLDrawPool* mTerrainPool; LLDrawPool* mWaterPool; LLDrawPool* mGroundPool; - LLDrawPool* mHUDPool; + LLRenderPass* mSimplePool; + LLDrawPool* mBumpPool; // Note: no need to keep an quick-lookup to avatar pools, since there's only one per avatar - LLDynamicArray<LLFace*> mHighlightFaces; // highlight faces on physical objects - LLDynamicArray<SelectedFaceInfo> mSelectedFaces; + std::vector<LLFace*> mHighlightFaces; // highlight faces on physical objects + std::vector<LLFace*> mSelectedFaces; LLPointer<LLViewerImage> mFaceSelectImagep; LLPointer<LLViewerImage> mBloomImagep; LLPointer<LLViewerImage> mBloomImage2p; - - BOOL mAGPBound; - LLAGPMemPool *mAGPMemPool; - U32 mGlobalFence; - - // Round-robin AGP buffers for use by the software skinner - enum - { - kMaxBufferCount = 4 - }; - S32 mBufferIndex; - S32 mBufferCount; - LLAGPArray<U8> *mBufferMemory[kMaxBufferCount]; - U32 mBufferFence[kMaxBufferCount]; - BOOL mUseOcclusionCulling; // object-object occlusion culling U32 mLightMask; U32 mLightMovingMask; S32 mLightingDetail; diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 9f6a001e4f..baa023cd4e 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -49,6 +49,8 @@ class ViewerManifest(LLManifest): # XUI if self.prefix(src="skins"): + # include the entire textures directory recursively + self.path("textures") self.path("paths.xml") self.path("xui/*/*.xml") self.path('words.*.txt') @@ -98,6 +100,8 @@ class WindowsManifest(ViewerManifest): # *NOTE: these are the only two executable names that the crash reporter recognizes if self.args['grid'] == '': return "SecondLife.exe" + elif self.args['grid'] == 'firstlook': + return "SecondLifeFirstLook.exe" else: return "SecondLifePreview.exe" # return "SecondLifePreview%s.exe" % (self.args['grid'], ) @@ -396,7 +400,7 @@ class Linux_i686Manifest(LinuxManifest): self.path("libvorbis.so.0") self.path("libvorbisfile.so.0") self.path("libvorbisenc.so.0") - self.path("libcurl.so.3") + self.path("libcurl.so.4") self.path("libcrypto.so.0.9.7") self.path("libssl.so.0.9.7") self.path("libexpat.so.1") |