Merge remote-tracking branch 'origin/main' into DRTVWR-528
commit
0b188ac04e
|
|
@ -482,9 +482,9 @@
|
|||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>2653c3627fd8687ff9e003425fd14834</string>
|
||||
<string>439d92ec73f0500ba1671faad2bd8090</string>
|
||||
<key>url</key>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/90199/821852/dullahan-1.12.3.202111032211_91.1.21_g9dd45fe_chromium-91.0.4472.114-darwin64-565428.tar.bz2</string>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/104637/916643/dullahan-1.12.4.202209142017_91.1.21_g9dd45fe_chromium-91.0.4472.114-darwin64-575005.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>darwin64</string>
|
||||
|
|
@ -494,9 +494,9 @@
|
|||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>b4003772562a5dd40bc112eec7cba5f5</string>
|
||||
<string>2a7c01da15de77bc1fd1863327174d5e</string>
|
||||
<key>url</key>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/90201/821871/dullahan-1.12.3.202111032221_91.1.21_g9dd45fe_chromium-91.0.4472.114-windows-565428.tar.bz2</string>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/104638/916654/dullahan-1.12.4.202209142021_91.1.21_g9dd45fe_chromium-91.0.4472.114-windows-575005.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows</string>
|
||||
|
|
@ -506,16 +506,16 @@
|
|||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>d9030d7a7390b3bda7de2adcc27e535a</string>
|
||||
<string>d06bee9b2517fbb09ba1a65e6d675361</string>
|
||||
<key>url</key>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/90200/821876/dullahan-1.12.3.202111032221_91.1.21_g9dd45fe_chromium-91.0.4472.114-windows64-565428.tar.bz2</string>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/104639/916659/dullahan-1.12.4.202209142021_91.1.21_g9dd45fe_chromium-91.0.4472.114-windows64-575005.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows64</string>
|
||||
</map>
|
||||
</map>
|
||||
<key>version</key>
|
||||
<string>1.12.3.202111032221_91.1.21_g9dd45fe_chromium-91.0.4472.114</string>
|
||||
<string>1.12.4.202209142021_91.1.21_g9dd45fe_chromium-91.0.4472.114</string>
|
||||
</map>
|
||||
<key>expat</key>
|
||||
<map>
|
||||
|
|
@ -2393,9 +2393,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>6ce3cbaed968a69fb7a2cca80220874d</string>
|
||||
<string>b583668b28fde0490e6953f10e93e4ab</string>
|
||||
<key>url</key>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/80380/758537/slvoice-4.10.0000.32327.5fc3fe7c.558436-darwin64-558436.tar.bz2</string>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/98681/871545/slvoice-4.10.0000.32327.5fc3fe7c.571099-darwin64-571099.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>darwin64</string>
|
||||
|
|
@ -2417,9 +2417,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>2eb38c5eff4d0f18fbb89d0c30c4f0a4</string>
|
||||
<string>6e0ed41653955afe8eeb8945776cf07b</string>
|
||||
<key>url</key>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/80382/758550/slvoice-4.10.0000.32327.5fc3fe7c.558436-windows-558436.tar.bz2</string>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/98683/871560/slvoice-4.10.0000.32327.5fc3fe7c.571099-windows-571099.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows</string>
|
||||
|
|
@ -2429,16 +2429,16 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>9ee8f3cbc5369c598a998c61961ed16d</string>
|
||||
<string>c39735851fd05c194d0be09b8f9e8cb7</string>
|
||||
<key>url</key>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/80381/758551/slvoice-4.10.0000.32327.5fc3fe7c.558436-windows64-558436.tar.bz2</string>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/98682/871552/slvoice-4.10.0000.32327.5fc3fe7c.571099-windows64-571099.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows64</string>
|
||||
</map>
|
||||
</map>
|
||||
<key>version</key>
|
||||
<string>4.10.0000.32327.5fc3fe7c.558436</string>
|
||||
<string>4.10.0000.32327.5fc3fe7c.571099</string>
|
||||
</map>
|
||||
<key>threejs</key>
|
||||
<map>
|
||||
|
|
@ -2888,7 +2888,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<key>package_description</key>
|
||||
<map>
|
||||
<key>canonical_repo</key>
|
||||
<string>https://bitbucket.org/lindenlab/viewer</string>
|
||||
<string>https://github.com/secondlife/viewer</string>
|
||||
<key>copyright</key>
|
||||
<string>Copyright (c) 2020, Linden Research, Inc.</string>
|
||||
<key>description</key>
|
||||
|
|
|
|||
|
|
@ -223,6 +223,7 @@ Ansariel Hiller
|
|||
MAINT-8723
|
||||
SL-10385
|
||||
SL-10891
|
||||
SL-10675
|
||||
SL-13364
|
||||
SL-13858
|
||||
SL-13697
|
||||
|
|
@ -235,6 +236,7 @@ Ansariel Hiller
|
|||
SL-15226
|
||||
SL-15227
|
||||
SL-15398
|
||||
SL-18432
|
||||
Aralara Rajal
|
||||
Arare Chantilly
|
||||
CHUIBUG-191
|
||||
|
|
@ -400,6 +402,7 @@ Cinder Roxley
|
|||
STORM-2127
|
||||
STORM-2144
|
||||
SL-3404
|
||||
SL-17634
|
||||
Clara Young
|
||||
Coaldust Numbers
|
||||
VWR-1095
|
||||
|
|
@ -820,6 +823,7 @@ Jonathan Yap
|
|||
Kadah Coba
|
||||
STORM-1060
|
||||
STORM-1843
|
||||
SL-10675
|
||||
Jondan Lundquist
|
||||
Joosten Briebers
|
||||
MAINT-7074
|
||||
|
|
@ -1120,6 +1124,7 @@ Nicky Dasmijn
|
|||
SL-14541
|
||||
SL-16438
|
||||
SL-17218
|
||||
SL-17585
|
||||
Nicky Perian
|
||||
OPEN-1
|
||||
STORM-1087
|
||||
|
|
|
|||
|
|
@ -927,6 +927,9 @@ BOOL LLAvatarAppearance::loadAvatar()
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
// initialize mJointAliasMap
|
||||
getJointAliases();
|
||||
|
||||
// avatar_lad.xml : <skeleton>
|
||||
if( !loadSkeletonNode() )
|
||||
{
|
||||
|
|
@ -1047,7 +1050,6 @@ BOOL LLAvatarAppearance::loadAvatar()
|
|||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -612,14 +612,16 @@ BOOL LLPolyMeshSharedData::loadMesh( const std::string& fileName )
|
|||
// we reached the end of the morphs
|
||||
break;
|
||||
}
|
||||
LLPolyMorphData* morph_data = new LLPolyMorphData(std::string(morphName));
|
||||
std::string morph_name(morphName);
|
||||
LLPolyMorphData* morph_data = new LLPolyMorphData(morph_name);
|
||||
|
||||
BOOL result = morph_data->loadBinary(fp, this);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
delete morph_data;
|
||||
continue;
|
||||
LL_WARNS() << "Failure loading " << morph_name << " from " << fileName << LL_ENDL;
|
||||
delete morph_data;
|
||||
continue;
|
||||
}
|
||||
|
||||
mMorphData.insert(morph_data);
|
||||
|
|
|
|||
|
|
@ -156,7 +156,9 @@ BOOL LLPolyMorphData::loadBinary(LLFILE *fp, LLPolyMeshSharedData *mesh)
|
|||
|
||||
if (mVertexIndices[v] > 10000)
|
||||
{
|
||||
LL_ERRS() << "Bad morph index: " << mVertexIndices[v] << LL_ENDL;
|
||||
// Bad install? These are usually .llm files from 'character' fodler
|
||||
LL_WARNS() << "Bad morph index " << v << ": " << mVertexIndices[v] << LL_ENDL;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,8 @@
|
|||
#include "llendianswizzle.h"
|
||||
#include "llassetstorage.h"
|
||||
#include "llrefcount.h"
|
||||
#include "threadpool.h"
|
||||
#include "workqueue.h"
|
||||
|
||||
#include "llvorbisencode.h"
|
||||
|
||||
|
|
@ -45,15 +47,13 @@
|
|||
|
||||
extern LLAudioEngine *gAudiop;
|
||||
|
||||
LLAudioDecodeMgr *gAudioDecodeMgrp = NULL;
|
||||
|
||||
static const S32 WAV_HEADER_SIZE = 44;
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class LLVorbisDecodeState : public LLRefCount
|
||||
class LLVorbisDecodeState : public LLThreadSafeRefCount
|
||||
{
|
||||
public:
|
||||
class WriteResponder : public LLLFSThread::Responder
|
||||
|
|
@ -532,146 +532,254 @@ void LLVorbisDecodeState::flushBadFile()
|
|||
|
||||
class LLAudioDecodeMgr::Impl
|
||||
{
|
||||
friend class LLAudioDecodeMgr;
|
||||
public:
|
||||
Impl() {};
|
||||
~Impl() {};
|
||||
friend class LLAudioDecodeMgr;
|
||||
Impl();
|
||||
public:
|
||||
|
||||
void processQueue(const F32 num_secs = 0.005);
|
||||
void processQueue();
|
||||
|
||||
protected:
|
||||
std::deque<LLUUID> mDecodeQueue;
|
||||
LLPointer<LLVorbisDecodeState> mCurrentDecodep;
|
||||
void startMoreDecodes();
|
||||
void enqueueFinishAudio(const LLUUID &decode_id, LLPointer<LLVorbisDecodeState>& decode_state);
|
||||
void checkDecodesFinished();
|
||||
|
||||
protected:
|
||||
std::deque<LLUUID> mDecodeQueue;
|
||||
std::map<LLUUID, LLPointer<LLVorbisDecodeState>> mDecodes;
|
||||
};
|
||||
|
||||
|
||||
void LLAudioDecodeMgr::Impl::processQueue(const F32 num_secs)
|
||||
LLAudioDecodeMgr::Impl::Impl()
|
||||
{
|
||||
LLUUID uuid;
|
||||
}
|
||||
|
||||
LLTimer decode_timer;
|
||||
// Returns the in-progress decode_state, which may be an empty LLPointer if
|
||||
// there was an error and there is no more work to be done.
|
||||
LLPointer<LLVorbisDecodeState> beginDecodingAndWritingAudio(const LLUUID &decode_id);
|
||||
|
||||
BOOL done = FALSE;
|
||||
while (!done)
|
||||
{
|
||||
if (mCurrentDecodep)
|
||||
{
|
||||
BOOL res;
|
||||
// Return true if finished
|
||||
bool tryFinishAudio(const LLUUID &decode_id, LLPointer<LLVorbisDecodeState> decode_state);
|
||||
|
||||
// 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
|
||||
}
|
||||
void LLAudioDecodeMgr::Impl::processQueue()
|
||||
{
|
||||
// First, check if any audio from in-progress decodes are ready to play. If
|
||||
// so, mark them ready for playback (or errored, in case of error).
|
||||
checkDecodesFinished();
|
||||
|
||||
if (mCurrentDecodep->isDone() && !mCurrentDecodep->isValid())
|
||||
{
|
||||
// We had an error when decoding, abort.
|
||||
LL_WARNS("AudioEngine") << mCurrentDecodep->getUUID() << " has invalid vorbis data, aborting decode" << LL_ENDL;
|
||||
mCurrentDecodep->flushBadFile();
|
||||
// Second, start as many decodes from the queue as permitted
|
||||
startMoreDecodes();
|
||||
}
|
||||
|
||||
if (gAudiop)
|
||||
{
|
||||
LLAudioData *adp = gAudiop->getAudioData(mCurrentDecodep->getUUID());
|
||||
adp->setHasValidData(false);
|
||||
adp->setHasCompletedDecode(true);
|
||||
}
|
||||
void LLAudioDecodeMgr::Impl::startMoreDecodes()
|
||||
{
|
||||
llassert_always(gAudiop);
|
||||
|
||||
mCurrentDecodep = NULL;
|
||||
done = TRUE;
|
||||
}
|
||||
LL::WorkQueue::ptr_t main_queue = LL::WorkQueue::getInstance("mainloop");
|
||||
// *NOTE: main_queue->postTo casts this refcounted smart pointer to a weak
|
||||
// pointer
|
||||
LL::WorkQueue::ptr_t general_queue = LL::WorkQueue::getInstance("General");
|
||||
const LL::ThreadPool::ptr_t general_thread_pool = LL::ThreadPool::getInstance("General");
|
||||
llassert_always(main_queue);
|
||||
llassert_always(general_queue);
|
||||
llassert_always(general_thread_pool);
|
||||
// Set max decodes to double the thread count of the general work queue.
|
||||
// This ensures the general work queue is full, but prevents theoretical
|
||||
// buildup of buffers in memory due to disk writes once the
|
||||
// LLVorbisDecodeState leaves the worker thread (see
|
||||
// LLLFSThread::sLocal->write). This is probably as fast as we can get it
|
||||
// without modifying/removing LLVorbisDecodeState, at which point we should
|
||||
// consider decoding the audio during the asset download process.
|
||||
// -Cosmic,2022-05-11
|
||||
const size_t max_decodes = general_thread_pool->getWidth() * 2;
|
||||
|
||||
if (!res)
|
||||
{
|
||||
// We've used up out time slice, bail...
|
||||
done = TRUE;
|
||||
}
|
||||
else if (mCurrentDecodep)
|
||||
{
|
||||
if (gAudiop && mCurrentDecodep->finishDecode())
|
||||
{
|
||||
// We finished!
|
||||
LLAudioData *adp = gAudiop->getAudioData(mCurrentDecodep->getUUID());
|
||||
if (!adp)
|
||||
{
|
||||
LL_WARNS("AudioEngine") << "Missing LLAudioData for decode of " << mCurrentDecodep->getUUID() << LL_ENDL;
|
||||
}
|
||||
else if (mCurrentDecodep->isValid() && mCurrentDecodep->isDone())
|
||||
{
|
||||
adp->setHasCompletedDecode(true);
|
||||
adp->setHasDecodedData(true);
|
||||
adp->setHasValidData(true);
|
||||
while (!mDecodeQueue.empty() && mDecodes.size() < max_decodes)
|
||||
{
|
||||
const LLUUID decode_id = mDecodeQueue.front();
|
||||
mDecodeQueue.pop_front();
|
||||
|
||||
// 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.
|
||||
//LL_INFOS("AudioEngine") << "Finished the vorbis decode, now what?" << LL_ENDL;
|
||||
}
|
||||
else
|
||||
{
|
||||
adp->setHasCompletedDecode(true);
|
||||
LL_INFOS("AudioEngine") << "Vorbis decode failed for " << mCurrentDecodep->getUUID() << LL_ENDL;
|
||||
}
|
||||
mCurrentDecodep = NULL;
|
||||
}
|
||||
done = TRUE; // done for now
|
||||
}
|
||||
}
|
||||
// Don't decode the same file twice
|
||||
if (mDecodes.find(decode_id) != mDecodes.end())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (gAudiop->hasDecodedFile(decode_id))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!done)
|
||||
{
|
||||
if (mDecodeQueue.empty())
|
||||
{
|
||||
// Nothing else on the queue.
|
||||
done = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
LLUUID uuid;
|
||||
uuid = mDecodeQueue.front();
|
||||
mDecodeQueue.pop_front();
|
||||
if (!gAudiop || gAudiop->hasDecodedFile(uuid))
|
||||
{
|
||||
// This file has already been decoded, don't decode it again.
|
||||
continue;
|
||||
}
|
||||
// Kick off a decode
|
||||
mDecodes[decode_id] = LLPointer<LLVorbisDecodeState>(NULL);
|
||||
try
|
||||
{
|
||||
main_queue->postTo(
|
||||
general_queue,
|
||||
[decode_id]() // Work done on general queue
|
||||
{
|
||||
LLPointer<LLVorbisDecodeState> decode_state = beginDecodingAndWritingAudio(decode_id);
|
||||
|
||||
LL_DEBUGS() << "Decoding " << uuid << " from audio queue!" << LL_ENDL;
|
||||
if (!decode_state)
|
||||
{
|
||||
// Audio decode has errored
|
||||
return decode_state;
|
||||
}
|
||||
|
||||
std::string uuid_str;
|
||||
std::string d_path;
|
||||
// Disk write of decoded audio is now in progress off-thread
|
||||
return decode_state;
|
||||
},
|
||||
[decode_id, this](LLPointer<LLVorbisDecodeState> decode_state) // Callback to main thread
|
||||
mutable {
|
||||
if (!gAudiop)
|
||||
{
|
||||
// There is no LLAudioEngine anymore. This might happen if
|
||||
// an audio decode is enqueued just before shutdown.
|
||||
return;
|
||||
}
|
||||
|
||||
LLTimer timer;
|
||||
timer.reset();
|
||||
// At this point, we can be certain that the pointer to "this"
|
||||
// is valid because the lifetime of "this" is dependent upon
|
||||
// the lifetime of gAudiop.
|
||||
|
||||
uuid.toString(uuid_str);
|
||||
d_path = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_str) + ".dsf";
|
||||
enqueueFinishAudio(decode_id, decode_state);
|
||||
});
|
||||
}
|
||||
catch (const LLThreadSafeQueueInterrupt&)
|
||||
{
|
||||
// Shutdown
|
||||
// Consider making processQueue() do a cleanup instead
|
||||
// of starting more decodes
|
||||
LL_WARNS() << "Tried to start decoding on shutdown" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mCurrentDecodep = new LLVorbisDecodeState(uuid, d_path);
|
||||
if (!mCurrentDecodep->initDecode())
|
||||
{
|
||||
mCurrentDecodep = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
LLPointer<LLVorbisDecodeState> beginDecodingAndWritingAudio(const LLUUID &decode_id)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA;
|
||||
|
||||
LL_DEBUGS() << "Decoding " << decode_id << " from audio queue!" << LL_ENDL;
|
||||
|
||||
std::string d_path = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, decode_id.asString()) + ".dsf";
|
||||
LLPointer<LLVorbisDecodeState> decode_state = new LLVorbisDecodeState(decode_id, d_path);
|
||||
|
||||
if (!decode_state->initDecode())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Decode in a loop until we're done
|
||||
while (!decode_state->decodeSection())
|
||||
{
|
||||
// decodeSection does all of the work above
|
||||
}
|
||||
|
||||
if (!decode_state->isDone())
|
||||
{
|
||||
// Decode stopped early, or something bad happened to the file
|
||||
// during decoding.
|
||||
LL_WARNS("AudioEngine") << decode_id << " has invalid vorbis data or decode has been canceled, aborting decode" << LL_ENDL;
|
||||
decode_state->flushBadFile();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!decode_state->isValid())
|
||||
{
|
||||
// We had an error when decoding, abort.
|
||||
LL_WARNS("AudioEngine") << decode_id << " has invalid vorbis data, aborting decode" << LL_ENDL;
|
||||
decode_state->flushBadFile();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Kick off the writing of the decoded audio to the disk cache.
|
||||
// The receiving thread can then cheaply call finishDecode() again to check
|
||||
// if writing has finished. Someone has to hold on to the refcounted
|
||||
// decode_state to prevent it from getting destroyed during write.
|
||||
decode_state->finishDecode();
|
||||
|
||||
return decode_state;
|
||||
}
|
||||
|
||||
void LLAudioDecodeMgr::Impl::enqueueFinishAudio(const LLUUID &decode_id, LLPointer<LLVorbisDecodeState>& decode_state)
|
||||
{
|
||||
// Assumed fast
|
||||
if (tryFinishAudio(decode_id, decode_state))
|
||||
{
|
||||
// Done early!
|
||||
auto decode_iter = mDecodes.find(decode_id);
|
||||
llassert(decode_iter != mDecodes.end());
|
||||
mDecodes.erase(decode_iter);
|
||||
return;
|
||||
}
|
||||
|
||||
// Not done yet... enqueue it
|
||||
mDecodes[decode_id] = decode_state;
|
||||
}
|
||||
|
||||
void LLAudioDecodeMgr::Impl::checkDecodesFinished()
|
||||
{
|
||||
auto decode_iter = mDecodes.begin();
|
||||
while (decode_iter != mDecodes.end())
|
||||
{
|
||||
const LLUUID& decode_id = decode_iter->first;
|
||||
const LLPointer<LLVorbisDecodeState>& decode_state = decode_iter->second;
|
||||
if (tryFinishAudio(decode_id, decode_state))
|
||||
{
|
||||
decode_iter = mDecodes.erase(decode_iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
++decode_iter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool tryFinishAudio(const LLUUID &decode_id, LLPointer<LLVorbisDecodeState> decode_state)
|
||||
{
|
||||
// decode_state is a file write in progress unless finished is true
|
||||
bool finished = decode_state && decode_state->finishDecode();
|
||||
if (!finished)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
llassert_always(gAudiop);
|
||||
|
||||
LLAudioData *adp = gAudiop->getAudioData(decode_id);
|
||||
if (!adp)
|
||||
{
|
||||
LL_WARNS("AudioEngine") << "Missing LLAudioData for decode of " << decode_id << LL_ENDL;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool valid = decode_state && decode_state->isValid();
|
||||
// Mark current decode finished regardless of success or failure
|
||||
adp->setHasCompletedDecode(true);
|
||||
// Flip flags for decoded data
|
||||
adp->setHasDecodeFailed(!valid);
|
||||
adp->setHasDecodedData(valid);
|
||||
// When finished decoding, there will also be a decoded wav file cached on
|
||||
// disk with the .dsf extension
|
||||
if (valid)
|
||||
{
|
||||
adp->setHasWAVLoadFailed(false);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
LLAudioDecodeMgr::LLAudioDecodeMgr()
|
||||
{
|
||||
mImpl = new Impl;
|
||||
mImpl = new Impl();
|
||||
}
|
||||
|
||||
LLAudioDecodeMgr::~LLAudioDecodeMgr()
|
||||
{
|
||||
delete mImpl;
|
||||
delete mImpl;
|
||||
mImpl = nullptr;
|
||||
}
|
||||
|
||||
void LLAudioDecodeMgr::processQueue(const F32 num_secs)
|
||||
void LLAudioDecodeMgr::processQueue()
|
||||
{
|
||||
mImpl->processQueue(num_secs);
|
||||
mImpl->processQueue();
|
||||
}
|
||||
|
||||
BOOL LLAudioDecodeMgr::addDecodeRequest(const LLUUID &uuid)
|
||||
|
|
@ -687,7 +795,7 @@ BOOL LLAudioDecodeMgr::addDecodeRequest(const LLUUID &uuid)
|
|||
{
|
||||
// Just put it on the decode queue.
|
||||
LL_DEBUGS("AudioEngine") << "addDecodeRequest for " << uuid << " has local asset file already" << LL_ENDL;
|
||||
mImpl->mDecodeQueue.push_back(uuid);
|
||||
mImpl->mDecodeQueue.push_back(uuid);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -32,24 +32,23 @@
|
|||
|
||||
#include "llassettype.h"
|
||||
#include "llframetimer.h"
|
||||
#include "llsingleton.h"
|
||||
|
||||
template<class T> class LLPointer;
|
||||
class LLVorbisDecodeState;
|
||||
|
||||
class LLAudioDecodeMgr
|
||||
class LLAudioDecodeMgr : public LLSingleton<LLAudioDecodeMgr>
|
||||
{
|
||||
LLSINGLETON(LLAudioDecodeMgr);
|
||||
~LLAudioDecodeMgr();
|
||||
public:
|
||||
LLAudioDecodeMgr();
|
||||
~LLAudioDecodeMgr();
|
||||
|
||||
void processQueue(const F32 num_secs = 0.005);
|
||||
void processQueue();
|
||||
BOOL addDecodeRequest(const LLUUID &uuid);
|
||||
void addAudioRequest(const LLUUID &uuid);
|
||||
|
||||
protected:
|
||||
class Impl;
|
||||
Impl* mImpl;
|
||||
Impl* mImpl;
|
||||
};
|
||||
|
||||
extern LLAudioDecodeMgr *gAudioDecodeMgrp;
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -83,18 +83,10 @@ void LLAudioEngine::setDefaults()
|
|||
|
||||
mLastStatus = 0;
|
||||
|
||||
mNumChannels = 0;
|
||||
mEnableWind = false;
|
||||
|
||||
S32 i;
|
||||
for (i = 0; i < MAX_CHANNELS; i++)
|
||||
{
|
||||
mChannels[i] = NULL;
|
||||
}
|
||||
for (i = 0; i < MAX_BUFFERS; i++)
|
||||
{
|
||||
mBuffers[i] = NULL;
|
||||
}
|
||||
mChannels.fill(nullptr);
|
||||
mBuffers.fill(nullptr);
|
||||
|
||||
mMasterGain = 1.f;
|
||||
// Setting mInternalGain to an out of range value fixes the issue reported in STORM-830.
|
||||
|
|
@ -111,18 +103,14 @@ void LLAudioEngine::setDefaults()
|
|||
}
|
||||
|
||||
|
||||
bool LLAudioEngine::init(const S32 num_channels, void* userdata, const std::string &app_title)
|
||||
bool LLAudioEngine::init(void* userdata, const std::string &app_title)
|
||||
{
|
||||
setDefaults();
|
||||
|
||||
mNumChannels = num_channels;
|
||||
mUserData = userdata;
|
||||
|
||||
allocateListener();
|
||||
|
||||
// Initialize the decode manager
|
||||
gAudioDecodeMgrp = new LLAudioDecodeMgr;
|
||||
|
||||
LL_INFOS("AudioEngine") << "LLAudioEngine::init() AudioEngine successfully initialized" << LL_ENDL;
|
||||
|
||||
return true;
|
||||
|
|
@ -131,10 +119,6 @@ bool LLAudioEngine::init(const S32 num_channels, void* userdata, const std::stri
|
|||
|
||||
void LLAudioEngine::shutdown()
|
||||
{
|
||||
// Clean up decode manager
|
||||
delete gAudioDecodeMgrp;
|
||||
gAudioDecodeMgrp = NULL;
|
||||
|
||||
// Clean up wind source
|
||||
cleanupWind();
|
||||
|
||||
|
|
@ -156,14 +140,14 @@ void LLAudioEngine::shutdown()
|
|||
|
||||
// Clean up channels
|
||||
S32 i;
|
||||
for (i = 0; i < MAX_CHANNELS; i++)
|
||||
for (i = 0; i < LL_MAX_AUDIO_CHANNELS; i++)
|
||||
{
|
||||
delete mChannels[i];
|
||||
mChannels[i] = NULL;
|
||||
}
|
||||
|
||||
// Clean up buffers
|
||||
for (i = 0; i < MAX_BUFFERS; i++)
|
||||
for (i = 0; i < LL_MAX_AUDIO_BUFFERS; i++)
|
||||
{
|
||||
delete mBuffers[i];
|
||||
mBuffers[i] = NULL;
|
||||
|
|
@ -229,7 +213,7 @@ std::string LLAudioEngine::getInternetStreamURL()
|
|||
void LLAudioEngine::updateChannels()
|
||||
{
|
||||
S32 i;
|
||||
for (i = 0; i < MAX_CHANNELS; i++)
|
||||
for (i = 0; i < LL_MAX_AUDIO_CHANNELS; i++)
|
||||
{
|
||||
if (mChannels[i])
|
||||
{
|
||||
|
|
@ -240,20 +224,14 @@ void LLAudioEngine::updateChannels()
|
|||
}
|
||||
}
|
||||
|
||||
static const F32 default_max_decode_time = .002f; // 2 ms
|
||||
void LLAudioEngine::idle(F32 max_decode_time)
|
||||
void LLAudioEngine::idle()
|
||||
{
|
||||
if (max_decode_time <= 0.f)
|
||||
{
|
||||
max_decode_time = default_max_decode_time;
|
||||
}
|
||||
|
||||
// "Update" all of our audio sources, clean up dead ones.
|
||||
// Primarily does position updating, cleanup of unused audio sources.
|
||||
// Also does regeneration of the current priority of each audio source.
|
||||
|
||||
S32 i;
|
||||
for (i = 0; i < MAX_BUFFERS; i++)
|
||||
for (i = 0; i < LL_MAX_AUDIO_BUFFERS; i++)
|
||||
{
|
||||
if (mBuffers[i])
|
||||
{
|
||||
|
|
@ -276,7 +254,7 @@ void LLAudioEngine::idle(F32 max_decode_time)
|
|||
{
|
||||
// The source is done playing, clean it up.
|
||||
delete sourcep;
|
||||
mAllSources.erase(iter++);
|
||||
iter = mAllSources.erase(iter);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -473,7 +451,7 @@ void LLAudioEngine::idle(F32 max_decode_time)
|
|||
commitDeferredChanges();
|
||||
|
||||
// Flush unused buffers that are stale enough
|
||||
for (i = 0; i < MAX_BUFFERS; i++)
|
||||
for (i = 0; i < LL_MAX_AUDIO_BUFFERS; i++)
|
||||
{
|
||||
if (mBuffers[i])
|
||||
{
|
||||
|
|
@ -489,7 +467,7 @@ void LLAudioEngine::idle(F32 max_decode_time)
|
|||
|
||||
|
||||
// Clear all of the looped flags for the channels
|
||||
for (i = 0; i < MAX_CHANNELS; i++)
|
||||
for (i = 0; i < LL_MAX_AUDIO_CHANNELS; i++)
|
||||
{
|
||||
if (mChannels[i])
|
||||
{
|
||||
|
|
@ -498,7 +476,7 @@ void LLAudioEngine::idle(F32 max_decode_time)
|
|||
}
|
||||
|
||||
// Decode audio files
|
||||
gAudioDecodeMgrp->processQueue(max_decode_time);
|
||||
LLAudioDecodeMgr::getInstance()->processQueue();
|
||||
|
||||
// Call this every frame, just in case we somehow
|
||||
// missed picking it up in all the places that can add
|
||||
|
|
@ -532,7 +510,7 @@ bool LLAudioEngine::updateBufferForData(LLAudioData *adp, const LLUUID &audio_uu
|
|||
{
|
||||
if (audio_uuid.notNull())
|
||||
{
|
||||
gAudioDecodeMgrp->addDecodeRequest(audio_uuid);
|
||||
LLAudioDecodeMgr::getInstance()->addDecodeRequest(audio_uuid);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -561,7 +539,7 @@ void LLAudioEngine::enableWind(bool enable)
|
|||
LLAudioBuffer * LLAudioEngine::getFreeBuffer()
|
||||
{
|
||||
S32 i;
|
||||
for (i = 0; i < MAX_BUFFERS; i++)
|
||||
for (i = 0; i < LL_MAX_AUDIO_BUFFERS; i++)
|
||||
{
|
||||
if (!mBuffers[i])
|
||||
{
|
||||
|
|
@ -574,7 +552,7 @@ LLAudioBuffer * LLAudioEngine::getFreeBuffer()
|
|||
// Grab the oldest unused buffer
|
||||
F32 max_age = -1.f;
|
||||
S32 buffer_id = -1;
|
||||
for (i = 0; i < MAX_BUFFERS; i++)
|
||||
for (i = 0; i < LL_MAX_AUDIO_BUFFERS; i++)
|
||||
{
|
||||
if (mBuffers[i])
|
||||
{
|
||||
|
|
@ -605,7 +583,7 @@ LLAudioBuffer * LLAudioEngine::getFreeBuffer()
|
|||
LLAudioChannel * LLAudioEngine::getFreeChannel(const F32 priority)
|
||||
{
|
||||
S32 i;
|
||||
for (i = 0; i < mNumChannels; i++)
|
||||
for (i = 0; i < LL_MAX_AUDIO_CHANNELS; i++)
|
||||
{
|
||||
if (!mChannels[i])
|
||||
{
|
||||
|
|
@ -633,7 +611,7 @@ LLAudioChannel * LLAudioEngine::getFreeChannel(const F32 priority)
|
|||
F32 min_priority = 10000.f;
|
||||
LLAudioChannel *min_channelp = NULL;
|
||||
|
||||
for (i = 0; i < mNumChannels; i++)
|
||||
for (i = 0; i < LL_MAX_AUDIO_CHANNELS; i++)
|
||||
{
|
||||
LLAudioChannel *channelp = mChannels[i];
|
||||
LLAudioSource *sourcep = channelp->getSource();
|
||||
|
|
@ -660,7 +638,7 @@ LLAudioChannel * LLAudioEngine::getFreeChannel(const F32 priority)
|
|||
void LLAudioEngine::cleanupBuffer(LLAudioBuffer *bufferp)
|
||||
{
|
||||
S32 i;
|
||||
for (i = 0; i < MAX_BUFFERS; i++)
|
||||
for (i = 0; i < LL_MAX_AUDIO_BUFFERS; i++)
|
||||
{
|
||||
if (mBuffers[i] == bufferp)
|
||||
{
|
||||
|
|
@ -678,7 +656,7 @@ bool LLAudioEngine::preloadSound(const LLUUID &uuid)
|
|||
getAudioData(uuid); // We don't care about the return value, this is just to make sure
|
||||
// that we have an entry, which will mean that the audio engine knows about this
|
||||
|
||||
if (gAudioDecodeMgrp->addDecodeRequest(uuid))
|
||||
if (LLAudioDecodeMgr::getInstance()->addDecodeRequest(uuid))
|
||||
{
|
||||
// This means that we do have a local copy, and we're working on decoding it.
|
||||
return true;
|
||||
|
|
@ -827,7 +805,8 @@ void LLAudioEngine::triggerSound(const LLUUID &audio_uuid, const LLUUID& owner_i
|
|||
addAudioSource(asp);
|
||||
if (pos_global.isExactlyZero())
|
||||
{
|
||||
asp->setAmbient(true);
|
||||
// For sound preview and UI
|
||||
asp->setForcedPriority(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -953,6 +932,7 @@ LLAudioSource * LLAudioEngine::findAudioSource(const LLUUID &source_id)
|
|||
|
||||
LLAudioData * LLAudioEngine::getAudioData(const LLUUID &audio_uuid)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA;
|
||||
data_map::iterator iter;
|
||||
iter = mAllData.find(audio_uuid);
|
||||
if (iter == mAllData.end())
|
||||
|
|
@ -1039,7 +1019,7 @@ void LLAudioEngine::startNextTransfer()
|
|||
|
||||
// Check all channels for currently playing sounds.
|
||||
F32 max_pri = -1.f;
|
||||
for (i = 0; i < MAX_CHANNELS; i++)
|
||||
for (i = 0; i < LL_MAX_AUDIO_CHANNELS; i++)
|
||||
{
|
||||
if (!mChannels[i])
|
||||
{
|
||||
|
|
@ -1067,7 +1047,7 @@ void LLAudioEngine::startNextTransfer()
|
|||
continue;
|
||||
}
|
||||
|
||||
if (!adp->hasLocalData() && adp->hasValidData())
|
||||
if (!adp->hasLocalData() && !adp->hasDecodeFailed())
|
||||
{
|
||||
asset_id = adp->getID();
|
||||
max_pri = asp->getPriority();
|
||||
|
|
@ -1078,7 +1058,7 @@ void LLAudioEngine::startNextTransfer()
|
|||
if (asset_id.isNull())
|
||||
{
|
||||
max_pri = -1.f;
|
||||
for (i = 0; i < MAX_CHANNELS; i++)
|
||||
for (i = 0; i < LL_MAX_AUDIO_CHANNELS; i++)
|
||||
{
|
||||
if (!mChannels[i])
|
||||
{
|
||||
|
|
@ -1103,7 +1083,7 @@ void LLAudioEngine::startNextTransfer()
|
|||
continue;
|
||||
}
|
||||
|
||||
if (!adp->hasLocalData() && adp->hasValidData())
|
||||
if (!adp->hasLocalData() && !adp->hasDecodeFailed())
|
||||
{
|
||||
asset_id = adp->getID();
|
||||
max_pri = asp->getPriority();
|
||||
|
|
@ -1115,7 +1095,7 @@ void LLAudioEngine::startNextTransfer()
|
|||
if (asset_id.isNull())
|
||||
{
|
||||
max_pri = -1.f;
|
||||
for (i = 0; i < MAX_CHANNELS; i++)
|
||||
for (i = 0; i < LL_MAX_AUDIO_CHANNELS; i++)
|
||||
{
|
||||
if (!mChannels[i])
|
||||
{
|
||||
|
|
@ -1143,7 +1123,7 @@ void LLAudioEngine::startNextTransfer()
|
|||
continue;
|
||||
}
|
||||
|
||||
if (!adp->hasLocalData() && adp->hasValidData())
|
||||
if (!adp->hasLocalData() && !adp->hasDecodeFailed())
|
||||
{
|
||||
asset_id = adp->getID();
|
||||
max_pri = asp->getPriority();
|
||||
|
|
@ -1171,7 +1151,7 @@ void LLAudioEngine::startNextTransfer()
|
|||
}
|
||||
|
||||
adp = asp->getCurrentData();
|
||||
if (adp && !adp->hasLocalData() && adp->hasValidData())
|
||||
if (adp && !adp->hasLocalData() && !adp->hasDecodeFailed())
|
||||
{
|
||||
asset_id = adp->getID();
|
||||
max_pri = asp->getPriority();
|
||||
|
|
@ -1179,7 +1159,7 @@ void LLAudioEngine::startNextTransfer()
|
|||
}
|
||||
|
||||
adp = asp->getQueuedData();
|
||||
if (adp && !adp->hasLocalData() && adp->hasValidData())
|
||||
if (adp && !adp->hasLocalData() && !adp->hasDecodeFailed())
|
||||
{
|
||||
asset_id = adp->getID();
|
||||
max_pri = asp->getPriority();
|
||||
|
|
@ -1194,7 +1174,7 @@ void LLAudioEngine::startNextTransfer()
|
|||
continue;
|
||||
}
|
||||
|
||||
if (!adp->hasLocalData() && adp->hasValidData())
|
||||
if (!adp->hasLocalData() && !adp->hasDecodeFailed())
|
||||
{
|
||||
asset_id = adp->getID();
|
||||
max_pri = asp->getPriority();
|
||||
|
|
@ -1235,7 +1215,7 @@ void LLAudioEngine::assetCallback(const LLUUID &uuid, LLAssetType::EType type, v
|
|||
LLAudioData *adp = gAudiop->getAudioData(uuid);
|
||||
if (adp)
|
||||
{ // Make sure everything is cleared
|
||||
adp->setHasValidData(false);
|
||||
adp->setHasDecodeFailed(true);
|
||||
adp->setHasLocalData(false);
|
||||
adp->setHasDecodedData(false);
|
||||
adp->setHasCompletedDecode(true);
|
||||
|
|
@ -1252,9 +1232,9 @@ void LLAudioEngine::assetCallback(const LLUUID &uuid, LLAssetType::EType type, v
|
|||
else
|
||||
{
|
||||
// LL_INFOS() << "Got asset callback with good audio data for " << uuid << ", making decode request" << LL_ENDL;
|
||||
adp->setHasValidData(true);
|
||||
adp->setHasDecodeFailed(false);
|
||||
adp->setHasLocalData(true);
|
||||
gAudioDecodeMgrp->addDecodeRequest(uuid);
|
||||
LLAudioDecodeMgr::getInstance()->addDecodeRequest(uuid);
|
||||
}
|
||||
}
|
||||
gAudiop->mCurrentTransfer = LLUUID::null;
|
||||
|
|
@ -1273,7 +1253,7 @@ LLAudioSource::LLAudioSource(const LLUUID& id, const LLUUID& owner_id, const F32
|
|||
mPriority(0.f),
|
||||
mGain(gain),
|
||||
mSourceMuted(false),
|
||||
mAmbient(false),
|
||||
mForcedPriority(false),
|
||||
mLoop(false),
|
||||
mSyncMaster(false),
|
||||
mSyncSlave(false),
|
||||
|
|
@ -1324,11 +1304,15 @@ void LLAudioSource::update()
|
|||
{
|
||||
// Hack - try and load the sound. Will do this as a callback
|
||||
// on decode later.
|
||||
if (adp->load() && adp->getBuffer())
|
||||
if (adp->getBuffer())
|
||||
{
|
||||
play(adp->getID());
|
||||
}
|
||||
else if (adp->hasCompletedDecode()) // Only mark corrupted after decode is done
|
||||
else if (adp->hasDecodedData() && !adp->hasWAVLoadFailed())
|
||||
{
|
||||
adp->load();
|
||||
}
|
||||
else if (adp->hasCompletedDecode() && adp->hasDecodeFailed()) // Only mark corrupted after decode is done
|
||||
{
|
||||
LL_WARNS() << "Marking LLAudioSource corrupted for " << adp->getID() << LL_ENDL;
|
||||
mCorrupted = true ;
|
||||
|
|
@ -1339,7 +1323,7 @@ void LLAudioSource::update()
|
|||
|
||||
void LLAudioSource::updatePriority()
|
||||
{
|
||||
if (isAmbient())
|
||||
if (isForcedPriority())
|
||||
{
|
||||
mPriority = 1.f;
|
||||
}
|
||||
|
|
@ -1624,12 +1608,12 @@ bool LLAudioSource::hasPendingPreloads() const
|
|||
{
|
||||
LLAudioData *adp = iter->second;
|
||||
// note: a bad UUID will forever be !hasDecodedData()
|
||||
// but also !hasValidData(), hence the check for hasValidData()
|
||||
// but also hasDecodeFailed(), hence the check for hasDecodeFailed()
|
||||
if (!adp)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (!adp->hasDecodedData() && adp->hasValidData())
|
||||
if (!adp->hasDecodedData() && !adp->hasDecodeFailed())
|
||||
{
|
||||
// This source is still waiting for a preload
|
||||
return true;
|
||||
|
|
@ -1786,7 +1770,8 @@ LLAudioData::LLAudioData(const LLUUID &uuid) :
|
|||
mHasLocalData(false),
|
||||
mHasDecodedData(false),
|
||||
mHasCompletedDecode(false),
|
||||
mHasValidData(true)
|
||||
mHasDecodeFailed(false),
|
||||
mHasWAVLoadFailed(false)
|
||||
{
|
||||
if (uuid.isNull())
|
||||
{
|
||||
|
|
@ -1821,12 +1806,14 @@ bool LLAudioData::load()
|
|||
{
|
||||
// We already have this sound in a buffer, don't do anything.
|
||||
LL_INFOS() << "Already have a buffer for this sound, don't bother loading!" << LL_ENDL;
|
||||
mHasWAVLoadFailed = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!gAudiop)
|
||||
{
|
||||
LL_WARNS("AudioEngine") << "LLAudioEngine instance doesn't exist!" << LL_ENDL;
|
||||
mHasWAVLoadFailed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1835,6 +1822,8 @@ bool LLAudioData::load()
|
|||
{
|
||||
// No free buffers, abort.
|
||||
LL_INFOS() << "Not able to allocate a new audio buffer, aborting." << LL_ENDL;
|
||||
// *TODO: Mark this failure differently so the audio engine could retry loading this buffer in the future
|
||||
mHasWAVLoadFailed = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1843,7 +1832,8 @@ bool LLAudioData::load()
|
|||
mID.toString(uuid_str);
|
||||
wav_path= gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_str) + ".dsf";
|
||||
|
||||
if (!mBufferp->loadWAV(wav_path))
|
||||
mHasWAVLoadFailed = !mBufferp->loadWAV(wav_path);
|
||||
if (mHasWAVLoadFailed)
|
||||
{
|
||||
// Hrm. Right now, let's unset the buffer, since it's empty.
|
||||
gAudiop->cleanupBuffer(mBufferp);
|
||||
|
|
|
|||
|
|
@ -47,8 +47,8 @@ const F32 LL_WIND_UNDERWATER_CENTER_FREQ = 20.f;
|
|||
const F32 ATTACHED_OBJECT_TIMEOUT = 5.0f;
|
||||
const F32 DEFAULT_MIN_DISTANCE = 2.0f;
|
||||
|
||||
#define MAX_CHANNELS 30
|
||||
#define MAX_BUFFERS 40 // Some extra for preloading, maybe?
|
||||
#define LL_MAX_AUDIO_CHANNELS 30
|
||||
#define LL_MAX_AUDIO_BUFFERS 40 // Some extra for preloading, maybe?
|
||||
|
||||
class LLAudioSource;
|
||||
class LLAudioData;
|
||||
|
|
@ -88,7 +88,7 @@ public:
|
|||
virtual ~LLAudioEngine();
|
||||
|
||||
// initialization/startup/shutdown
|
||||
virtual bool init(const S32 num_channels, void *userdata, const std::string &app_title);
|
||||
virtual bool init(void *userdata, const std::string &app_title);
|
||||
virtual std::string getDriverName(bool verbose) = 0;
|
||||
virtual void shutdown();
|
||||
|
||||
|
|
@ -96,7 +96,7 @@ public:
|
|||
//virtual void processQueue(const LLUUID &sound_guid);
|
||||
virtual void setListener(LLVector3 pos,LLVector3 vel,LLVector3 up,LLVector3 at);
|
||||
virtual void updateWind(LLVector3 direction, F32 camera_height_above_water) = 0;
|
||||
virtual void idle(F32 max_decode_time = 0.f);
|
||||
virtual void idle();
|
||||
virtual void updateChannels();
|
||||
|
||||
//
|
||||
|
|
@ -209,7 +209,6 @@ protected:
|
|||
|
||||
S32 mLastStatus;
|
||||
|
||||
S32 mNumChannels;
|
||||
bool mEnableWind;
|
||||
|
||||
LLUUID mCurrentTransfer; // Audio file currently being transferred by the system
|
||||
|
|
@ -224,11 +223,11 @@ protected:
|
|||
source_map mAllSources;
|
||||
data_map mAllData;
|
||||
|
||||
LLAudioChannel *mChannels[MAX_CHANNELS];
|
||||
std::array<LLAudioChannel*, LL_MAX_AUDIO_CHANNELS> mChannels;
|
||||
|
||||
// Buffers needs to change into a different data structure, as the number of buffers
|
||||
// that we have active should be limited by RAM usage, not count.
|
||||
LLAudioBuffer *mBuffers[MAX_BUFFERS];
|
||||
std::array<LLAudioBuffer*, LL_MAX_AUDIO_BUFFERS> mBuffers;
|
||||
|
||||
F32 mMasterGain;
|
||||
F32 mInternalGain; // Actual gain set; either mMasterGain or 0 when mMuted is true.
|
||||
|
|
@ -266,8 +265,8 @@ public:
|
|||
|
||||
void addAudioData(LLAudioData *adp, bool set_current = TRUE);
|
||||
|
||||
void setAmbient(const bool ambient) { mAmbient = ambient; }
|
||||
bool isAmbient() const { return mAmbient; }
|
||||
void setForcedPriority(const bool ambient) { mForcedPriority = ambient; }
|
||||
bool isForcedPriority() const { return mForcedPriority; }
|
||||
|
||||
void setLoop(const bool loop) { mLoop = loop; }
|
||||
bool isLoop() const { return mLoop; }
|
||||
|
|
@ -326,7 +325,7 @@ protected:
|
|||
F32 mPriority;
|
||||
F32 mGain;
|
||||
bool mSourceMuted;
|
||||
bool mAmbient;
|
||||
bool mForcedPriority; // ignore mute, set high priority, researved for sound preview and UI
|
||||
bool mLoop;
|
||||
bool mSyncMaster;
|
||||
bool mSyncSlave;
|
||||
|
|
@ -360,32 +359,36 @@ protected:
|
|||
|
||||
class LLAudioData
|
||||
{
|
||||
public:
|
||||
LLAudioData(const LLUUID &uuid);
|
||||
bool load();
|
||||
public:
|
||||
LLAudioData(const LLUUID &uuid);
|
||||
bool load();
|
||||
|
||||
LLUUID getID() const { return mID; }
|
||||
LLAudioBuffer *getBuffer() const { return mBufferp; }
|
||||
LLUUID getID() const { return mID; }
|
||||
LLAudioBuffer *getBuffer() const { return mBufferp; }
|
||||
|
||||
bool hasLocalData() const { return mHasLocalData; }
|
||||
bool hasDecodedData() const { return mHasDecodedData; }
|
||||
bool hasCompletedDecode() const { return mHasCompletedDecode; }
|
||||
bool hasValidData() const { return mHasValidData; }
|
||||
bool hasLocalData() const { return mHasLocalData; }
|
||||
bool hasDecodedData() const { return mHasDecodedData; }
|
||||
bool hasCompletedDecode() const { return mHasCompletedDecode; }
|
||||
bool hasDecodeFailed() const { return mHasDecodeFailed; }
|
||||
bool hasWAVLoadFailed() const { return mHasWAVLoadFailed; }
|
||||
|
||||
void setHasLocalData(const bool hld) { mHasLocalData = hld; }
|
||||
void setHasDecodedData(const bool hdd) { mHasDecodedData = hdd; }
|
||||
void setHasCompletedDecode(const bool hcd) { mHasCompletedDecode = hcd; }
|
||||
void setHasValidData(const bool hvd) { mHasValidData = hvd; }
|
||||
void setHasLocalData(const bool hld) { mHasLocalData = hld; }
|
||||
void setHasDecodedData(const bool hdd) { mHasDecodedData = hdd; }
|
||||
void setHasCompletedDecode(const bool hcd) { mHasCompletedDecode = hcd; }
|
||||
void setHasDecodeFailed(const bool hdf) { mHasDecodeFailed = hdf; }
|
||||
void setHasWAVLoadFailed(const bool hwlf) { mHasWAVLoadFailed = hwlf; }
|
||||
|
||||
friend class LLAudioEngine; // Severe laziness, bad.
|
||||
friend class LLAudioEngine; // Severe laziness, bad.
|
||||
|
||||
protected:
|
||||
LLUUID mID;
|
||||
LLAudioBuffer *mBufferp; // If this data is being used by the audio system, a pointer to the buffer will be set here.
|
||||
bool mHasLocalData; // Set true if the sound asset file is available locally
|
||||
bool mHasDecodedData; // Set true if the sound file has been decoded
|
||||
bool mHasCompletedDecode; // Set true when the sound is decoded
|
||||
bool mHasValidData; // Set false if decoding failed, meaning the sound asset is bad
|
||||
protected:
|
||||
LLUUID mID;
|
||||
LLAudioBuffer *mBufferp; // If this data is being used by the audio system, a pointer to the buffer will be set here.
|
||||
bool mHasLocalData; // Set true if the encoded sound asset file is available locally
|
||||
bool mHasDecodedData; // Set true if the decoded sound file is available on disk
|
||||
bool mHasCompletedDecode; // Set true when the sound is decoded
|
||||
bool mHasDecodeFailed; // Set true if decoding failed, meaning the sound asset is bad
|
||||
bool mHasWAVLoadFailed; // Set true if loading the decoded WAV file failed, meaning the sound asset should be decoded instead if
|
||||
// possible
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ static inline bool Check_FMOD_Error(FMOD_RESULT result, const char *string)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool LLAudioEngine_FMODSTUDIO::init(const S32 num_channels, void* userdata, const std::string &app_title)
|
||||
bool LLAudioEngine_FMODSTUDIO::init(void* userdata, const std::string &app_title)
|
||||
{
|
||||
U32 version;
|
||||
FMOD_RESULT result;
|
||||
|
|
@ -86,7 +86,7 @@ bool LLAudioEngine_FMODSTUDIO::init(const S32 num_channels, void* userdata, cons
|
|||
return false;
|
||||
|
||||
//will call LLAudioEngine_FMODSTUDIO::allocateListener, which needs a valid mSystem pointer.
|
||||
LLAudioEngine::init(num_channels, userdata, app_title);
|
||||
LLAudioEngine::init(userdata, app_title);
|
||||
|
||||
result = mSystem->getVersion(&version);
|
||||
Check_FMOD_Error(result, "FMOD::System::getVersion");
|
||||
|
|
@ -98,7 +98,7 @@ bool LLAudioEngine_FMODSTUDIO::init(const S32 num_channels, void* userdata, cons
|
|||
}
|
||||
|
||||
// In this case, all sounds, PLUS wind and stream will be software.
|
||||
result = mSystem->setSoftwareChannels(num_channels + 2);
|
||||
result = mSystem->setSoftwareChannels(LL_MAX_AUDIO_CHANNELS + 2);
|
||||
Check_FMOD_Error(result, "FMOD::System::setSoftwareChannels");
|
||||
|
||||
FMOD_ADVANCEDSETTINGS settings;
|
||||
|
|
@ -127,7 +127,7 @@ bool LLAudioEngine_FMODSTUDIO::init(const S32 num_channels, void* userdata, cons
|
|||
{
|
||||
LL_DEBUGS("AppInit") << "Trying PulseAudio audio output..." << LL_ENDL;
|
||||
if (mSystem->setOutput(FMOD_OUTPUTTYPE_PULSEAUDIO) == FMOD_OK &&
|
||||
(result = mSystem->init(num_channels + 2, fmod_flags, const_cast<char*>(app_title.c_str()))) == FMOD_OK)
|
||||
(result = mSystem->init(LL_MAX_AUDIO_CHANNELS + 2, fmod_flags, const_cast<char*>(app_title.c_str()))) == FMOD_OK)
|
||||
{
|
||||
LL_DEBUGS("AppInit") << "PulseAudio output initialized OKAY" << LL_ENDL;
|
||||
audio_ok = true;
|
||||
|
|
@ -149,7 +149,7 @@ bool LLAudioEngine_FMODSTUDIO::init(const S32 num_channels, void* userdata, cons
|
|||
{
|
||||
LL_DEBUGS("AppInit") << "Trying ALSA audio output..." << LL_ENDL;
|
||||
if (mSystem->setOutput(FMOD_OUTPUTTYPE_ALSA) == FMOD_OK &&
|
||||
(result = mSystem->init(num_channels + 2, fmod_flags, 0)) == FMOD_OK)
|
||||
(result = mSystem->init(LL_MAX_AUDIO_CHANNELS + 2, fmod_flags, 0)) == FMOD_OK)
|
||||
{
|
||||
LL_DEBUGS("AppInit") << "ALSA audio output initialized OKAY" << LL_ENDL;
|
||||
audio_ok = true;
|
||||
|
|
@ -190,7 +190,7 @@ bool LLAudioEngine_FMODSTUDIO::init(const S32 num_channels, void* userdata, cons
|
|||
// initialize the FMOD engine
|
||||
// number of channel in this case looks to be identiacal to number of max simultaneously
|
||||
// playing objects and we can set practically any number
|
||||
result = mSystem->init(num_channels + 2, fmod_flags, 0);
|
||||
result = mSystem->init(LL_MAX_AUDIO_CHANNELS + 2, fmod_flags, 0);
|
||||
if (Check_FMOD_Error(result, "Error initializing FMOD Studio with default settins, retrying with other format"))
|
||||
{
|
||||
result = mSystem->setSoftwareFormat(44100, FMOD_SPEAKERMODE_STEREO, 0/*- ignore*/);
|
||||
|
|
@ -198,7 +198,7 @@ bool LLAudioEngine_FMODSTUDIO::init(const S32 num_channels, void* userdata, cons
|
|||
{
|
||||
return false;
|
||||
}
|
||||
result = mSystem->init(num_channels + 2, fmod_flags, 0);
|
||||
result = mSystem->init(LL_MAX_AUDIO_CHANNELS + 2, fmod_flags, 0);
|
||||
}
|
||||
if (Check_FMOD_Error(result, "Error initializing FMOD Studio"))
|
||||
{
|
||||
|
|
@ -519,9 +519,9 @@ void LLAudioChannelFMODSTUDIO::update3DPosition()
|
|||
return;
|
||||
}
|
||||
|
||||
if (mCurrentSourcep->isAmbient())
|
||||
if (mCurrentSourcep->isForcedPriority())
|
||||
{
|
||||
// Ambient sound, don't need to do any positional updates.
|
||||
// Prioritized UI and preview sounds don't need to do any positional updates.
|
||||
set3DMode(false);
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ public:
|
|||
virtual ~LLAudioEngine_FMODSTUDIO();
|
||||
|
||||
// initialization/startup/shutdown
|
||||
virtual bool init(const S32 num_channels, void *user_data, const std::string &app_title);
|
||||
virtual bool init(void *user_data, const std::string &app_title);
|
||||
virtual std::string getDriverName(bool verbose);
|
||||
virtual void allocateListener();
|
||||
|
||||
|
|
|
|||
|
|
@ -52,10 +52,10 @@ LLAudioEngine_OpenAL::~LLAudioEngine_OpenAL()
|
|||
}
|
||||
|
||||
// virtual
|
||||
bool LLAudioEngine_OpenAL::init(const S32 num_channels, void* userdata, const std::string &app_title)
|
||||
bool LLAudioEngine_OpenAL::init(void* userdata, const std::string &app_title)
|
||||
{
|
||||
mWindGen = NULL;
|
||||
LLAudioEngine::init(num_channels, userdata, app_title);
|
||||
LLAudioEngine::init(userdata, app_title);
|
||||
|
||||
if(!alutInit(NULL, NULL))
|
||||
{
|
||||
|
|
@ -297,7 +297,7 @@ void LLAudioChannelOpenAL::update3DPosition()
|
|||
{
|
||||
return;
|
||||
}
|
||||
if (mCurrentSourcep->isAmbient())
|
||||
if (mCurrentSourcep->isForcedPriority())
|
||||
{
|
||||
alSource3f(mALSource, AL_POSITION, 0.0, 0.0, 0.0);
|
||||
alSource3f(mALSource, AL_VELOCITY, 0.0, 0.0, 0.0);
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ class LLAudioEngine_OpenAL : public LLAudioEngine
|
|||
LLAudioEngine_OpenAL();
|
||||
virtual ~LLAudioEngine_OpenAL();
|
||||
|
||||
virtual bool init(const S32 num_channels, void *user_data, const std::string &app_title);
|
||||
virtual bool init(void *user_data, const std::string &app_title);
|
||||
virtual std::string getDriverName(bool verbose);
|
||||
virtual void allocateListener();
|
||||
|
||||
|
|
|
|||
|
|
@ -70,7 +70,11 @@ mRetryCount(0)
|
|||
// Must be larger than the usual Second Life frame stutter time.
|
||||
const U32 buffer_seconds = 10; //sec
|
||||
const U32 estimated_bitrate = 128; //kbit/sec
|
||||
mSystem->setStreamBufferSize(estimated_bitrate * buffer_seconds * 128/*bytes/kbit*/, FMOD_TIMEUNIT_RAWBYTES);
|
||||
FMOD_RESULT result = mSystem->setStreamBufferSize(estimated_bitrate * buffer_seconds * 128/*bytes/kbit*/, FMOD_TIMEUNIT_RAWBYTES);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
LL_WARNS("FMOD") << "setStreamBufferSize error: " << FMOD_ErrorString(result) << LL_ENDL;
|
||||
}
|
||||
|
||||
// Here's where we set the size of the network buffer and some buffering
|
||||
// parameters. In this case we want a network buffer of 16k, we want it
|
||||
|
|
@ -134,7 +138,7 @@ void LLStreamingAudio_FMODSTUDIO::killDeadStreams()
|
|||
{
|
||||
LL_INFOS("FMOD") << "Closed dead stream" << LL_ENDL;
|
||||
delete streamp;
|
||||
mDeadStreams.erase(iter++);
|
||||
iter = mDeadStreams.erase(iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -404,7 +408,11 @@ FMOD::Channel *LLAudioStreamManagerFMODSTUDIO::startStream()
|
|||
if (mStreamChannel)
|
||||
return mStreamChannel; //Already have a channel for this stream.
|
||||
|
||||
mSystem->playSound(mInternetStream, NULL, true, &mStreamChannel);
|
||||
FMOD_RESULT result = mSystem->playSound(mInternetStream, NULL, true, &mStreamChannel);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
LL_WARNS("FMOD") << FMOD_ErrorString(result) << LL_ENDL;
|
||||
}
|
||||
return mStreamChannel;
|
||||
}
|
||||
|
||||
|
|
@ -445,16 +453,29 @@ bool LLAudioStreamManagerFMODSTUDIO::stopStream()
|
|||
FMOD_OPENSTATE LLAudioStreamManagerFMODSTUDIO::getOpenState(unsigned int* percentbuffered, bool* starving, bool* diskbusy)
|
||||
{
|
||||
FMOD_OPENSTATE state;
|
||||
mInternetStream->getOpenState(&state, percentbuffered, starving, diskbusy);
|
||||
FMOD_RESULT result = mInternetStream->getOpenState(&state, percentbuffered, starving, diskbusy);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
LL_WARNS("FMOD") << FMOD_ErrorString(result) << LL_ENDL;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
void LLStreamingAudio_FMODSTUDIO::setBufferSizes(U32 streambuffertime, U32 decodebuffertime)
|
||||
{
|
||||
mSystem->setStreamBufferSize(streambuffertime / 1000 * 128 * 128, FMOD_TIMEUNIT_RAWBYTES);
|
||||
FMOD_RESULT result = mSystem->setStreamBufferSize(streambuffertime / 1000 * 128 * 128, FMOD_TIMEUNIT_RAWBYTES);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
LL_WARNS("FMOD") << "setStreamBufferSize error: " << FMOD_ErrorString(result) << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
FMOD_ADVANCEDSETTINGS settings;
|
||||
memset(&settings, 0, sizeof(settings));
|
||||
settings.cbSize = sizeof(settings);
|
||||
settings.defaultDecodeBufferSize = decodebuffertime;//ms
|
||||
mSystem->setAdvancedSettings(&settings);
|
||||
result = mSystem->setAdvancedSettings(&settings);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
LL_WARNS("FMOD") << "setAdvancedSettings error: " << FMOD_ErrorString(result) << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,6 +44,14 @@ using namespace std;
|
|||
|
||||
#define INCHES_TO_METERS 0.02540005f
|
||||
|
||||
/// The .bvh does not have a formal spec, and different readers interpret things in their own way.
|
||||
/// In OUR usage, frame 0 is used in optimization and is not considered to be part of the animation.
|
||||
const S32 NUMBER_OF_IGNORED_FRAMES_AT_START = 1;
|
||||
/// In our usage, the last frame is used only to indicate what the penultimate frame should be interpolated towards.
|
||||
/// I.e., the animation only plays up to the start of the last frame. There is no hold or exptrapolation past that point..
|
||||
/// Thus there are two frame of the total that do not contribute to the total running time of the animation.
|
||||
const S32 NUMBER_OF_UNPLAYED_FRAMES = NUMBER_OF_IGNORED_FRAMES_AT_START + 1;
|
||||
|
||||
const F32 POSITION_KEYFRAME_THRESHOLD_SQUARED = 0.03f * 0.03f;
|
||||
const F32 ROTATION_KEYFRAME_THRESHOLD = 0.01f;
|
||||
|
||||
|
|
@ -865,7 +873,10 @@ ELoadStatus LLBVHLoader::loadBVHFile(const char *buffer, char* error_text, S32 &
|
|||
return E_ST_NO_FRAME_TIME;
|
||||
}
|
||||
|
||||
mDuration = (F32)mNumFrames * mFrameTime;
|
||||
// If the user only supplies one animation frame (after the ignored reference frame 0), hold for mFrameTime.
|
||||
// If the user supples exactly one total frame, it isn't clear if that is a pose or reference frame, and the
|
||||
// behavior is not defined. In this case, retain historical undefined behavior.
|
||||
mDuration = llmax((F32)(mNumFrames - NUMBER_OF_UNPLAYED_FRAMES), 1.0f) * mFrameTime;
|
||||
if (!mLoop)
|
||||
{
|
||||
mLoopOutPoint = mDuration;
|
||||
|
|
@ -1355,12 +1366,13 @@ BOOL LLBVHLoader::serialize(LLDataPacker& dp)
|
|||
|
||||
LLQuaternion::Order order = bvhStringToOrder( joint->mOrder );
|
||||
S32 outcount = 0;
|
||||
S32 frame = 1;
|
||||
S32 frame = 0;
|
||||
for ( ki = joint->mKeys.begin();
|
||||
ki != joint->mKeys.end();
|
||||
++ki )
|
||||
{
|
||||
if ((frame == 1) && joint->mRelativeRotationKey)
|
||||
|
||||
if ((frame == 0) && joint->mRelativeRotationKey)
|
||||
{
|
||||
first_frame_rot = mayaQ( ki->mRot[0], ki->mRot[1], ki->mRot[2], order);
|
||||
|
||||
|
|
@ -1373,7 +1385,7 @@ BOOL LLBVHLoader::serialize(LLDataPacker& dp)
|
|||
continue;
|
||||
}
|
||||
|
||||
time = (F32)frame * mFrameTime;
|
||||
time = llmax((F32)(frame - NUMBER_OF_IGNORED_FRAMES_AT_START), 0.0f) * mFrameTime; // Time elapsed before this frame starts.
|
||||
|
||||
if (mergeParent)
|
||||
{
|
||||
|
|
@ -1433,12 +1445,12 @@ BOOL LLBVHLoader::serialize(LLDataPacker& dp)
|
|||
LLVector3 relPos = joint->mRelativePosition;
|
||||
LLVector3 relKey;
|
||||
|
||||
frame = 1;
|
||||
frame = 0;
|
||||
for ( ki = joint->mKeys.begin();
|
||||
ki != joint->mKeys.end();
|
||||
++ki )
|
||||
{
|
||||
if ((frame == 1) && joint->mRelativePositionKey)
|
||||
if ((frame == 0) && joint->mRelativePositionKey)
|
||||
{
|
||||
relKey.setVec(ki->mPos);
|
||||
}
|
||||
|
|
@ -1449,7 +1461,7 @@ BOOL LLBVHLoader::serialize(LLDataPacker& dp)
|
|||
continue;
|
||||
}
|
||||
|
||||
time = (F32)frame * mFrameTime;
|
||||
time = llmax((F32)(frame - NUMBER_OF_IGNORED_FRAMES_AT_START), 0.0f) * mFrameTime; // Time elapsed before this frame starts.
|
||||
|
||||
LLVector3 inPos = (LLVector3(ki->mPos) - relKey) * ~first_frame_rot;// * fixup_rot;
|
||||
LLVector3 outPos = inPos * frameRot * offsetRot;
|
||||
|
|
|
|||
|
|
@ -1222,8 +1222,11 @@ void LLKeyframeMotion::applyConstraint(JointConstraint* constraint, F32 time, U8
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
// deserialize()
|
||||
//
|
||||
// allow_invalid_joints should be true when handling existing content, to avoid breakage.
|
||||
// During upload, we should be more restrictive and reject such animations.
|
||||
//-----------------------------------------------------------------------------
|
||||
BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp, const LLUUID& asset_id)
|
||||
BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp, const LLUUID& asset_id, bool allow_invalid_joints)
|
||||
{
|
||||
BOOL old_version = FALSE;
|
||||
mJointMotionList = new LLKeyframeMotion::JointMotionList;
|
||||
|
|
@ -1344,6 +1347,15 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp, const LLUUID& asset_id)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
//SL-17206 hack to alter Female_land loop setting, while current behavior won't be changed serverside
|
||||
LLUUID const female_land_anim("ca1baf4d-0a18-5a1f-0330-e4bd1e71f09e");
|
||||
LLUUID const formal_female_land_anim("6a9a173b-61fa-3ad5-01fa-a851cfc5f66a");
|
||||
if (female_land_anim == asset_id || formal_female_land_anim == asset_id)
|
||||
{
|
||||
LL_WARNS() << "Animation(" << asset_id << ") won't be looped." << LL_ENDL;
|
||||
mJointMotionList->mLoop = FALSE;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// get easeIn and easeOut
|
||||
//-------------------------------------------------------------------------
|
||||
|
|
@ -1443,6 +1455,7 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp, const LLUUID& asset_id)
|
|||
if (joint)
|
||||
{
|
||||
S32 joint_num = joint->getJointNum();
|
||||
joint_name = joint->getName(); // canonical name in case this is an alias.
|
||||
// LL_INFOS() << " joint: " << joint_name << LL_ENDL;
|
||||
if ((joint_num >= (S32)LL_CHARACTER_MAX_ANIMATED_JOINTS) || (joint_num < 0))
|
||||
{
|
||||
|
|
@ -1457,7 +1470,10 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp, const LLUUID& asset_id)
|
|||
{
|
||||
LL_WARNS() << "invalid joint name: " << joint_name
|
||||
<< " for animation " << asset_id << LL_ENDL;
|
||||
//return FALSE;
|
||||
if (!allow_invalid_joints)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
joint_motion->mJointName = joint_name;
|
||||
|
|
@ -2096,8 +2112,9 @@ U32 LLKeyframeMotion::getFileSize()
|
|||
//-----------------------------------------------------------------------------
|
||||
// dumpToFile()
|
||||
//-----------------------------------------------------------------------------
|
||||
void LLKeyframeMotion::dumpToFile(const std::string& name)
|
||||
bool LLKeyframeMotion::dumpToFile(const std::string& name)
|
||||
{
|
||||
bool succ = false;
|
||||
if (isLoaded())
|
||||
{
|
||||
std::string outfile_base;
|
||||
|
|
@ -2114,10 +2131,24 @@ void LLKeyframeMotion::dumpToFile(const std::string& name)
|
|||
const LLUUID& id = getID();
|
||||
outfile_base = id.asString();
|
||||
}
|
||||
std::string outfilename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,outfile_base + ".anim");
|
||||
|
||||
if (gDirUtilp->getExtension(outfile_base).empty())
|
||||
{
|
||||
outfile_base += ".anim";
|
||||
}
|
||||
std::string outfilename;
|
||||
if (gDirUtilp->getDirName(outfile_base).empty())
|
||||
{
|
||||
outfilename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,outfile_base);
|
||||
}
|
||||
else
|
||||
{
|
||||
outfilename = outfile_base;
|
||||
}
|
||||
if (LLFile::isfile(outfilename))
|
||||
{
|
||||
return;
|
||||
LL_WARNS() << outfilename << " already exists, write failed" << LL_ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
S32 file_size = getFileSize();
|
||||
|
|
@ -2131,11 +2162,13 @@ void LLKeyframeMotion::dumpToFile(const std::string& name)
|
|||
outfile.open(outfilename, LL_APR_WPB);
|
||||
if (outfile.getFileHandle())
|
||||
{
|
||||
outfile.write(buffer, file_size);
|
||||
S32 wrote_bytes = outfile.write(buffer, file_size);
|
||||
succ = (wrote_bytes == file_size);
|
||||
}
|
||||
}
|
||||
delete [] buffer;
|
||||
}
|
||||
return succ;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -156,9 +156,9 @@ public:
|
|||
public:
|
||||
U32 getFileSize();
|
||||
BOOL serialize(LLDataPacker& dp) const;
|
||||
BOOL deserialize(LLDataPacker& dp, const LLUUID& asset_id);
|
||||
BOOL deserialize(LLDataPacker& dp, const LLUUID& asset_id, bool allow_invalid_joints = true);
|
||||
BOOL isLoaded() { return mJointMotionList != NULL; }
|
||||
void dumpToFile(const std::string& name);
|
||||
bool dumpToFile(const std::string& name);
|
||||
|
||||
|
||||
// setters for modifying a keyframe animation
|
||||
|
|
@ -432,6 +432,9 @@ protected:
|
|||
F32 mLastUpdateTime;
|
||||
F32 mLastLoopedTime;
|
||||
AssetStatus mAssetStatus;
|
||||
|
||||
public:
|
||||
void setCharacter(LLCharacter* character) { mCharacter = character; }
|
||||
};
|
||||
|
||||
class LLKeyframeDataCache
|
||||
|
|
|
|||
|
|
@ -266,6 +266,11 @@ set(llcommon_HEADER_FILES
|
|||
workqueue.h
|
||||
StackWalker.h
|
||||
)
|
||||
|
||||
if (DARWIN)
|
||||
list(APPEND llcommon_HEADER_FILES llsys_objc.h)
|
||||
list(APPEND llcommon_SOURCE_FILES llsys_objc.mm)
|
||||
endif (DARWIN)
|
||||
|
||||
set_source_files_properties(${llcommon_HEADER_FILES}
|
||||
PROPERTIES HEADER_FILE_ONLY TRUE)
|
||||
|
|
@ -313,12 +318,6 @@ target_link_libraries(
|
|||
${TRACY_LIBRARY}
|
||||
)
|
||||
|
||||
if (DARWIN)
|
||||
include(CMakeFindFrameworks)
|
||||
find_library(CARBON_LIBRARY Carbon)
|
||||
target_link_libraries(llcommon ${CARBON_LIBRARY})
|
||||
endif (DARWIN)
|
||||
|
||||
add_dependencies(llcommon stage_third_party_libs)
|
||||
|
||||
if (LL_TESTS)
|
||||
|
|
|
|||
|
|
@ -116,14 +116,20 @@ void LLAlignedArray<T, alignment>::resize(U32 size)
|
|||
template <class T, U32 alignment>
|
||||
T& LLAlignedArray<T, alignment>::operator[](int idx)
|
||||
{
|
||||
llassert(idx < mElementCount);
|
||||
if(idx >= mElementCount || idx < 0)
|
||||
{
|
||||
LL_ERRS() << "Out of bounds LLAlignedArray, requested: " << (S32)idx << " size: " << mElementCount << LL_ENDL;
|
||||
}
|
||||
return mArray[idx];
|
||||
}
|
||||
|
||||
template <class T, U32 alignment>
|
||||
const T& LLAlignedArray<T, alignment>::operator[](int idx) const
|
||||
{
|
||||
llassert(idx < mElementCount);
|
||||
if (idx >= mElementCount || idx < 0)
|
||||
{
|
||||
LL_ERRS() << "Out of bounds LLAlignedArray, requested: " << (S32)idx << " size: " << mElementCount << LL_ENDL;
|
||||
}
|
||||
return mArray[idx];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
// STL headers
|
||||
// std headers
|
||||
#include <atomic>
|
||||
#include <stdexcept>
|
||||
// external library headers
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/fiber/fiber.hpp>
|
||||
|
|
@ -214,6 +215,22 @@ std::string LLCoros::logname()
|
|||
return data.mName.empty()? data.getKey() : data.mName;
|
||||
}
|
||||
|
||||
void LLCoros::saveException(const std::string& name, std::exception_ptr exc)
|
||||
{
|
||||
mExceptionQueue.emplace(name, exc);
|
||||
}
|
||||
|
||||
void LLCoros::rethrow()
|
||||
{
|
||||
if (! mExceptionQueue.empty())
|
||||
{
|
||||
ExceptionData front = mExceptionQueue.front();
|
||||
mExceptionQueue.pop();
|
||||
LL_WARNS("LLCoros") << "Rethrowing exception from coroutine " << front.name << LL_ENDL;
|
||||
std::rethrow_exception(front.exception);
|
||||
}
|
||||
}
|
||||
|
||||
void LLCoros::setStackSize(S32 stacksize)
|
||||
{
|
||||
LL_DEBUGS("LLCoros") << "Setting coroutine stack size to " << stacksize << LL_ENDL;
|
||||
|
|
@ -302,11 +319,11 @@ U32 cpp_exception_filter(U32 code, struct _EXCEPTION_POINTERS *exception_infop,
|
|||
}
|
||||
}
|
||||
|
||||
void LLCoros::winlevel(const std::string& name, const callable_t& callable)
|
||||
void LLCoros::sehHandle(const std::string& name, const LLCoros::callable_t& callable)
|
||||
{
|
||||
__try
|
||||
{
|
||||
toplevelTryWrapper(name, callable);
|
||||
LLCoros::toplevelTryWrapper(name, callable);
|
||||
}
|
||||
__except (cpp_exception_filter(GetExceptionCode(), GetExceptionInformation(), name))
|
||||
{
|
||||
|
|
@ -321,7 +338,6 @@ void LLCoros::winlevel(const std::string& name, const callable_t& callable)
|
|||
throw std::exception(integer_string);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void LLCoros::toplevelTryWrapper(const std::string& name, const callable_t& callable)
|
||||
|
|
@ -350,11 +366,19 @@ void LLCoros::toplevelTryWrapper(const std::string& name, const callable_t& call
|
|||
}
|
||||
catch (...)
|
||||
{
|
||||
#if LL_WINDOWS
|
||||
// Any OTHER kind of uncaught exception will cause the viewer to
|
||||
// crash, hopefully informatively.
|
||||
// crash, SEH handling should catch it and report to bugsplat.
|
||||
LOG_UNHANDLED_EXCEPTION(STRINGIZE("coroutine " << name));
|
||||
// to not modify callstack
|
||||
throw;
|
||||
#else
|
||||
// Stash any OTHER kind of uncaught exception in the rethrow() queue
|
||||
// to be rethrown by the main fiber.
|
||||
LL_WARNS("LLCoros") << "Capturing uncaught exception in coroutine "
|
||||
<< name << LL_ENDL;
|
||||
LLCoros::instance().saveException(name, std::current_exception());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -364,8 +388,9 @@ void LLCoros::toplevelTryWrapper(const std::string& name, const callable_t& call
|
|||
void LLCoros::toplevel(std::string name, callable_t callable)
|
||||
{
|
||||
#if LL_WINDOWS
|
||||
// Can not use __try in functions that require unwinding, so use one more wrapper
|
||||
winlevel(name, callable);
|
||||
// Because SEH can's have unwinding, need to call a wrapper
|
||||
// 'try' is inside SEH handling to not catch LLContinue
|
||||
sehHandle(name, callable);
|
||||
#else
|
||||
toplevelTryWrapper(name, callable);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -38,6 +38,8 @@
|
|||
#include "llinstancetracker.h"
|
||||
#include <boost/function.hpp>
|
||||
#include <string>
|
||||
#include <exception>
|
||||
#include <queue>
|
||||
|
||||
// e.g. #include LLCOROS_MUTEX_HEADER
|
||||
#define LLCOROS_MUTEX_HEADER <boost/fiber/mutex.hpp>
|
||||
|
|
@ -156,6 +158,19 @@ public:
|
|||
* LLCoros::launch()).
|
||||
*/
|
||||
static std::string getName();
|
||||
|
||||
/**
|
||||
* rethrow() is called by the thread's main fiber to propagate an
|
||||
* exception from any coroutine into the main fiber, where it can engage
|
||||
* the normal unhandled-exception machinery, up to and including crash
|
||||
* reporting.
|
||||
*
|
||||
* LLCoros maintains a queue of otherwise-uncaught exceptions from
|
||||
* terminated coroutines. Each call to rethrow() pops the first of those
|
||||
* and rethrows it. When the queue is empty (normal case), rethrow() is a
|
||||
* no-op.
|
||||
*/
|
||||
void rethrow();
|
||||
|
||||
/**
|
||||
* This variation returns a name suitable for log messages: the explicit
|
||||
|
|
@ -292,13 +307,27 @@ public:
|
|||
|
||||
private:
|
||||
std::string generateDistinctName(const std::string& prefix) const;
|
||||
#if LL_WINDOWS
|
||||
void winlevel(const std::string& name, const callable_t& callable);
|
||||
#endif
|
||||
void toplevelTryWrapper(const std::string& name, const callable_t& callable);
|
||||
void toplevel(std::string name, callable_t callable);
|
||||
#if LL_WINDOWS
|
||||
void sehHandle(const std::string& name, const callable_t& callable); // calls toplevelTryWrapper
|
||||
#endif
|
||||
void toplevel(std::string name, callable_t callable); // calls sehHandle or toplevelTryWrapper
|
||||
struct CoroData;
|
||||
static CoroData& get_CoroData(const std::string& caller);
|
||||
void saveException(const std::string& name, std::exception_ptr exc);
|
||||
|
||||
struct ExceptionData
|
||||
{
|
||||
ExceptionData(const std::string& nm, std::exception_ptr exc):
|
||||
name(nm),
|
||||
exception(exc)
|
||||
{}
|
||||
// name of coroutine that originally threw this exception
|
||||
std::string name;
|
||||
// the thrown exception
|
||||
std::exception_ptr exception;
|
||||
};
|
||||
std::queue<ExceptionData> mExceptionQueue;
|
||||
|
||||
S32 mStackSize;
|
||||
|
||||
|
|
|
|||
|
|
@ -212,11 +212,9 @@ U64 LLMemory::getCurrentRSS()
|
|||
mach_msg_type_number_t basicInfoCount = MACH_TASK_BASIC_INFO_COUNT;
|
||||
if (task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&basicInfo, &basicInfoCount) == KERN_SUCCESS)
|
||||
{
|
||||
// residentSize = basicInfo.resident_size;
|
||||
// Although this method is defined to return the "resident set size,"
|
||||
// in fact what callers want from it is the total virtual memory
|
||||
// consumed by the application.
|
||||
residentSize = basicInfo.virtual_size;
|
||||
residentSize = basicInfo.resident_size;
|
||||
// 64-bit macos apps allocate 32 GB or more at startup, and this is reflected in virtual_size.
|
||||
// basicInfo.virtual_size is not what we want.
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -118,7 +118,11 @@ namespace
|
|||
eMONTIOR_MWAIT=33,
|
||||
eCPLDebugStore=34,
|
||||
eThermalMonitor2=35,
|
||||
eAltivec=36
|
||||
eAltivec=36,
|
||||
eSSE3S_Features = 37,
|
||||
eSSE4_1_Features = 38,
|
||||
eSSE4_2_Features = 39,
|
||||
eSSE4a_Features = 40,
|
||||
};
|
||||
|
||||
const char* cpu_feature_names[] =
|
||||
|
|
@ -161,7 +165,11 @@ namespace
|
|||
"CPL Qualified Debug Store",
|
||||
"Thermal Monitor 2",
|
||||
|
||||
"Altivec"
|
||||
"Altivec",
|
||||
"SSE3S Instructions",
|
||||
"SSE4.1 Instructions",
|
||||
"SSE4.2 Instructions",
|
||||
"SSE4a Instructions",
|
||||
};
|
||||
|
||||
std::string intel_CPUFamilyName(int composed_family)
|
||||
|
|
@ -250,6 +258,31 @@ public:
|
|||
return hasExtension(cpu_feature_names[eSSE2_Ext]);
|
||||
}
|
||||
|
||||
bool hasSSE3() const
|
||||
{
|
||||
return hasExtension(cpu_feature_names[eSSE3_Features]);
|
||||
}
|
||||
|
||||
bool hasSSE3S() const
|
||||
{
|
||||
return hasExtension(cpu_feature_names[eSSE3S_Features]);
|
||||
}
|
||||
|
||||
bool hasSSE41() const
|
||||
{
|
||||
return hasExtension(cpu_feature_names[eSSE4_1_Features]);
|
||||
}
|
||||
|
||||
bool hasSSE42() const
|
||||
{
|
||||
return hasExtension(cpu_feature_names[eSSE4_2_Features]);
|
||||
}
|
||||
|
||||
bool hasSSE4a() const
|
||||
{
|
||||
return hasExtension(cpu_feature_names[eSSE4a_Features]);
|
||||
}
|
||||
|
||||
bool hasAltivec() const
|
||||
{
|
||||
return hasExtension("Altivec");
|
||||
|
|
@ -473,6 +506,12 @@ private:
|
|||
*((int*)(cpu_vendor+4)) = cpu_info[3];
|
||||
*((int*)(cpu_vendor+8)) = cpu_info[2];
|
||||
setInfo(eVendor, cpu_vendor);
|
||||
std::string cmp_vendor(cpu_vendor);
|
||||
bool is_amd = false;
|
||||
if (cmp_vendor == "AuthenticAMD")
|
||||
{
|
||||
is_amd = true;
|
||||
}
|
||||
|
||||
// Get the information associated with each valid Id
|
||||
for(unsigned int i=0; i<=ids; ++i)
|
||||
|
|
@ -504,6 +543,7 @@ private:
|
|||
|
||||
if(cpu_info[2] & 0x8)
|
||||
{
|
||||
// intel specific SSE3 suplements
|
||||
setExtension(cpu_feature_names[eMONTIOR_MWAIT]);
|
||||
}
|
||||
|
||||
|
|
@ -516,7 +556,22 @@ private:
|
|||
{
|
||||
setExtension(cpu_feature_names[eThermalMonitor2]);
|
||||
}
|
||||
|
||||
|
||||
if (cpu_info[2] & 0x200)
|
||||
{
|
||||
setExtension(cpu_feature_names[eSSE3S_Features]);
|
||||
}
|
||||
|
||||
if (cpu_info[2] & 0x80000)
|
||||
{
|
||||
setExtension(cpu_feature_names[eSSE4_1_Features]);
|
||||
}
|
||||
|
||||
if (cpu_info[2] & 0x100000)
|
||||
{
|
||||
setExtension(cpu_feature_names[eSSE4_2_Features]);
|
||||
}
|
||||
|
||||
unsigned int feature_info = (unsigned int) cpu_info[3];
|
||||
for(unsigned int index = 0, bit = 1; index < eSSE3_Features; ++index, bit <<= 1)
|
||||
{
|
||||
|
|
@ -543,8 +598,17 @@ private:
|
|||
__cpuid(cpu_info, i);
|
||||
|
||||
// Interpret CPU brand string and cache information.
|
||||
if (i == 0x80000002)
|
||||
memcpy(cpu_brand_string, cpu_info, sizeof(cpu_info));
|
||||
if (i == 0x80000001)
|
||||
{
|
||||
if (is_amd)
|
||||
{
|
||||
setExtension(cpu_feature_names[eSSE4a_Features]);
|
||||
}
|
||||
}
|
||||
else if (i == 0x80000002)
|
||||
{
|
||||
memcpy(cpu_brand_string, cpu_info, sizeof(cpu_info));
|
||||
}
|
||||
else if (i == 0x80000003)
|
||||
memcpy(cpu_brand_string + 16, cpu_info, sizeof(cpu_info));
|
||||
else if (i == 0x80000004)
|
||||
|
|
@ -690,6 +754,41 @@ private:
|
|||
uint64_t ext_feature_info = getSysctlInt64("machdep.cpu.extfeature_bits");
|
||||
S32 *ext_feature_infos = (S32*)(&ext_feature_info);
|
||||
setConfig(eExtFeatureBits, ext_feature_infos[0]);
|
||||
|
||||
|
||||
char cpu_features[1024];
|
||||
len = sizeof(cpu_features);
|
||||
memset(cpu_features, 0, len);
|
||||
sysctlbyname("machdep.cpu.features", (void*)cpu_features, &len, NULL, 0);
|
||||
|
||||
std::string cpu_features_str(cpu_features);
|
||||
cpu_features_str = " " + cpu_features_str + " ";
|
||||
|
||||
if (cpu_features_str.find(" SSE3 ") != std::string::npos)
|
||||
{
|
||||
setExtension(cpu_feature_names[eSSE3_Features]);
|
||||
}
|
||||
|
||||
if (cpu_features_str.find(" SSSE3 ") != std::string::npos)
|
||||
{
|
||||
setExtension(cpu_feature_names[eSSE3S_Features]);
|
||||
}
|
||||
|
||||
if (cpu_features_str.find(" SSE4.1 ") != std::string::npos)
|
||||
{
|
||||
setExtension(cpu_feature_names[eSSE4_1_Features]);
|
||||
}
|
||||
|
||||
if (cpu_features_str.find(" SSE4.2 ") != std::string::npos)
|
||||
{
|
||||
setExtension(cpu_feature_names[eSSE4_2_Features]);
|
||||
}
|
||||
|
||||
if (cpu_features_str.find(" SSE4A ") != std::string::npos)
|
||||
{
|
||||
// Not supposed to happen?
|
||||
setExtension(cpu_feature_names[eSSE4a_Features]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -800,6 +899,31 @@ private:
|
|||
{
|
||||
setExtension(cpu_feature_names[eSSE2_Ext]);
|
||||
}
|
||||
|
||||
if (flags.find(" pni ") != std::string::npos)
|
||||
{
|
||||
setExtension(cpu_feature_names[eSSE3_Features]);
|
||||
}
|
||||
|
||||
if (flags.find(" ssse3 ") != std::string::npos)
|
||||
{
|
||||
setExtension(cpu_feature_names[eSSE3S_Features]);
|
||||
}
|
||||
|
||||
if (flags.find(" sse4_1 ") != std::string::npos)
|
||||
{
|
||||
setExtension(cpu_feature_names[eSSE4_1_Features]);
|
||||
}
|
||||
|
||||
if (flags.find(" sse4_2 ") != std::string::npos)
|
||||
{
|
||||
setExtension(cpu_feature_names[eSSE4_2_Features]);
|
||||
}
|
||||
|
||||
if (flags.find(" sse4a ") != std::string::npos)
|
||||
{
|
||||
setExtension(cpu_feature_names[eSSE4a_Features]);
|
||||
}
|
||||
|
||||
# endif // LL_X86
|
||||
}
|
||||
|
|
@ -860,6 +984,11 @@ LLProcessorInfo::~LLProcessorInfo() {}
|
|||
F64MegahertzImplicit LLProcessorInfo::getCPUFrequency() const { return mImpl->getCPUFrequency(); }
|
||||
bool LLProcessorInfo::hasSSE() const { return mImpl->hasSSE(); }
|
||||
bool LLProcessorInfo::hasSSE2() const { return mImpl->hasSSE2(); }
|
||||
bool LLProcessorInfo::hasSSE3() const { return mImpl->hasSSE3(); }
|
||||
bool LLProcessorInfo::hasSSE3S() const { return mImpl->hasSSE3S(); }
|
||||
bool LLProcessorInfo::hasSSE41() const { return mImpl->hasSSE41(); }
|
||||
bool LLProcessorInfo::hasSSE42() const { return mImpl->hasSSE42(); }
|
||||
bool LLProcessorInfo::hasSSE4a() const { return mImpl->hasSSE4a(); }
|
||||
bool LLProcessorInfo::hasAltivec() const { return mImpl->hasAltivec(); }
|
||||
std::string LLProcessorInfo::getCPUFamilyName() const { return mImpl->getCPUFamilyName(); }
|
||||
std::string LLProcessorInfo::getCPUBrandName() const { return mImpl->getCPUBrandName(); }
|
||||
|
|
|
|||
|
|
@ -54,6 +54,11 @@ public:
|
|||
F64MegahertzImplicit getCPUFrequency() const;
|
||||
bool hasSSE() const;
|
||||
bool hasSSE2() const;
|
||||
bool hasSSE3() const;
|
||||
bool hasSSE3S() const;
|
||||
bool hasSSE41() const;
|
||||
bool hasSSE42() const;
|
||||
bool hasSSE4a() const;
|
||||
bool hasAltivec() const;
|
||||
std::string getCPUFamilyName() const;
|
||||
std::string getCPUBrandName() const;
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
#include "llerror.h"
|
||||
|
||||
// maximum reference count before sounding memory leak alarm
|
||||
const S32 gMaxRefCount = 65536;
|
||||
const S32 gMaxRefCount = S32_MAX;
|
||||
|
||||
LLRefCount::LLRefCount(const LLRefCount& other)
|
||||
: mRef(0)
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ using namespace llsd;
|
|||
# include <psapi.h> // GetPerformanceInfo() et al.
|
||||
# include <VersionHelpers.h>
|
||||
#elif LL_DARWIN
|
||||
# include "llsys_objc.h"
|
||||
# include <errno.h>
|
||||
# include <sys/sysctl.h>
|
||||
# include <sys/utsname.h>
|
||||
|
|
@ -74,12 +75,6 @@ using namespace llsd;
|
|||
# include <mach/mach_host.h>
|
||||
# include <mach/task.h>
|
||||
# include <mach/task_info.h>
|
||||
|
||||
// disable warnings about Gestalt calls being deprecated
|
||||
// until Apple get's on the ball and provides an alternative
|
||||
//
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
|
||||
#elif LL_LINUX
|
||||
# include <errno.h>
|
||||
# include <sys/utsname.h>
|
||||
|
|
@ -278,12 +273,9 @@ LLOSInfo::LLOSInfo() :
|
|||
{
|
||||
const char * DARWIN_PRODUCT_NAME = "Mac OS X";
|
||||
|
||||
SInt32 major_version, minor_version, bugfix_version;
|
||||
OSErr r1 = Gestalt(gestaltSystemVersionMajor, &major_version);
|
||||
OSErr r2 = Gestalt(gestaltSystemVersionMinor, &minor_version);
|
||||
OSErr r3 = Gestalt(gestaltSystemVersionBugFix, &bugfix_version);
|
||||
S32 major_version, minor_version, bugfix_version = 0;
|
||||
|
||||
if((r1 == noErr) && (r2 == noErr) && (r3 == noErr))
|
||||
if (LLGetDarwinOSInfo(major_version, minor_version, bugfix_version))
|
||||
{
|
||||
mMajorVer = major_version;
|
||||
mMinorVer = minor_version;
|
||||
|
|
@ -597,6 +589,11 @@ LLCPUInfo::LLCPUInfo()
|
|||
// proc.WriteInfoTextFile("procInfo.txt");
|
||||
mHasSSE = proc.hasSSE();
|
||||
mHasSSE2 = proc.hasSSE2();
|
||||
mHasSSE3 = proc.hasSSE3();
|
||||
mHasSSE3S = proc.hasSSE3S();
|
||||
mHasSSE41 = proc.hasSSE41();
|
||||
mHasSSE42 = proc.hasSSE42();
|
||||
mHasSSE4a = proc.hasSSE4a();
|
||||
mHasAltivec = proc.hasAltivec();
|
||||
mCPUMHz = (F64)proc.getCPUFrequency();
|
||||
mFamily = proc.getCPUFamilyName();
|
||||
|
|
@ -609,6 +606,35 @@ LLCPUInfo::LLCPUInfo()
|
|||
}
|
||||
mCPUString = out.str();
|
||||
LLStringUtil::trim(mCPUString);
|
||||
|
||||
if (mHasSSE)
|
||||
{
|
||||
mSSEVersions.append("1");
|
||||
}
|
||||
if (mHasSSE2)
|
||||
{
|
||||
mSSEVersions.append("2");
|
||||
}
|
||||
if (mHasSSE3)
|
||||
{
|
||||
mSSEVersions.append("3");
|
||||
}
|
||||
if (mHasSSE3S)
|
||||
{
|
||||
mSSEVersions.append("3S");
|
||||
}
|
||||
if (mHasSSE41)
|
||||
{
|
||||
mSSEVersions.append("4.1");
|
||||
}
|
||||
if (mHasSSE42)
|
||||
{
|
||||
mSSEVersions.append("4.2");
|
||||
}
|
||||
if (mHasSSE4a)
|
||||
{
|
||||
mSSEVersions.append("4a");
|
||||
}
|
||||
}
|
||||
|
||||
bool LLCPUInfo::hasAltivec() const
|
||||
|
|
@ -626,6 +652,31 @@ bool LLCPUInfo::hasSSE2() const
|
|||
return mHasSSE2;
|
||||
}
|
||||
|
||||
bool LLCPUInfo::hasSSE3() const
|
||||
{
|
||||
return mHasSSE3;
|
||||
}
|
||||
|
||||
bool LLCPUInfo::hasSSE3S() const
|
||||
{
|
||||
return mHasSSE3S;
|
||||
}
|
||||
|
||||
bool LLCPUInfo::hasSSE41() const
|
||||
{
|
||||
return mHasSSE41;
|
||||
}
|
||||
|
||||
bool LLCPUInfo::hasSSE42() const
|
||||
{
|
||||
return mHasSSE42;
|
||||
}
|
||||
|
||||
bool LLCPUInfo::hasSSE4a() const
|
||||
{
|
||||
return mHasSSE4a;
|
||||
}
|
||||
|
||||
F64 LLCPUInfo::getMHz() const
|
||||
{
|
||||
return mCPUMHz;
|
||||
|
|
@ -636,6 +687,11 @@ std::string LLCPUInfo::getCPUString() const
|
|||
return mCPUString;
|
||||
}
|
||||
|
||||
const LLSD& LLCPUInfo::getSSEVersions() const
|
||||
{
|
||||
return mSSEVersions;
|
||||
}
|
||||
|
||||
void LLCPUInfo::stream(std::ostream& s) const
|
||||
{
|
||||
// gather machine information.
|
||||
|
|
@ -645,6 +701,11 @@ void LLCPUInfo::stream(std::ostream& s) const
|
|||
// CPU's attributes regardless of platform
|
||||
s << "->mHasSSE: " << (U32)mHasSSE << std::endl;
|
||||
s << "->mHasSSE2: " << (U32)mHasSSE2 << std::endl;
|
||||
s << "->mHasSSE3: " << (U32)mHasSSE3 << std::endl;
|
||||
s << "->mHasSSE3S: " << (U32)mHasSSE3S << std::endl;
|
||||
s << "->mHasSSE41: " << (U32)mHasSSE41 << std::endl;
|
||||
s << "->mHasSSE42: " << (U32)mHasSSE42 << std::endl;
|
||||
s << "->mHasSSE4a: " << (U32)mHasSSE4a << std::endl;
|
||||
s << "->mHasAltivec: " << (U32)mHasAltivec << std::endl;
|
||||
s << "->mCPUMHz: " << mCPUMHz << std::endl;
|
||||
s << "->mCPUString: " << mCPUString << std::endl;
|
||||
|
|
@ -1341,10 +1402,3 @@ BOOL gzip_file(const std::string& srcfile, const std::string& dstfile)
|
|||
if (dst != NULL) gzclose(dst);
|
||||
return retval;
|
||||
}
|
||||
|
||||
#if LL_DARWIN
|
||||
// disable warnings about Gestalt calls being deprecated
|
||||
// until Apple get's on the ball and provides an alternative
|
||||
//
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -80,10 +80,16 @@ public:
|
|||
void stream(std::ostream& s) const;
|
||||
|
||||
std::string getCPUString() const;
|
||||
const LLSD& getSSEVersions() const;
|
||||
|
||||
bool hasAltivec() const;
|
||||
bool hasSSE() const;
|
||||
bool hasSSE2() const;
|
||||
bool hasSSE3() const;
|
||||
bool hasSSE3S() const;
|
||||
bool hasSSE41() const;
|
||||
bool hasSSE42() const;
|
||||
bool hasSSE4a() const;
|
||||
F64 getMHz() const;
|
||||
|
||||
// Family is "AMD Duron" or "Intel Pentium Pro"
|
||||
|
|
@ -92,10 +98,16 @@ public:
|
|||
private:
|
||||
bool mHasSSE;
|
||||
bool mHasSSE2;
|
||||
bool mHasSSE3;
|
||||
bool mHasSSE3S;
|
||||
bool mHasSSE41;
|
||||
bool mHasSSE42;
|
||||
bool mHasSSE4a;
|
||||
bool mHasAltivec;
|
||||
F64 mCPUMHz;
|
||||
std::string mFamily;
|
||||
std::string mCPUString;
|
||||
LLSD mSSEVersions;
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
/**
|
||||
* @file llsys_objc.h
|
||||
* @brief Header file for llsys_objc.mm
|
||||
*
|
||||
* $LicenseInfo:firstyear=2022&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2022, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLSYS_OBJC_H
|
||||
#define LL_LLSYS_OBJC_H
|
||||
|
||||
bool LLGetDarwinOSInfo(int &major, int &minor, int &patch);
|
||||
|
||||
|
||||
#endif // LL_LLSYS_OBJC_H
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
/**
|
||||
* @file llsys_objc.mm
|
||||
* @brief obj-c implementation of the system information functions
|
||||
*
|
||||
* $LicenseInfo:firstyear=2022&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2022, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#import "llsys_objc.h"
|
||||
#import <AppKit/AppKit.h>
|
||||
|
||||
static int intAtStringIndex(NSArray *array, int index)
|
||||
{
|
||||
return [(NSString *)[array objectAtIndex:index] integerValue];
|
||||
}
|
||||
|
||||
bool LLGetDarwinOSInfo(int &major, int &minor, int &patch)
|
||||
{
|
||||
if (NSAppKitVersionNumber > NSAppKitVersionNumber10_8)
|
||||
{
|
||||
NSOperatingSystemVersion osVersion = [[NSProcessInfo processInfo] operatingSystemVersion];
|
||||
major = osVersion.majorVersion;
|
||||
minor = osVersion.minorVersion;
|
||||
patch = osVersion.patchVersion;
|
||||
}
|
||||
else
|
||||
{
|
||||
NSString* versionString = [[NSDictionary dictionaryWithContentsOfFile:
|
||||
@"/System/Library/CoreServices/SystemVersion.plist"] objectForKey:@"ProductVersion"];
|
||||
NSArray* versions = [versionString componentsSeparatedByString:@"."];
|
||||
NSUInteger count = [versions count];
|
||||
if (count > 0)
|
||||
{
|
||||
major = intAtStringIndex(versions, 0);
|
||||
if (count > 1)
|
||||
{
|
||||
minor = intAtStringIndex(versions, 1);
|
||||
if (count > 2)
|
||||
{
|
||||
patch = intAtStringIndex(versions, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
@ -22,6 +22,7 @@
|
|||
#include "stringize.h"
|
||||
|
||||
LL::ThreadPool::ThreadPool(const std::string& name, size_t threads, size_t capacity):
|
||||
super(name),
|
||||
mQueue(name, capacity),
|
||||
mName("ThreadPool:" + name),
|
||||
mThreadCount(threads)
|
||||
|
|
|
|||
|
|
@ -22,8 +22,10 @@
|
|||
namespace LL
|
||||
{
|
||||
|
||||
class ThreadPool
|
||||
class ThreadPool: public LLInstanceTracker<ThreadPool, std::string>
|
||||
{
|
||||
private:
|
||||
using super = LLInstanceTracker<ThreadPool, std::string>;
|
||||
public:
|
||||
/**
|
||||
* Pass ThreadPool a string name. This can be used to look up the
|
||||
|
|
|
|||
|
|
@ -403,7 +403,7 @@ namespace LL
|
|||
[result = std::forward<CALLABLE>(callable)(),
|
||||
callback = std::move(callback)]
|
||||
()
|
||||
{ callback(std::move(result)); };
|
||||
mutable { callback(std::move(result)); };
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -449,7 +449,7 @@ namespace LL
|
|||
callable = std::move(callable),
|
||||
callback = std::move(callback)]
|
||||
()
|
||||
{
|
||||
mutable {
|
||||
// Use postMaybe() below in case this originating WorkQueue
|
||||
// has been closed or destroyed. Remember, the outer lambda is
|
||||
// now running on a thread servicing the target WorkQueue, and
|
||||
|
|
@ -513,7 +513,7 @@ namespace LL
|
|||
// We dare to bind a reference to Promise because it's
|
||||
// specifically designed for cross-thread communication.
|
||||
[&promise, callable = std::move(callable)]()
|
||||
{
|
||||
mutable {
|
||||
try
|
||||
{
|
||||
// call the caller's callable and trigger promise with result
|
||||
|
|
@ -542,7 +542,7 @@ namespace LL
|
|||
time,
|
||||
// &promise is designed for cross-thread access
|
||||
[&promise, callable = std::move(callable)]()
|
||||
{
|
||||
mutable {
|
||||
try
|
||||
{
|
||||
callable();
|
||||
|
|
|
|||
|
|
@ -131,28 +131,44 @@ void LLDiskCache::purge()
|
|||
|
||||
LL_INFOS() << "Purging cache to a maximum of " << mMaxSizeBytes << " bytes" << LL_ENDL;
|
||||
|
||||
std::vector<bool> file_removed;
|
||||
if (mEnableCacheDebugInfo)
|
||||
{
|
||||
file_removed.reserve(file_info.size());
|
||||
}
|
||||
uintmax_t file_size_total = 0;
|
||||
for (file_info_t& entry : file_info)
|
||||
{
|
||||
file_size_total += entry.second.first;
|
||||
|
||||
std::string action = "";
|
||||
if (file_size_total > mMaxSizeBytes)
|
||||
bool should_remove = file_size_total > mMaxSizeBytes;
|
||||
if (mEnableCacheDebugInfo)
|
||||
{
|
||||
file_removed.push_back(should_remove);
|
||||
}
|
||||
if (should_remove)
|
||||
{
|
||||
action = "DELETE:";
|
||||
boost::filesystem::remove(entry.second.second, ec);
|
||||
if (ec.failed())
|
||||
{
|
||||
LL_WARNS() << "Failed to delete cache file " << entry.second.second << ": " << ec.message() << LL_ENDL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
action = " KEEP:";
|
||||
}
|
||||
}
|
||||
|
||||
if (mEnableCacheDebugInfo)
|
||||
if (mEnableCacheDebugInfo)
|
||||
{
|
||||
auto end_time = std::chrono::high_resolution_clock::now();
|
||||
auto execute_time = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time).count();
|
||||
|
||||
// Log afterward so it doesn't affect the time measurement
|
||||
// Logging thousands of file results can take hundreds of milliseconds
|
||||
for (size_t i = 0; i < file_info.size(); ++i)
|
||||
{
|
||||
const file_info_t& entry = file_info[i];
|
||||
const bool removed = file_removed[i];
|
||||
const std::string action = removed ? "DELETE:" : "KEEP:";
|
||||
|
||||
// have to do this because of LL_INFO/LL_END weirdness
|
||||
std::ostringstream line;
|
||||
|
||||
|
|
@ -163,12 +179,7 @@ void LLDiskCache::purge()
|
|||
line << " (" << file_size_total << "/" << mMaxSizeBytes << ")";
|
||||
LL_INFOS() << line.str() << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
if (mEnableCacheDebugInfo)
|
||||
{
|
||||
auto end_time = std::chrono::high_resolution_clock::now();
|
||||
auto execute_time = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time).count();
|
||||
LL_INFOS() << "Total dir size after purge is " << dirFileSize(mCacheDir) << LL_ENDL;
|
||||
LL_INFOS() << "Cache purge took " << execute_time << " ms to execute for " << file_info.size() << " files" << LL_ENDL;
|
||||
}
|
||||
|
|
@ -354,6 +365,38 @@ void LLDiskCache::clearCache()
|
|||
}
|
||||
}
|
||||
|
||||
void LLDiskCache::removeOldVFSFiles()
|
||||
{
|
||||
//VFS files won't be created, so consider removing this code later
|
||||
static const char CACHE_FORMAT[] = "inv.llsd";
|
||||
static const char DB_FORMAT[] = "db2.x";
|
||||
|
||||
boost::system::error_code ec;
|
||||
#if LL_WINDOWS
|
||||
std::wstring cache_path(utf8str_to_utf16str(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "")));
|
||||
#else
|
||||
std::string cache_path(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ""));
|
||||
#endif
|
||||
if (boost::filesystem::is_directory(cache_path, ec) && !ec.failed())
|
||||
{
|
||||
for (auto& entry : boost::make_iterator_range(boost::filesystem::directory_iterator(cache_path, ec), {}))
|
||||
{
|
||||
if (boost::filesystem::is_regular_file(entry, ec) && !ec.failed())
|
||||
{
|
||||
if ((entry.path().string().find(CACHE_FORMAT) != std::string::npos) ||
|
||||
(entry.path().string().find(DB_FORMAT) != std::string::npos))
|
||||
{
|
||||
boost::filesystem::remove(entry, ec);
|
||||
if (ec.failed())
|
||||
{
|
||||
LL_WARNS() << "Failed to delete cache file " << entry << ": " << ec.message() << LL_ENDL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uintmax_t LLDiskCache::dirFileSize(const std::string dir)
|
||||
{
|
||||
uintmax_t total_file_size = 0;
|
||||
|
|
|
|||
|
|
@ -140,6 +140,8 @@ class LLDiskCache :
|
|||
*/
|
||||
const std::string getCacheInfo();
|
||||
|
||||
void removeOldVFSFiles();
|
||||
|
||||
private:
|
||||
/**
|
||||
* Utility function to gather the total size the files in a given
|
||||
|
|
|
|||
|
|
@ -234,6 +234,8 @@ void LLParcel::init(const LLUUID &owner_id,
|
|||
|
||||
setRegionAllowEnvironmentOverride(FALSE);
|
||||
setParcelEnvironmentVersion(INVALID_PARCEL_ENVIRONMENT_VERSION);
|
||||
|
||||
setObscureMOAP(false);
|
||||
}
|
||||
|
||||
void LLParcel::overrideOwner(const LLUUID& owner_id, BOOL is_group_owned)
|
||||
|
|
@ -540,6 +542,7 @@ void LLParcel::packMessage(LLSD& msg)
|
|||
msg["see_avs"] = (LLSD::Boolean) getSeeAVs();
|
||||
msg["group_av_sounds"] = (LLSD::Boolean) getAllowGroupAVSounds();
|
||||
msg["any_av_sounds"] = (LLSD::Boolean) getAllowAnyAVSounds();
|
||||
msg["obscure_moap"] = (LLSD::Boolean) getObscureMOAP();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -306,6 +306,7 @@ public:
|
|||
void setRestrictPushObject(BOOL b) { setParcelFlag(PF_RESTRICT_PUSHOBJECT, b); }
|
||||
void setAllowGroupAVSounds(BOOL b) { mAllowGroupAVSounds = b; }
|
||||
void setAllowAnyAVSounds(BOOL b) { mAllowAnyAVSounds = b; }
|
||||
void setObscureMOAP(bool b) { mObscureMOAP = b; }
|
||||
|
||||
void setDrawDistance(F32 dist) { mDrawDistance = dist; }
|
||||
void setSalePrice(S32 price) { mSalePrice = price; }
|
||||
|
|
@ -517,6 +518,8 @@ public:
|
|||
|
||||
BOOL getAllowGroupAVSounds() const { return mAllowGroupAVSounds; }
|
||||
BOOL getAllowAnyAVSounds() const { return mAllowAnyAVSounds; }
|
||||
|
||||
bool getObscureMOAP() const { return mObscureMOAP; }
|
||||
|
||||
F32 getDrawDistance() const { return mDrawDistance; }
|
||||
S32 getSalePrice() const { return mSalePrice; }
|
||||
|
|
@ -670,6 +673,7 @@ protected:
|
|||
BOOL mRegionAllowEnvironmentOverride;
|
||||
BOOL mAllowGroupAVSounds;
|
||||
BOOL mAllowAnyAVSounds;
|
||||
bool mObscureMOAP;
|
||||
S32 mCurrentEnvironmentVersion;
|
||||
|
||||
bool mIsDefaultDayCycle;
|
||||
|
|
|
|||
|
|
@ -4,12 +4,14 @@ project(llmath)
|
|||
|
||||
include(00-Common)
|
||||
include(LLCommon)
|
||||
include(LLMeshOptimizer)
|
||||
include(bugsplat)
|
||||
include(Boost)
|
||||
|
||||
include_directories(
|
||||
${LLCOMMON_INCLUDE_DIRS}
|
||||
${LLCOMMON_SYSTEM_INCLUDE_DIRS}
|
||||
${LLMESHOPTIMIZER_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
set(llmath_SOURCE_FILES
|
||||
|
|
@ -109,6 +111,7 @@ add_library (llmath ${llmath_SOURCE_FILES})
|
|||
|
||||
target_link_libraries(llmath
|
||||
${LLCOMMON_LIBRARIES}
|
||||
${LLMESHOPTIMIZER_LIBRARIES}
|
||||
)
|
||||
|
||||
# Add tests
|
||||
|
|
|
|||
|
|
@ -48,52 +48,59 @@ extern float gOctreeMinSize;
|
|||
#define LL_OCTREE_MAX_CAPACITY 128
|
||||
#endif*/
|
||||
|
||||
template <class T> class LLOctreeNode;
|
||||
// T is the type of the element referenced by the octree node.
|
||||
// T_PTR determines how pointers to elements are stored internally.
|
||||
// LLOctreeNode<T, LLPointer<T>> assumes ownership of inserted elements and
|
||||
// deletes elements removed from the tree.
|
||||
// LLOctreeNode<T, T*> doesn't take ownership of inserted elements, so the API
|
||||
// user is responsible for managing the storage lifecycle of elements added to
|
||||
// the tree.
|
||||
template <class T, typename T_PTR> class LLOctreeNode;
|
||||
|
||||
template <class T>
|
||||
template <class T, typename T_PTR>
|
||||
class LLOctreeListener: public LLTreeListener<T>
|
||||
{
|
||||
public:
|
||||
typedef LLTreeListener<T> BaseType;
|
||||
typedef LLOctreeNode<T> oct_node;
|
||||
typedef LLOctreeNode<T, T_PTR> oct_node;
|
||||
|
||||
virtual void handleChildAddition(const oct_node* parent, oct_node* child) = 0;
|
||||
virtual void handleChildRemoval(const oct_node* parent, const oct_node* child) = 0;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
template <class T, typename T_PTR>
|
||||
class LLOctreeTraveler
|
||||
{
|
||||
public:
|
||||
virtual void traverse(const LLOctreeNode<T>* node);
|
||||
virtual void visit(const LLOctreeNode<T>* branch) = 0;
|
||||
virtual void traverse(const LLOctreeNode<T, T_PTR>* node);
|
||||
virtual void visit(const LLOctreeNode<T, T_PTR>* branch) = 0;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class LLOctreeTravelerDepthFirst : public LLOctreeTraveler<T>
|
||||
template <class T, typename T_PTR>
|
||||
class LLOctreeTravelerDepthFirst : public LLOctreeTraveler<T, T_PTR>
|
||||
{
|
||||
public:
|
||||
virtual void traverse(const LLOctreeNode<T>* node) override;
|
||||
virtual void traverse(const LLOctreeNode<T, T_PTR>* node) override;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
template <class T, typename T_PTR>
|
||||
class alignas(16) LLOctreeNode : public LLTreeNode<T>
|
||||
{
|
||||
LL_ALIGN_NEW
|
||||
public:
|
||||
|
||||
typedef LLOctreeTraveler<T> oct_traveler;
|
||||
typedef LLTreeTraveler<T> tree_traveler;
|
||||
typedef std::vector< LLPointer<T> > element_list; // note: don't remove the whitespace between "> >"
|
||||
typedef LLPointer<T>* element_iter;
|
||||
typedef const LLPointer<T>* const_element_iter;
|
||||
typedef LLOctreeTraveler<T, T_PTR> oct_traveler;
|
||||
typedef LLTreeTraveler<T> tree_traveler;
|
||||
typedef std::vector<T_PTR> element_list;
|
||||
typedef typename element_list::iterator element_iter;
|
||||
typedef typename element_list::const_iterator const_element_iter;
|
||||
typedef typename std::vector<LLTreeListener<T>*>::iterator tree_listener_iter;
|
||||
typedef LLOctreeNode<T>** child_list;
|
||||
typedef LLOctreeNode<T>** child_iter;
|
||||
typedef LLOctreeNode<T, T_PTR>** child_list;
|
||||
typedef LLOctreeNode<T, T_PTR>** child_iter;
|
||||
|
||||
typedef LLTreeNode<T> BaseType;
|
||||
typedef LLOctreeNode<T> oct_node;
|
||||
typedef LLOctreeListener<T> oct_listener;
|
||||
typedef LLTreeNode<T> BaseType;
|
||||
typedef LLOctreeNode<T, T_PTR> oct_node;
|
||||
typedef LLOctreeListener<T, T_PTR> oct_listener;
|
||||
|
||||
enum
|
||||
{
|
||||
|
|
@ -108,9 +115,6 @@ public:
|
|||
mOctant(octant)
|
||||
{
|
||||
llassert(size[0] >= gOctreeMinSize*0.5f);
|
||||
//always keep a NULL terminated list to avoid out of bounds exceptions in debug builds
|
||||
mData.push_back(NULL);
|
||||
mDataEnd = &mData[0];
|
||||
|
||||
mCenter = center;
|
||||
mSize = size;
|
||||
|
|
@ -121,8 +125,6 @@ public:
|
|||
mOctant = ((oct_node*) mParent)->getOctant(mCenter);
|
||||
}
|
||||
|
||||
mElementCount = 0;
|
||||
|
||||
clearChildren();
|
||||
}
|
||||
|
||||
|
|
@ -130,15 +132,14 @@ public:
|
|||
{
|
||||
BaseType::destroyListeners();
|
||||
|
||||
for (U32 i = 0; i < mElementCount; ++i)
|
||||
const U32 element_count = getElementCount();
|
||||
for (U32 i = 0; i < element_count; ++i)
|
||||
{
|
||||
mData[i]->setBinIndex(-1);
|
||||
mData[i] = NULL;
|
||||
}
|
||||
|
||||
mData.clear();
|
||||
mData.push_back(NULL);
|
||||
mDataEnd = &mData[0];
|
||||
|
||||
for (U32 i = 0; i < getChildCount(); i++)
|
||||
{
|
||||
|
|
@ -238,14 +239,12 @@ public:
|
|||
void accept(oct_traveler* visitor) { visitor->visit(this); }
|
||||
virtual bool isLeaf() const { return mChildCount == 0; }
|
||||
|
||||
U32 getElementCount() const { return mElementCount; }
|
||||
bool isEmpty() const { return mElementCount == 0; }
|
||||
element_list& getData() { return mData; }
|
||||
const element_list& getData() const { return mData; }
|
||||
element_iter getDataBegin() { return &mData[0]; }
|
||||
element_iter getDataEnd() { return mDataEnd; }
|
||||
const_element_iter getDataBegin() const { return &mData[0]; }
|
||||
const_element_iter getDataEnd() const { return mDataEnd; }
|
||||
U32 getElementCount() const { return (U32)mData.size(); }
|
||||
bool isEmpty() const { return mData.empty(); }
|
||||
element_iter getDataBegin() { return mData.begin(); }
|
||||
element_iter getDataEnd() { return mData.end(); }
|
||||
const_element_iter getDataBegin() const { return mData.cbegin(); }
|
||||
const_element_iter getDataEnd() const { return mData.cend(); }
|
||||
|
||||
U32 getChildCount() const { return mChildCount; }
|
||||
oct_node* getChild(U32 index) { return mChild[index]; }
|
||||
|
|
@ -263,7 +262,7 @@ public:
|
|||
U8 idx = mChildMap[i];
|
||||
if (idx != NO_CHILD_NODES)
|
||||
{
|
||||
LLOctreeNode<T>* child = mChild[idx];
|
||||
oct_node* child = mChild[idx];
|
||||
|
||||
if (child->getOctant() != i)
|
||||
{
|
||||
|
|
@ -281,7 +280,7 @@ public:
|
|||
|
||||
oct_node* getNodeAt(const LLVector4a& pos, const F32& rad)
|
||||
{
|
||||
LLOctreeNode<T>* node = this;
|
||||
oct_node* node = this;
|
||||
|
||||
if (node->isInside(pos, rad))
|
||||
{
|
||||
|
|
@ -303,7 +302,7 @@ public:
|
|||
}
|
||||
else if (!node->contains(rad) && node->getParent())
|
||||
{ //if we got here, data does not exist in this node
|
||||
return ((LLOctreeNode<T>*) node->getParent())->getNodeAt(pos, rad);
|
||||
return ((oct_node*) node->getParent())->getNodeAt(pos, rad);
|
||||
}
|
||||
|
||||
return node;
|
||||
|
|
@ -318,7 +317,7 @@ public:
|
|||
OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE BRANCH !!!" << LL_ENDL;
|
||||
return false;
|
||||
}
|
||||
LLOctreeNode<T>* parent = getOctParent();
|
||||
oct_node* parent = getOctParent();
|
||||
|
||||
//is it here?
|
||||
if (isInside(data->getPositionGroup()))
|
||||
|
|
@ -326,11 +325,8 @@ public:
|
|||
if ((((getElementCount() < gOctreeMaxCapacity || getSize()[0] <= gOctreeMinSize) && contains(data->getBinRadius())) ||
|
||||
(data->getBinRadius() > getSize()[0] && parent && parent->getElementCount() >= gOctreeMaxCapacity)))
|
||||
{ //it belongs here
|
||||
mData.push_back(NULL);
|
||||
mData[mElementCount] = data;
|
||||
mElementCount++;
|
||||
mDataEnd = &mData[mElementCount];
|
||||
data->setBinIndex(mElementCount-1);
|
||||
mData.push_back(data);
|
||||
data->setBinIndex(getElementCount() - 1);
|
||||
BaseType::insert(data);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -354,7 +350,7 @@ public:
|
|||
size.mul(0.5f);
|
||||
|
||||
//push center in direction of data
|
||||
LLOctreeNode<T>::pushCenter(center, size, data);
|
||||
oct_node::pushCenter(center, size, data);
|
||||
|
||||
// handle case where floating point number gets too small
|
||||
LLVector4a val;
|
||||
|
|
@ -366,11 +362,8 @@ public:
|
|||
|
||||
if( lt == 0x7 )
|
||||
{
|
||||
mData.push_back(NULL);
|
||||
mData[mElementCount] = data;
|
||||
mElementCount++;
|
||||
mDataEnd = &mData[mElementCount];
|
||||
data->setBinIndex(mElementCount-1);
|
||||
mData.push_back(data);
|
||||
data->setBinIndex(getElementCount() - 1);
|
||||
BaseType::insert(data);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -396,7 +389,7 @@ public:
|
|||
|
||||
llassert(size[0] >= gOctreeMinSize*0.5f);
|
||||
//make the new kid
|
||||
child = new LLOctreeNode<T>(center, size, this);
|
||||
child = new oct_node(center, size, this);
|
||||
addChild(child);
|
||||
|
||||
child->insert(data);
|
||||
|
|
@ -429,28 +422,25 @@ public:
|
|||
}
|
||||
|
||||
void _remove(T* data, S32 i)
|
||||
{ //precondition -- mElementCount > 0, idx is in range [0, mElementCount)
|
||||
{ //precondition -- getElementCount() > 0, idx is in range [0, getElementCount())
|
||||
|
||||
mElementCount--;
|
||||
data->setBinIndex(-1);
|
||||
|
||||
if (mElementCount > 0)
|
||||
const U32 new_element_count = getElementCount() - 1;
|
||||
if (new_element_count > 0)
|
||||
{
|
||||
if (mElementCount != i)
|
||||
if (new_element_count != i)
|
||||
{
|
||||
mData[i] = mData[mElementCount]; //might unref data, do not access data after this point
|
||||
mData[i] = mData[new_element_count]; //might unref data, do not access data after this point
|
||||
mData[i]->setBinIndex(i);
|
||||
}
|
||||
|
||||
mData[mElementCount] = NULL;
|
||||
mData[new_element_count] = NULL;
|
||||
mData.pop_back();
|
||||
mDataEnd = &mData[mElementCount];
|
||||
}
|
||||
else
|
||||
{
|
||||
mData.clear();
|
||||
mData.push_back(NULL);
|
||||
mDataEnd = &mData[0];
|
||||
}
|
||||
|
||||
this->notifyRemoval(data);
|
||||
|
|
@ -463,7 +453,7 @@ public:
|
|||
|
||||
S32 i = data->getBinIndex();
|
||||
|
||||
if (i >= 0 && i < mElementCount)
|
||||
if (i >= 0 && i < getElementCount())
|
||||
{
|
||||
if (mData[i] == data)
|
||||
{ //found it
|
||||
|
|
@ -506,7 +496,8 @@ public:
|
|||
|
||||
void removeByAddress(T* data)
|
||||
{
|
||||
for (U32 i = 0; i < mElementCount; ++i)
|
||||
const U32 element_count = getElementCount();
|
||||
for (U32 i = 0; i < element_count; ++i)
|
||||
{
|
||||
if (mData[i] == data)
|
||||
{ //we have data
|
||||
|
|
@ -518,7 +509,7 @@ public:
|
|||
|
||||
for (U32 i = 0; i < getChildCount(); i++)
|
||||
{ //we don't contain data, so pass this guy down
|
||||
LLOctreeNode<T>* child = (LLOctreeNode<T>*) getChild(i);
|
||||
oct_node* child = (oct_node*) getChild(i);
|
||||
child->removeByAddress(data);
|
||||
}
|
||||
}
|
||||
|
|
@ -672,22 +663,20 @@ protected:
|
|||
oct_node* mParent;
|
||||
U8 mOctant;
|
||||
|
||||
LLOctreeNode<T>* mChild[8];
|
||||
oct_node* mChild[8];
|
||||
U8 mChildMap[8];
|
||||
U32 mChildCount;
|
||||
|
||||
element_list mData;
|
||||
element_iter mDataEnd;
|
||||
U32 mElementCount;
|
||||
};
|
||||
|
||||
//just like a regular node, except it might expand on insert and compress on balance
|
||||
template <class T>
|
||||
class LLOctreeRoot : public LLOctreeNode<T>
|
||||
template <class T, typename T_PTR>
|
||||
class LLOctreeRoot : public LLOctreeNode<T, T_PTR>
|
||||
{
|
||||
public:
|
||||
typedef LLOctreeNode<T> BaseType;
|
||||
typedef LLOctreeNode<T> oct_node;
|
||||
typedef LLOctreeNode<T, T_PTR> BaseType;
|
||||
typedef LLOctreeNode<T, T_PTR> oct_node;
|
||||
|
||||
LLOctreeRoot(const LLVector4a& center,
|
||||
const LLVector4a& size,
|
||||
|
|
@ -768,7 +757,7 @@ public:
|
|||
oct_node* node = this->getNodeAt(data);
|
||||
if (node == this)
|
||||
{
|
||||
LLOctreeNode<T>::insert(data);
|
||||
oct_node::insert(data);
|
||||
}
|
||||
else if (node->isInside(data->getPositionGroup()))
|
||||
{
|
||||
|
|
@ -788,13 +777,13 @@ public:
|
|||
LLVector4a center, size;
|
||||
center = this->getCenter();
|
||||
size = this->getSize();
|
||||
LLOctreeNode<T>::pushCenter(center, size, data);
|
||||
oct_node::pushCenter(center, size, data);
|
||||
this->setCenter(center);
|
||||
size.mul(2.f);
|
||||
this->setSize(size);
|
||||
this->updateMinMax();
|
||||
}
|
||||
LLOctreeNode<T>::insert(data);
|
||||
oct_node::insert(data);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -806,7 +795,7 @@ public:
|
|||
|
||||
//expand this node
|
||||
LLVector4a newcenter(center);
|
||||
LLOctreeNode<T>::pushCenter(newcenter, size, data);
|
||||
oct_node::pushCenter(newcenter, size, data);
|
||||
this->setCenter(newcenter);
|
||||
LLVector4a size2 = size;
|
||||
size2.mul(2.f);
|
||||
|
|
@ -816,11 +805,11 @@ public:
|
|||
llassert(size[0] >= gOctreeMinSize);
|
||||
|
||||
//copy our children to a new branch
|
||||
LLOctreeNode<T>* newnode = new LLOctreeNode<T>(center, size, this);
|
||||
oct_node* newnode = new oct_node(center, size, this);
|
||||
|
||||
for (U32 i = 0; i < this->getChildCount(); i++)
|
||||
{
|
||||
LLOctreeNode<T>* child = this->getChild(i);
|
||||
oct_node* child = this->getChild(i);
|
||||
newnode->addChild(child);
|
||||
}
|
||||
|
||||
|
|
@ -846,8 +835,8 @@ public:
|
|||
//========================
|
||||
// LLOctreeTraveler
|
||||
//========================
|
||||
template <class T>
|
||||
void LLOctreeTraveler<T>::traverse(const LLOctreeNode<T>* node)
|
||||
template <class T, typename T_PTR>
|
||||
void LLOctreeTraveler<T, T_PTR>::traverse(const LLOctreeNode<T, T_PTR>* node)
|
||||
{
|
||||
node->accept(this);
|
||||
for (U32 i = 0; i < node->getChildCount(); i++)
|
||||
|
|
@ -856,8 +845,8 @@ void LLOctreeTraveler<T>::traverse(const LLOctreeNode<T>* node)
|
|||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void LLOctreeTravelerDepthFirst<T>::traverse(const LLOctreeNode<T>* node)
|
||||
template <class T, typename T_PTR>
|
||||
void LLOctreeTravelerDepthFirst<T, T_PTR>::traverse(const LLOctreeNode<T, T_PTR>* node)
|
||||
{
|
||||
for (U32 i = 0; i < node->getChildCount(); i++)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@
|
|||
#include "llsdserialize.h"
|
||||
#include "llvector4a.h"
|
||||
#include "llmatrix4a.h"
|
||||
#include "llmeshoptimizer.h"
|
||||
#include "lltimer.h"
|
||||
|
||||
#define DEBUG_SILHOUETTE_BINORMALS 0
|
||||
|
|
@ -370,7 +371,7 @@ BOOL LLTriangleRayIntersect(const LLVector3& vert0, const LLVector3& vert1, cons
|
|||
}
|
||||
}
|
||||
|
||||
class LLVolumeOctreeRebound : public LLOctreeTravelerDepthFirst<LLVolumeTriangle>
|
||||
class LLVolumeOctreeRebound : public LLOctreeTravelerDepthFirst<LLVolumeTriangle, LLVolumeTriangle*>
|
||||
{
|
||||
public:
|
||||
const LLVolumeFace* mFace;
|
||||
|
|
@ -380,7 +381,7 @@ public:
|
|||
mFace = face;
|
||||
}
|
||||
|
||||
virtual void visit(const LLOctreeNode<LLVolumeTriangle>* branch)
|
||||
virtual void visit(const LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>* branch)
|
||||
{ //this is a depth first traversal, so it's safe to assum all children have complete
|
||||
//bounding data
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME
|
||||
|
|
@ -398,8 +399,7 @@ public:
|
|||
min = *(tri->mV[0]);
|
||||
max = *(tri->mV[0]);
|
||||
|
||||
for (LLOctreeNode<LLVolumeTriangle>::const_element_iter iter =
|
||||
branch->getDataBegin(); iter != branch->getDataEnd(); ++iter)
|
||||
for (LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>::const_element_iter iter = branch->getDataBegin(); iter != branch->getDataEnd(); ++iter)
|
||||
{ //for each triangle in node
|
||||
|
||||
//stretch by triangles in node
|
||||
|
|
@ -683,7 +683,7 @@ LLProfile::Face* LLProfile::addHole(const LLProfileParams& params, BOOL flat, F3
|
|||
|
||||
Face *face = addFace(mTotalOut, mTotal-mTotalOut,0,LL_FACE_INNER_SIDE, flat);
|
||||
|
||||
static LLAlignedArray<LLVector4a,64> pt;
|
||||
static thread_local LLAlignedArray<LLVector4a,64> pt;
|
||||
pt.resize(mTotal) ;
|
||||
|
||||
for (S32 i=mTotalOut;i<mTotal;i++)
|
||||
|
|
@ -1624,9 +1624,6 @@ BOOL LLPath::generate(const LLPathParams& params, F32 detail, S32 split,
|
|||
//genNGon(params, llfloor(MIN_DETAIL_FACES * detail), 4.f, 0.f);
|
||||
genNGon(params, llfloor(MIN_DETAIL_FACES * detail));
|
||||
|
||||
F32 t = 0.f;
|
||||
F32 tStep = 1.0f / mPath.size();
|
||||
|
||||
F32 toggle = 0.5f;
|
||||
for (S32 i=0;i<(S32)mPath.size();i++)
|
||||
{
|
||||
|
|
@ -1635,7 +1632,6 @@ BOOL LLPath::generate(const LLPathParams& params, F32 detail, S32 split,
|
|||
toggle = -0.5f;
|
||||
else
|
||||
toggle = 0.5f;
|
||||
t += tStep;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2426,6 +2422,13 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
|
|||
|
||||
//copy out indices
|
||||
S32 num_indices = idx.size() / 2;
|
||||
const S32 indices_to_discard = num_indices % 3;
|
||||
if (indices_to_discard > 0)
|
||||
{
|
||||
// Invalid number of triangle indices
|
||||
LL_WARNS() << "Incomplete triangle discarded from face! Indices count " << num_indices << " was not divisible by 3. face index: " << i << " Total: " << face_count << LL_ENDL;
|
||||
num_indices -= indices_to_discard;
|
||||
}
|
||||
face.resizeIndices(num_indices);
|
||||
|
||||
if (num_indices > 2 && !face.mIndices)
|
||||
|
|
@ -2441,8 +2444,7 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
|
|||
}
|
||||
|
||||
U16* indices = (U16*) &(idx[0]);
|
||||
U32 count = idx.size()/2;
|
||||
for (U32 j = 0; j < count; ++j)
|
||||
for (U32 j = 0; j < num_indices; ++j)
|
||||
{
|
||||
face.mIndices[j] = indices[j];
|
||||
}
|
||||
|
|
@ -3834,8 +3836,8 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
|
|||
#if DEBUG_SILHOUETTE_EDGE_MAP
|
||||
|
||||
//for each triangle
|
||||
U32 count = face.mNumIndices;
|
||||
for (U32 j = 0; j < count/3; j++) {
|
||||
U32 tri_count = face.mNumIndices / 3;
|
||||
for (U32 j = 0; j < tri_count; j++) {
|
||||
//get vertices
|
||||
S32 v1 = face.mIndices[j*3+0];
|
||||
S32 v2 = face.mIndices[j*3+1];
|
||||
|
|
@ -3853,7 +3855,7 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
|
|||
continue;
|
||||
}
|
||||
|
||||
if (nIndex >= (S32) count/3) {
|
||||
if (nIndex >= (S32)tri_count) {
|
||||
continue;
|
||||
}
|
||||
//get neighbor vertices
|
||||
|
|
@ -4145,13 +4147,13 @@ S32 LLVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& en
|
|||
}
|
||||
else
|
||||
{
|
||||
if (!face.mOctree)
|
||||
if (!face.getOctree())
|
||||
{
|
||||
face.createOctree();
|
||||
}
|
||||
|
||||
LLOctreeTriangleRayIntersect intersect(start, dir, &face, &closest_t, intersection, tex_coord, normal, tangent_out);
|
||||
intersect.traverse(face.mOctree);
|
||||
intersect.traverse(face.getOctree());
|
||||
if (intersect.mHitFace)
|
||||
{
|
||||
hit_face = i;
|
||||
|
|
@ -4706,6 +4708,7 @@ LLVolumeFace::LLVolumeFace() :
|
|||
#endif
|
||||
mWeightsScrubbed(FALSE),
|
||||
mOctree(NULL),
|
||||
mOctreeTriangles(NULL),
|
||||
mOptimized(FALSE)
|
||||
{
|
||||
mExtents = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*3);
|
||||
|
|
@ -4735,8 +4738,9 @@ LLVolumeFace::LLVolumeFace(const LLVolumeFace& src)
|
|||
mJointIndices(NULL),
|
||||
#endif
|
||||
mWeightsScrubbed(FALSE),
|
||||
mOctree(NULL)
|
||||
{
|
||||
mOctree(NULL),
|
||||
mOctreeTriangles(NULL)
|
||||
{
|
||||
mExtents = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*3);
|
||||
mCenter = mExtents+2;
|
||||
*this = src;
|
||||
|
|
@ -4876,8 +4880,7 @@ void LLVolumeFace::freeData()
|
|||
mJustWeights = NULL;
|
||||
#endif
|
||||
|
||||
delete mOctree;
|
||||
mOctree = NULL;
|
||||
destroyOctree();
|
||||
}
|
||||
|
||||
BOOL LLVolumeFace::create(LLVolume* volume, BOOL partial_build)
|
||||
|
|
@ -4885,8 +4888,7 @@ BOOL LLVolumeFace::create(LLVolume* volume, BOOL partial_build)
|
|||
LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME
|
||||
|
||||
//tree for this face is no longer valid
|
||||
delete mOctree;
|
||||
mOctree = NULL;
|
||||
destroyOctree();
|
||||
|
||||
LL_CHECK_MEMORY
|
||||
BOOL ret = FALSE ;
|
||||
|
|
@ -4952,6 +4954,50 @@ bool LLVolumeFace::VertexMapData::ComparePosition::operator()(const LLVector3& a
|
|||
return a.mV[2] < b.mV[2];
|
||||
}
|
||||
|
||||
void LLVolumeFace::remap()
|
||||
{
|
||||
// Generate a remap buffer
|
||||
std::vector<unsigned int> remap(mNumVertices);
|
||||
S32 remap_vertices_count = LLMeshOptimizer::generateRemapMultiU16(&remap[0],
|
||||
mIndices,
|
||||
mNumIndices,
|
||||
mPositions,
|
||||
mNormals,
|
||||
mTexCoords,
|
||||
mNumVertices);
|
||||
|
||||
// Allocate new buffers
|
||||
S32 size = ((mNumIndices * sizeof(U16)) + 0xF) & ~0xF;
|
||||
U16* remap_indices = (U16*)ll_aligned_malloc_16(size);
|
||||
|
||||
S32 tc_bytes_size = ((remap_vertices_count * sizeof(LLVector2)) + 0xF) & ~0xF;
|
||||
LLVector4a* remap_positions = (LLVector4a*)ll_aligned_malloc<64>(sizeof(LLVector4a) * 2 * remap_vertices_count + tc_bytes_size);
|
||||
LLVector4a* remap_normals = remap_positions + remap_vertices_count;
|
||||
LLVector2* remap_tex_coords = (LLVector2*)(remap_normals + remap_vertices_count);
|
||||
|
||||
// Fill the buffers
|
||||
LLMeshOptimizer::remapIndexBufferU16(remap_indices, mIndices, mNumIndices, &remap[0]);
|
||||
LLMeshOptimizer::remapPositionsBuffer(remap_positions, mPositions, mNumVertices, &remap[0]);
|
||||
LLMeshOptimizer::remapNormalsBuffer(remap_normals, mNormals, mNumVertices, &remap[0]);
|
||||
LLMeshOptimizer::remapUVBuffer(remap_tex_coords, mTexCoords, mNumVertices, &remap[0]);
|
||||
|
||||
// Free unused buffers
|
||||
ll_aligned_free_16(mIndices);
|
||||
ll_aligned_free<64>(mPositions);
|
||||
|
||||
// Tangets are now invalid
|
||||
ll_aligned_free_16(mTangents);
|
||||
mTangents = NULL;
|
||||
|
||||
// Assign new values
|
||||
mIndices = remap_indices;
|
||||
mPositions = remap_positions;
|
||||
mNormals = remap_normals;
|
||||
mTexCoords = remap_tex_coords;
|
||||
mNumVertices = remap_vertices_count;
|
||||
mNumAllocatedVertices = remap_vertices_count;
|
||||
}
|
||||
|
||||
void LLVolumeFace::optimize(F32 angle_cutoff)
|
||||
{
|
||||
LLVolumeFace new_face;
|
||||
|
|
@ -5555,21 +5601,27 @@ void LLVolumeFace::createOctree(F32 scaler, const LLVector4a& center, const LLVe
|
|||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME
|
||||
|
||||
if (mOctree)
|
||||
if (getOctree())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
mOctree = new LLOctreeRoot<LLVolumeTriangle>(center, size, NULL);
|
||||
new LLVolumeOctreeListener(mOctree);
|
||||
llassert(mNumIndices % 3 == 0);
|
||||
|
||||
for (U32 i = 0; i < mNumIndices; i+= 3)
|
||||
mOctree = new LLOctreeRoot<LLVolumeTriangle, LLVolumeTriangle*>(center, size, NULL);
|
||||
new LLVolumeOctreeListener(mOctree);
|
||||
const U32 num_triangles = mNumIndices / 3;
|
||||
// Initialize all the triangles we need
|
||||
mOctreeTriangles = new LLVolumeTriangle[num_triangles];
|
||||
|
||||
for (U32 triangle_index = 0; triangle_index < num_triangles; ++triangle_index)
|
||||
{ //for each triangle
|
||||
LLPointer<LLVolumeTriangle> tri = new LLVolumeTriangle();
|
||||
const U32 index = triangle_index * 3;
|
||||
LLVolumeTriangle* tri = &mOctreeTriangles[triangle_index];
|
||||
|
||||
const LLVector4a& v0 = mPositions[mIndices[i]];
|
||||
const LLVector4a& v1 = mPositions[mIndices[i+1]];
|
||||
const LLVector4a& v2 = mPositions[mIndices[i+2]];
|
||||
const LLVector4a& v0 = mPositions[mIndices[index]];
|
||||
const LLVector4a& v1 = mPositions[mIndices[index + 1]];
|
||||
const LLVector4a& v2 = mPositions[mIndices[index + 2]];
|
||||
|
||||
//store pointers to vertex data
|
||||
tri->mV[0] = &v0;
|
||||
|
|
@ -5577,9 +5629,9 @@ void LLVolumeFace::createOctree(F32 scaler, const LLVector4a& center, const LLVe
|
|||
tri->mV[2] = &v2;
|
||||
|
||||
//store indices
|
||||
tri->mIndex[0] = mIndices[i];
|
||||
tri->mIndex[1] = mIndices[i+1];
|
||||
tri->mIndex[2] = mIndices[i+2];
|
||||
tri->mIndex[0] = mIndices[index];
|
||||
tri->mIndex[1] = mIndices[index + 1];
|
||||
tri->mIndex[2] = mIndices[index + 2];
|
||||
|
||||
//get minimum point
|
||||
LLVector4a min = v0;
|
||||
|
|
@ -5622,6 +5674,19 @@ void LLVolumeFace::createOctree(F32 scaler, const LLVector4a& center, const LLVe
|
|||
}
|
||||
}
|
||||
|
||||
void LLVolumeFace::destroyOctree()
|
||||
{
|
||||
delete mOctree;
|
||||
mOctree = NULL;
|
||||
delete[] mOctreeTriangles;
|
||||
mOctreeTriangles = NULL;
|
||||
}
|
||||
|
||||
const LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>* LLVolumeFace::getOctree() const
|
||||
{
|
||||
return mOctree;
|
||||
}
|
||||
|
||||
|
||||
void LLVolumeFace::swapData(LLVolumeFace& rhs)
|
||||
{
|
||||
|
|
@ -6493,6 +6558,7 @@ void LLVolumeFace::allocateJointIndices(S32 num_verts)
|
|||
void LLVolumeFace::resizeIndices(S32 num_indices)
|
||||
{
|
||||
ll_aligned_free_16(mIndices);
|
||||
llassert(num_indices % 3 == 0);
|
||||
|
||||
if (num_indices)
|
||||
{
|
||||
|
|
@ -6629,13 +6695,19 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
|
|||
else
|
||||
{
|
||||
// Get s value for tex-coord.
|
||||
if (!flat)
|
||||
S32 index = mBeginS + s;
|
||||
if (index >= profile.size())
|
||||
{
|
||||
// edge?
|
||||
ss = flat ? 1.f - begin_stex : 1.f;
|
||||
}
|
||||
else if (!flat)
|
||||
{
|
||||
ss = profile[mBeginS + s][2];
|
||||
ss = profile[index][2];
|
||||
}
|
||||
else
|
||||
{
|
||||
ss = profile[mBeginS + s][2] - begin_stex;
|
||||
ss = profile[index][2] - begin_stex;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -6821,7 +6893,7 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
|
|||
|
||||
LLVector4a* norm = mNormals;
|
||||
|
||||
static LLAlignedArray<LLVector4a, 64> triangle_normals;
|
||||
static thread_local LLAlignedArray<LLVector4a, 64> triangle_normals;
|
||||
try
|
||||
{
|
||||
triangle_normals.resize(count);
|
||||
|
|
|
|||
|
|
@ -35,7 +35,8 @@ class LLVolumeParams;
|
|||
class LLProfile;
|
||||
class LLPath;
|
||||
|
||||
template <class T> class LLOctreeNode;
|
||||
template<class T> class LLPointer;
|
||||
template <class T, typename T_PTR> class LLOctreeNode;
|
||||
|
||||
class LLVolumeFace;
|
||||
class LLVolume;
|
||||
|
|
@ -902,10 +903,17 @@ public:
|
|||
typedef std::map<LLVector3, std::vector<VertexMapData>, VertexMapData::ComparePosition > PointMap;
|
||||
};
|
||||
|
||||
// Eliminates non unique triangles, takes positions,
|
||||
// normals and texture coordinates into account.
|
||||
void remap();
|
||||
|
||||
void optimize(F32 angle_cutoff = 2.f);
|
||||
bool cacheOptimize();
|
||||
|
||||
void createOctree(F32 scaler = 0.25f, const LLVector4a& center = LLVector4a(0,0,0), const LLVector4a& size = LLVector4a(0.5f,0.5f,0.5f));
|
||||
void destroyOctree();
|
||||
// Get a reference to the octree, which may be null
|
||||
const LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>* getOctree() const;
|
||||
|
||||
enum
|
||||
{
|
||||
|
|
@ -973,13 +981,14 @@ public:
|
|||
// Which joints are rigged to, and the bounding box of any rigged
|
||||
// vertices per joint.
|
||||
LLJointRiggingInfoTab mJointRiggingInfoTab;
|
||||
|
||||
LLOctreeNode<LLVolumeTriangle>* mOctree;
|
||||
|
||||
//whether or not face has been cache optimized
|
||||
BOOL mOptimized;
|
||||
|
||||
private:
|
||||
LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>* mOctree;
|
||||
LLVolumeTriangle* mOctreeTriangles;
|
||||
|
||||
BOOL createUnCutCubeCap(LLVolume* volume, BOOL partial_build = FALSE);
|
||||
BOOL createCap(LLVolume* volume, BOOL partial_build = FALSE);
|
||||
BOOL createSide(LLVolume* volume, BOOL partial_build = FALSE);
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ BOOL LLLineSegmentBoxIntersect(const LLVector4a& start, const LLVector4a& end, c
|
|||
}
|
||||
|
||||
|
||||
LLVolumeOctreeListener::LLVolumeOctreeListener(LLOctreeNode<LLVolumeTriangle>* node)
|
||||
LLVolumeOctreeListener::LLVolumeOctreeListener(LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>* node)
|
||||
{
|
||||
node->addListener(this);
|
||||
}
|
||||
|
|
@ -85,13 +85,12 @@ LLVolumeOctreeListener::~LLVolumeOctreeListener()
|
|||
|
||||
}
|
||||
|
||||
void LLVolumeOctreeListener::handleChildAddition(const LLOctreeNode<LLVolumeTriangle>* parent,
|
||||
LLOctreeNode<LLVolumeTriangle>* child)
|
||||
void LLVolumeOctreeListener::handleChildAddition(const LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>* parent,
|
||||
LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>* child)
|
||||
{
|
||||
new LLVolumeOctreeListener(child);
|
||||
}
|
||||
|
||||
|
||||
LLOctreeTriangleRayIntersect::LLOctreeTriangleRayIntersect(const LLVector4a& start, const LLVector4a& dir,
|
||||
const LLVolumeFace* face, F32* closest_t,
|
||||
LLVector4a* intersection,LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent)
|
||||
|
|
@ -108,7 +107,7 @@ LLOctreeTriangleRayIntersect::LLOctreeTriangleRayIntersect(const LLVector4a& sta
|
|||
mEnd.setAdd(mStart, mDir);
|
||||
}
|
||||
|
||||
void LLOctreeTriangleRayIntersect::traverse(const LLOctreeNode<LLVolumeTriangle>* node)
|
||||
void LLOctreeTriangleRayIntersect::traverse(const LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>* node)
|
||||
{
|
||||
LLVolumeOctreeListener* vl = (LLVolumeOctreeListener*) node->getListener(0);
|
||||
|
||||
|
|
@ -122,9 +121,9 @@ void LLOctreeTriangleRayIntersect::traverse(const LLOctreeNode<LLVolumeTriangle>
|
|||
}
|
||||
}
|
||||
|
||||
void LLOctreeTriangleRayIntersect::visit(const LLOctreeNode<LLVolumeTriangle>* node)
|
||||
void LLOctreeTriangleRayIntersect::visit(const LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>* node)
|
||||
{
|
||||
for (LLOctreeNode<LLVolumeTriangle>::const_element_iter iter =
|
||||
for (typename LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>::const_element_iter iter =
|
||||
node->getDataBegin(); iter != node->getDataEnd(); ++iter)
|
||||
{
|
||||
const LLVolumeTriangle* tri = *iter;
|
||||
|
|
@ -219,7 +218,7 @@ const F32& LLVolumeTriangle::getBinRadius() const
|
|||
|
||||
//TEST CODE
|
||||
|
||||
void LLVolumeOctreeValidate::visit(const LLOctreeNode<LLVolumeTriangle>* branch)
|
||||
void LLVolumeOctreeValidate::visit(const LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>* branch)
|
||||
{
|
||||
LLVolumeOctreeListener* node = (LLVolumeOctreeListener*) branch->getListener(0);
|
||||
|
||||
|
|
@ -256,7 +255,7 @@ void LLVolumeOctreeValidate::visit(const LLOctreeNode<LLVolumeTriangle>* branch)
|
|||
}
|
||||
|
||||
//children fit, check data
|
||||
for (LLOctreeNode<LLVolumeTriangle>::const_element_iter iter = branch->getDataBegin();
|
||||
for (typename LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>::const_element_iter iter = branch->getDataBegin();
|
||||
iter != branch->getDataEnd(); ++iter)
|
||||
{
|
||||
const LLVolumeTriangle* tri = *iter;
|
||||
|
|
@ -273,4 +272,3 @@ void LLVolumeOctreeValidate::visit(const LLOctreeNode<LLVolumeTriangle>* branch)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -77,11 +77,11 @@ public:
|
|||
|
||||
};
|
||||
|
||||
class alignas(16) LLVolumeOctreeListener : public LLOctreeListener<LLVolumeTriangle>
|
||||
class alignas(16) LLVolumeOctreeListener : public LLOctreeListener<LLVolumeTriangle, LLVolumeTriangle*>
|
||||
{
|
||||
LL_ALIGN_NEW
|
||||
public:
|
||||
LLVolumeOctreeListener(LLOctreeNode<LLVolumeTriangle>* node);
|
||||
LLVolumeOctreeListener(LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>* node);
|
||||
~LLVolumeOctreeListener();
|
||||
|
||||
LLVolumeOctreeListener(const LLVolumeOctreeListener& rhs)
|
||||
|
|
@ -96,11 +96,9 @@ public:
|
|||
}
|
||||
|
||||
//LISTENER FUNCTIONS
|
||||
virtual void handleChildAddition(const LLOctreeNode<LLVolumeTriangle>* parent,
|
||||
LLOctreeNode<LLVolumeTriangle>* child);
|
||||
virtual void handleChildAddition(const LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>* parent, LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>* child);
|
||||
virtual void handleStateChange(const LLTreeNode<LLVolumeTriangle>* node) { }
|
||||
virtual void handleChildRemoval(const LLOctreeNode<LLVolumeTriangle>* parent,
|
||||
const LLOctreeNode<LLVolumeTriangle>* child) { }
|
||||
virtual void handleChildRemoval(const LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>* parent, const LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>* child) { }
|
||||
virtual void handleInsertion(const LLTreeNode<LLVolumeTriangle>* node, LLVolumeTriangle* tri) { }
|
||||
virtual void handleRemoval(const LLTreeNode<LLVolumeTriangle>* node, LLVolumeTriangle* tri) { }
|
||||
virtual void handleDestruction(const LLTreeNode<LLVolumeTriangle>* node) { }
|
||||
|
|
@ -111,7 +109,7 @@ public:
|
|||
LL_ALIGN_16(LLVector4a mExtents[2]); // extents (min, max) of this node and all its children
|
||||
};
|
||||
|
||||
class LLOctreeTriangleRayIntersect : public LLOctreeTraveler<LLVolumeTriangle>
|
||||
class LLOctreeTriangleRayIntersect : public LLOctreeTraveler<LLVolumeTriangle, LLVolumeTriangle*>
|
||||
{
|
||||
public:
|
||||
const LLVolumeFace* mFace;
|
||||
|
|
@ -129,14 +127,14 @@ public:
|
|||
const LLVolumeFace* face, F32* closest_t,
|
||||
LLVector4a* intersection,LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent);
|
||||
|
||||
void traverse(const LLOctreeNode<LLVolumeTriangle>* node);
|
||||
void traverse(const LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>* node);
|
||||
|
||||
virtual void visit(const LLOctreeNode<LLVolumeTriangle>* node);
|
||||
virtual void visit(const LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>* node);
|
||||
};
|
||||
|
||||
class LLVolumeOctreeValidate : public LLOctreeTraveler<LLVolumeTriangle>
|
||||
class LLVolumeOctreeValidate : public LLOctreeTraveler<LLVolumeTriangle, LLVolumeTriangle*>
|
||||
{
|
||||
virtual void visit(const LLOctreeNode<LLVolumeTriangle>* branch);
|
||||
virtual void visit(const LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>* branch);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -28,6 +28,9 @@
|
|||
|
||||
#include "meshoptimizer.h"
|
||||
|
||||
#include "llmath.h"
|
||||
#include "v2math.h"
|
||||
|
||||
LLMeshOptimizer::LLMeshOptimizer()
|
||||
{
|
||||
// Todo: Looks like for memory management, we can add allocator and deallocator callbacks
|
||||
|
|
@ -40,24 +43,218 @@ LLMeshOptimizer::~LLMeshOptimizer()
|
|||
}
|
||||
|
||||
//static
|
||||
void LLMeshOptimizer::generateShadowIndexBuffer(U16 *destination,
|
||||
const U16 *indices,
|
||||
void LLMeshOptimizer::generateShadowIndexBufferU32(U32 *destination,
|
||||
const U32 *indices,
|
||||
U64 index_count,
|
||||
const LLVector4a *vertex_positions,
|
||||
U64 vertex_count,
|
||||
U64 vertex_positions_stride
|
||||
const LLVector4a * vertex_positions,
|
||||
const LLVector4a * normals,
|
||||
const LLVector2 * text_coords,
|
||||
U64 vertex_count
|
||||
)
|
||||
{
|
||||
meshopt_generateShadowIndexBuffer<unsigned short>(destination,
|
||||
meshopt_Stream streams[3];
|
||||
|
||||
S32 index = 0;
|
||||
if (vertex_positions)
|
||||
{
|
||||
streams[index].data = (const float*)vertex_positions;
|
||||
// Despite being LLVector4a, only x, y and z are in use
|
||||
streams[index].size = sizeof(F32) * 3;
|
||||
streams[index].stride = sizeof(F32) * 4;
|
||||
index++;
|
||||
}
|
||||
if (normals)
|
||||
{
|
||||
streams[index].data = (const float*)normals;
|
||||
streams[index].size = sizeof(F32) * 3;
|
||||
streams[index].stride = sizeof(F32) * 4;
|
||||
index++;
|
||||
}
|
||||
if (text_coords)
|
||||
{
|
||||
streams[index].data = (const float*)text_coords;
|
||||
streams[index].size = sizeof(F32) * 2;
|
||||
streams[index].stride = sizeof(F32) * 2;
|
||||
index++;
|
||||
}
|
||||
|
||||
if (index == 0)
|
||||
{
|
||||
// invalid
|
||||
return;
|
||||
}
|
||||
|
||||
meshopt_generateShadowIndexBufferMulti<unsigned int>(destination,
|
||||
indices,
|
||||
index_count,
|
||||
(const float*)vertex_positions, // verify that it is correct to convert to float
|
||||
vertex_count,
|
||||
sizeof(LLVector4a),
|
||||
vertex_positions_stride
|
||||
streams,
|
||||
index
|
||||
);
|
||||
}
|
||||
|
||||
//static
|
||||
void LLMeshOptimizer::generateShadowIndexBufferU16(U16 *destination,
|
||||
const U16 *indices,
|
||||
U64 index_count,
|
||||
const LLVector4a * vertex_positions,
|
||||
const LLVector4a * normals,
|
||||
const LLVector2 * text_coords,
|
||||
U64 vertex_count
|
||||
)
|
||||
{
|
||||
meshopt_Stream streams[3];
|
||||
|
||||
S32 index = 0;
|
||||
if (vertex_positions)
|
||||
{
|
||||
streams[index].data = (const float*)vertex_positions;
|
||||
streams[index].size = sizeof(F32) * 3;
|
||||
streams[index].stride = sizeof(F32) * 4;
|
||||
index++;
|
||||
}
|
||||
if (normals)
|
||||
{
|
||||
streams[index].data = (const float*)normals;
|
||||
streams[index].size = sizeof(F32) * 3;
|
||||
streams[index].stride = sizeof(F32) * 4;
|
||||
index++;
|
||||
}
|
||||
if (text_coords)
|
||||
{
|
||||
streams[index].data = (const float*)text_coords;
|
||||
streams[index].size = sizeof(F32) * 2;
|
||||
streams[index].stride = sizeof(F32) * 2;
|
||||
index++;
|
||||
}
|
||||
|
||||
if (index == 0)
|
||||
{
|
||||
// invalid
|
||||
return;
|
||||
}
|
||||
|
||||
meshopt_generateShadowIndexBufferMulti<unsigned short>(destination,
|
||||
indices,
|
||||
index_count,
|
||||
vertex_count,
|
||||
streams,
|
||||
index);
|
||||
}
|
||||
|
||||
void LLMeshOptimizer::optimizeVertexCacheU32(U32 * destination, const U32 * indices, U64 index_count, U64 vertex_count)
|
||||
{
|
||||
meshopt_optimizeVertexCache<unsigned int>(destination, indices, index_count, vertex_count);
|
||||
}
|
||||
|
||||
void LLMeshOptimizer::optimizeVertexCacheU16(U16 * destination, const U16 * indices, U64 index_count, U64 vertex_count)
|
||||
{
|
||||
meshopt_optimizeVertexCache<unsigned short>(destination, indices, index_count, vertex_count);
|
||||
}
|
||||
|
||||
size_t LLMeshOptimizer::generateRemapMultiU32(
|
||||
unsigned int* remap,
|
||||
const U32 * indices,
|
||||
U64 index_count,
|
||||
const LLVector4a * vertex_positions,
|
||||
const LLVector4a * normals,
|
||||
const LLVector2 * text_coords,
|
||||
U64 vertex_count)
|
||||
{
|
||||
meshopt_Stream streams[] = {
|
||||
{(const float*)vertex_positions, sizeof(F32) * 3, sizeof(F32) * 4},
|
||||
{(const float*)normals, sizeof(F32) * 3, sizeof(F32) * 4},
|
||||
{(const float*)text_coords, sizeof(F32) * 2, sizeof(F32) * 2},
|
||||
};
|
||||
|
||||
// Remap can function without indices,
|
||||
// but providing indices helps with removing unused vertices
|
||||
U64 indeces_cmp = indices ? index_count : vertex_count;
|
||||
|
||||
// meshopt_generateVertexRemapMulti will throw an assert if (indices[i] >= vertex_count)
|
||||
return meshopt_generateVertexRemapMulti(&remap[0], indices, indeces_cmp, vertex_count, streams, sizeof(streams) / sizeof(streams[0]));
|
||||
}
|
||||
|
||||
size_t LLMeshOptimizer::generateRemapMultiU16(
|
||||
unsigned int* remap,
|
||||
const U16 * indices,
|
||||
U64 index_count,
|
||||
const LLVector4a * vertex_positions,
|
||||
const LLVector4a * normals,
|
||||
const LLVector2 * text_coords,
|
||||
U64 vertex_count)
|
||||
{
|
||||
S32 out_of_range_count = 0;
|
||||
U32* indices_u32 = NULL;
|
||||
if (indices)
|
||||
{
|
||||
indices_u32 = (U32*)ll_aligned_malloc_32(index_count * sizeof(U32));
|
||||
for (U64 i = 0; i < index_count; i++)
|
||||
{
|
||||
if (indices[i] < vertex_count)
|
||||
{
|
||||
indices_u32[i] = (U32)indices[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
out_of_range_count++;
|
||||
indices_u32[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (out_of_range_count)
|
||||
{
|
||||
LL_WARNS() << out_of_range_count << " indices are out of range." << LL_ENDL;
|
||||
}
|
||||
|
||||
size_t unique = generateRemapMultiU32(remap, indices_u32, index_count, vertex_positions, normals, text_coords, vertex_count);
|
||||
|
||||
ll_aligned_free_32(indices_u32);
|
||||
|
||||
return unique;
|
||||
}
|
||||
|
||||
void LLMeshOptimizer::remapIndexBufferU32(U32 * destination_indices,
|
||||
const U32 * indices,
|
||||
U64 index_count,
|
||||
const unsigned int* remap)
|
||||
{
|
||||
meshopt_remapIndexBuffer<unsigned int>(destination_indices, indices, index_count, remap);
|
||||
}
|
||||
|
||||
void LLMeshOptimizer::remapIndexBufferU16(U16 * destination_indices,
|
||||
const U16 * indices,
|
||||
U64 index_count,
|
||||
const unsigned int* remap)
|
||||
{
|
||||
meshopt_remapIndexBuffer<unsigned short>(destination_indices, indices, index_count, remap);
|
||||
}
|
||||
|
||||
void LLMeshOptimizer::remapPositionsBuffer(LLVector4a * destination_vertices,
|
||||
const LLVector4a * vertex_positions,
|
||||
U64 vertex_count,
|
||||
const unsigned int* remap)
|
||||
{
|
||||
meshopt_remapVertexBuffer((float*)destination_vertices, (const float*)vertex_positions, vertex_count, sizeof(LLVector4a), remap);
|
||||
}
|
||||
|
||||
void LLMeshOptimizer::remapNormalsBuffer(LLVector4a * destination_normalss,
|
||||
const LLVector4a * normals,
|
||||
U64 mormals_count,
|
||||
const unsigned int* remap)
|
||||
{
|
||||
meshopt_remapVertexBuffer((float*)destination_normalss, (const float*)normals, mormals_count, sizeof(LLVector4a), remap);
|
||||
}
|
||||
|
||||
void LLMeshOptimizer::remapUVBuffer(LLVector2 * destination_uvs,
|
||||
const LLVector2 * uv_positions,
|
||||
U64 uv_count,
|
||||
const unsigned int* remap)
|
||||
{
|
||||
meshopt_remapVertexBuffer((float*)destination_uvs, (const float*)uv_positions, uv_count, sizeof(LLVector2), remap);
|
||||
}
|
||||
|
||||
//static
|
||||
U64 LLMeshOptimizer::simplifyU32(U32 *destination,
|
||||
const U32 *indices,
|
||||
|
|
|
|||
|
|
@ -28,7 +28,8 @@
|
|||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llmath.h"
|
||||
class LLVector4a;
|
||||
class LLVector2;
|
||||
|
||||
class LLMeshOptimizer
|
||||
{
|
||||
|
|
@ -36,13 +37,85 @@ public:
|
|||
LLMeshOptimizer();
|
||||
~LLMeshOptimizer();
|
||||
|
||||
static void generateShadowIndexBuffer(
|
||||
static void generateShadowIndexBufferU32(
|
||||
U32 *destination,
|
||||
const U32 *indices,
|
||||
U64 index_count,
|
||||
const LLVector4a * vertex_positions,
|
||||
const LLVector4a * normals,
|
||||
const LLVector2 * text_coords,
|
||||
U64 vertex_count);
|
||||
|
||||
static void generateShadowIndexBufferU16(
|
||||
U16 *destination,
|
||||
const U16 *indices,
|
||||
U64 index_count,
|
||||
const LLVector4a *vertex_positions,
|
||||
const LLVector4a * vertex_positions,
|
||||
const LLVector4a * normals,
|
||||
const LLVector2 * text_coords,
|
||||
U64 vertex_count);
|
||||
|
||||
static void optimizeVertexCacheU32(
|
||||
U32 *destination,
|
||||
const U32 *indices,
|
||||
U64 index_count,
|
||||
U64 vertex_count);
|
||||
|
||||
static void optimizeVertexCacheU16(
|
||||
U16 *destination,
|
||||
const U16 *indices,
|
||||
U64 index_count,
|
||||
U64 vertex_count);
|
||||
|
||||
// Remap functions
|
||||
// Welds indentical vertexes together.
|
||||
// Removes unused vertices if indices were provided.
|
||||
|
||||
static size_t generateRemapMultiU32(
|
||||
unsigned int* remap,
|
||||
const U32 * indices,
|
||||
U64 index_count,
|
||||
const LLVector4a * vertex_positions,
|
||||
const LLVector4a * normals,
|
||||
const LLVector2 * text_coords,
|
||||
U64 vertex_count);
|
||||
|
||||
static size_t generateRemapMultiU16(
|
||||
unsigned int* remap,
|
||||
const U16 * indices,
|
||||
U64 index_count,
|
||||
const LLVector4a * vertex_positions,
|
||||
const LLVector4a * normals,
|
||||
const LLVector2 * text_coords,
|
||||
U64 vertex_count);
|
||||
|
||||
static void remapIndexBufferU32(U32 * destination_indices,
|
||||
const U32 * indices,
|
||||
U64 index_count,
|
||||
const unsigned int* remap);
|
||||
|
||||
static void remapIndexBufferU16(U16 * destination_indices,
|
||||
const U16 * indices,
|
||||
U64 index_count,
|
||||
const unsigned int* remap);
|
||||
|
||||
|
||||
static void remapPositionsBuffer(LLVector4a * destination_vertices,
|
||||
const LLVector4a * vertex_positions,
|
||||
U64 vertex_count,
|
||||
U64 vertex_positions_stride);
|
||||
const unsigned int* remap);
|
||||
|
||||
static void remapNormalsBuffer(LLVector4a * destination_normalss,
|
||||
const LLVector4a * normals,
|
||||
U64 mormals_count,
|
||||
const unsigned int* remap);
|
||||
|
||||
static void remapUVBuffer(LLVector2 * destination_uvs,
|
||||
const LLVector2 * uv_positions,
|
||||
U64 uv_count,
|
||||
const unsigned int* remap);
|
||||
|
||||
// Simplification
|
||||
|
||||
// returns amount of indices in destiantion
|
||||
// sloppy engages a variant of a mechanizm that does not respect topology as much
|
||||
|
|
|
|||
|
|
@ -196,6 +196,10 @@ void LLAvatarNameCache::requestAvatarNameCache_(std::string url, std::vector<LLU
|
|||
LLAvatarNameCache::getInstance()->handleAvNameCacheSuccess(results, httpResults);
|
||||
}
|
||||
}
|
||||
catch (const LLCoros::Stop&)
|
||||
{
|
||||
LL_DEBUGS("AvNameCache") << "Received a shutdown exception" << LL_ENDL;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG_UNHANDLED_EXCEPTION(STRINGIZE("coroutine " << LLCoros::getName()
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@
|
|||
#include "llcoros.h"
|
||||
#include "llcorehttputil.h"
|
||||
#include "lluuid.h"
|
||||
#include <boost/smart_ptr/shared_ptr.hpp>
|
||||
|
||||
class LLCoprocedurePool;
|
||||
|
||||
|
|
@ -84,7 +83,7 @@ public:
|
|||
|
||||
private:
|
||||
|
||||
typedef boost::shared_ptr<LLCoprocedurePool> poolPtr_t;
|
||||
typedef std::shared_ptr<LLCoprocedurePool> poolPtr_t;
|
||||
typedef std::map<std::string, poolPtr_t> poolMap_t;
|
||||
|
||||
poolMap_t mPoolMap;
|
||||
|
|
|
|||
|
|
@ -127,13 +127,7 @@ BOOL LLDataPacker::unpackFixed(F32 &value, const char *name,
|
|||
total_bits++;
|
||||
}
|
||||
|
||||
S32 min_val;
|
||||
U32 max_val;
|
||||
if (is_signed)
|
||||
{
|
||||
min_val = 1 << int_bits;
|
||||
min_val *= -1;
|
||||
}
|
||||
max_val = 1 << int_bits;
|
||||
|
||||
F32 fixed_val;
|
||||
|
|
|
|||
|
|
@ -311,8 +311,9 @@ BOOL LLPartSysData::unpack(LLDataPacker &dp)
|
|||
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 << "Pattern: " << std::hex << (U32) data.mPattern << "\n";
|
||||
s << "Source Age: [" << data.mStartAge << ", " << data.mMaxAge << "]\n";
|
||||
s << "Particle Age: " << data.mPartData.mMaxAge << "\n";
|
||||
s << "Angle: [" << data.mInnerAngle << ", " << data.mOuterAngle << "]\n";
|
||||
s << "Burst Rate: " << data.mBurstRate << "\n";
|
||||
s << "Burst Radius: " << data.mBurstRadius << "\n";
|
||||
|
|
|
|||
|
|
@ -374,7 +374,6 @@ BOOL LLThrottleGroup::dynamicAdjust()
|
|||
}
|
||||
mDynamicAdjustTime = mt_sec;
|
||||
|
||||
S32 total = 0;
|
||||
// Update historical information
|
||||
for (i = 0; i < TC_EOF; i++)
|
||||
{
|
||||
|
|
@ -391,7 +390,6 @@ BOOL LLThrottleGroup::dynamicAdjust()
|
|||
}
|
||||
|
||||
mBitsSentThisPeriod[i] = 0;
|
||||
total += ll_round(mBitsSentHistory[i]);
|
||||
}
|
||||
|
||||
// Look for busy channels
|
||||
|
|
|
|||
|
|
@ -1386,6 +1386,7 @@ char const* const _PREHASH_RegionAllowAccessBlock = LLMessageStringTable::getIns
|
|||
char const* const _PREHASH_RegionAllowAccessOverride = LLMessageStringTable::getInstance()->getString("RegionAllowAccessOverride");
|
||||
char const* const _PREHASH_ParcelEnvironmentBlock = LLMessageStringTable::getInstance()->getString("ParcelEnvironmentBlock");
|
||||
char const* const _PREHASH_ParcelEnvironmentVersion = LLMessageStringTable::getInstance()->getString("ParcelEnvironmentVersion");
|
||||
char const* const _PREHASH_ParcelExtendedFlags = LLMessageStringTable::getInstance()->getString("ParcelExtendedFlags");
|
||||
char const* const _PREHASH_RegionAllowEnvironmentOverride = LLMessageStringTable::getInstance()->getString("RegionAllowEnvironmentOverride");
|
||||
char const* const _PREHASH_UCoord = LLMessageStringTable::getInstance()->getString("UCoord");
|
||||
char const* const _PREHASH_VCoord = LLMessageStringTable::getInstance()->getString("VCoord");
|
||||
|
|
|
|||
|
|
@ -1386,6 +1386,7 @@ extern char const* const _PREHASH_RegionAllowAccessBlock;
|
|||
extern char const* const _PREHASH_RegionAllowAccessOverride;
|
||||
extern char const* const _PREHASH_ParcelEnvironmentBlock;
|
||||
extern char const* const _PREHASH_ParcelEnvironmentVersion;
|
||||
extern char const* const _PREHASH_ParcelExtendedFlags;
|
||||
extern char const* const _PREHASH_RegionAllowEnvironmentOverride;
|
||||
extern char const* const _PREHASH_UCoord;
|
||||
extern char const* const _PREHASH_VCoord;
|
||||
|
|
|
|||
|
|
@ -1549,6 +1549,7 @@ void LLPluginClassMedia::seek(float time)
|
|||
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "seek");
|
||||
|
||||
message.setValueReal("time", time);
|
||||
mCurrentTime = time; // assume that it worked and we will receive an update later
|
||||
|
||||
sendMessage(message);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -999,7 +999,7 @@ void LLPluginProcessParent::poll(F64 timeout)
|
|||
while (itClean != sInstances.end())
|
||||
{
|
||||
if ((*itClean).second->isDone())
|
||||
sInstances.erase(itClean++);
|
||||
itClean = sInstances.erase(itClean);
|
||||
else
|
||||
++itClean;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2577,7 +2577,7 @@ bool LLDAELoader::loadModelsFromDomMesh(domMesh* mesh, std::vector<LLModel*>& mo
|
|||
|
||||
if (!mNoOptimize)
|
||||
{
|
||||
ret->optimizeVolumeFaces();
|
||||
ret->remapVolumeFaces();
|
||||
}
|
||||
|
||||
volume_faces = remainder.size();
|
||||
|
|
|
|||
|
|
@ -107,6 +107,14 @@ void LLModel::offsetMesh( const LLVector3& pivotPoint )
|
|||
}
|
||||
}
|
||||
|
||||
void LLModel::remapVolumeFaces()
|
||||
{
|
||||
for (U32 i = 0; i < getNumVolumeFaces(); ++i)
|
||||
{
|
||||
mVolumeFaces[i].remap();
|
||||
}
|
||||
}
|
||||
|
||||
void LLModel::optimizeVolumeFaces()
|
||||
{
|
||||
for (U32 i = 0; i < getNumVolumeFaces(); ++i)
|
||||
|
|
@ -371,6 +379,8 @@ void LLModel::setVolumeFaceData(
|
|||
U32 num_verts,
|
||||
U32 num_indices)
|
||||
{
|
||||
llassert(num_indices % 3 == 0);
|
||||
|
||||
LLVolumeFace& face = mVolumeFaces[f];
|
||||
|
||||
face.resizeVertices(num_verts);
|
||||
|
|
@ -835,7 +845,7 @@ LLSD LLModel::writeModel(
|
|||
{
|
||||
LLVector3 pos(face.mPositions[j].getF32ptr());
|
||||
|
||||
weight_list& weights = high->getJointInfluences(pos);
|
||||
weight_list& weights = model[idx]->getJointInfluences(pos);
|
||||
|
||||
S32 count = 0;
|
||||
for (weight_list::iterator iter = weights.begin(); iter != weights.end(); ++iter)
|
||||
|
|
@ -881,8 +891,6 @@ LLSD LLModel::writeModel(
|
|||
|
||||
LLSD LLModel::writeModelToStream(std::ostream& ostr, LLSD& mdl, BOOL nowrite, BOOL as_slm)
|
||||
{
|
||||
U32 bytes = 0;
|
||||
|
||||
std::string::size_type cur_offset = 0;
|
||||
|
||||
LLSD header;
|
||||
|
|
@ -904,7 +912,6 @@ LLSD LLModel::writeModelToStream(std::ostream& ostr, LLSD& mdl, BOOL nowrite, BO
|
|||
header["skin"]["offset"] = (LLSD::Integer) cur_offset;
|
||||
header["skin"]["size"] = (LLSD::Integer) size;
|
||||
cur_offset += size;
|
||||
bytes += size;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -920,7 +927,6 @@ LLSD LLModel::writeModelToStream(std::ostream& ostr, LLSD& mdl, BOOL nowrite, BO
|
|||
header["physics_convex"]["offset"] = (LLSD::Integer) cur_offset;
|
||||
header["physics_convex"]["size"] = (LLSD::Integer) size;
|
||||
cur_offset += size;
|
||||
bytes += size;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -942,7 +948,6 @@ LLSD LLModel::writeModelToStream(std::ostream& ostr, LLSD& mdl, BOOL nowrite, BO
|
|||
header[model_names[i]]["offset"] = (LLSD::Integer) cur_offset;
|
||||
header[model_names[i]]["size"] = (LLSD::Integer) size;
|
||||
cur_offset += size;
|
||||
bytes += size;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1545,6 +1550,25 @@ void LLMeshSkinInfo::updateHash()
|
|||
mHash = digest[0];
|
||||
}
|
||||
|
||||
U32 LLMeshSkinInfo::sizeBytes() const
|
||||
{
|
||||
U32 res = sizeof(LLUUID); // mMeshID
|
||||
|
||||
res += sizeof(std::vector<std::string>) + sizeof(std::string) * mJointNames.size();
|
||||
for (U32 i = 0; i < mJointNames.size(); ++i)
|
||||
{
|
||||
res += mJointNames[i].size(); // actual size, not capacity
|
||||
}
|
||||
|
||||
res += sizeof(std::vector<S32>) + sizeof(S32) * mJointNums.size();
|
||||
res += sizeof(std::vector<LLMatrix4>) + 16 * sizeof(float) * mInvBindMatrix.size();
|
||||
res += sizeof(std::vector<LLMatrix4>) + 16 * sizeof(float) * mAlternateBindMatrix.size();
|
||||
res += 16 * sizeof(float); //mBindShapeMatrix
|
||||
res += sizeof(float) + 3 * sizeof(bool);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
LLModel::Decomposition::Decomposition(LLSD& data)
|
||||
{
|
||||
fromLLSD(data);
|
||||
|
|
@ -1651,6 +1675,30 @@ void LLModel::Decomposition::fromLLSD(LLSD& decomp)
|
|||
}
|
||||
}
|
||||
|
||||
U32 LLModel::Decomposition::sizeBytes() const
|
||||
{
|
||||
U32 res = sizeof(LLUUID); // mMeshID
|
||||
|
||||
res += sizeof(LLModel::convex_hull_decomposition) + sizeof(std::vector<LLVector3>) * mHull.size();
|
||||
for (U32 i = 0; i < mHull.size(); ++i)
|
||||
{
|
||||
res += mHull[i].size() * sizeof(LLVector3);
|
||||
}
|
||||
|
||||
res += sizeof(LLModel::hull) + sizeof(LLVector3) * mBaseHull.size();
|
||||
|
||||
res += sizeof(std::vector<LLModel::PhysicsMesh>) + sizeof(std::vector<LLModel::PhysicsMesh>) * mMesh.size();
|
||||
for (U32 i = 0; i < mMesh.size(); ++i)
|
||||
{
|
||||
res += mMesh[i].sizeBytes();
|
||||
}
|
||||
|
||||
res += sizeof(std::vector<LLModel::PhysicsMesh>) * 2;
|
||||
res += mBaseHullMesh.sizeBytes() + mPhysicsShapeMesh.sizeBytes();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool LLModel::Decomposition::hasHullList() const
|
||||
{
|
||||
return !mHull.empty() ;
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ public:
|
|||
void fromLLSD(LLSD& data);
|
||||
LLSD asLLSD(bool include_joints, bool lock_scale_if_joint_position) const;
|
||||
void updateHash();
|
||||
U32 sizeBytes() const;
|
||||
|
||||
LLUUID mMeshID;
|
||||
std::vector<std::string> mJointNames;
|
||||
|
|
@ -112,6 +113,14 @@ public:
|
|||
{
|
||||
return mPositions.empty();
|
||||
}
|
||||
|
||||
U32 sizeBytes() const
|
||||
{
|
||||
U32 res = sizeof(std::vector<LLVector3>) * 2;
|
||||
res += sizeof(LLVector3) * mPositions.size();
|
||||
res += sizeof(LLVector3) * mNormals.size();
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
class Decomposition
|
||||
|
|
@ -122,6 +131,7 @@ public:
|
|||
void fromLLSD(LLSD& data);
|
||||
LLSD asLLSD() const;
|
||||
bool hasHullList() const;
|
||||
U32 sizeBytes() const;
|
||||
|
||||
void merge(const Decomposition* rhs);
|
||||
|
||||
|
|
@ -184,6 +194,7 @@ public:
|
|||
void sortVolumeFacesByMaterialName();
|
||||
void normalizeVolumeFaces();
|
||||
void trimVolumeFacesToSize(U32 new_count = LL_SCULPT_MESH_MAX_FACES, LLVolume::face_list_t* remainder = NULL);
|
||||
void remapVolumeFaces();
|
||||
void optimizeVolumeFaces();
|
||||
void offsetMesh( const LLVector3& pivotPoint );
|
||||
void getNormalizedScaleTranslation(LLVector3& scale_out, LLVector3& translation_out);
|
||||
|
|
|
|||
|
|
@ -743,6 +743,14 @@ bool LLGLManager::initGL()
|
|||
LL_WARNS("RenderInit") << "GL Drivers do not support GL_ARB_multitexture" << LL_ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mHasFramebufferObject)
|
||||
{
|
||||
mHasRequirements = FALSE;
|
||||
|
||||
LL_WARNS("RenderInit") << "GL Drivers do not support GL_ARB_framebuffer_object" << LL_ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
stop_glerror();
|
||||
|
||||
|
|
@ -758,12 +766,6 @@ bool LLGLManager::initGL()
|
|||
|
||||
//HACK always disable texture multisample, use FXAA instead
|
||||
mHasTextureMultisample = FALSE;
|
||||
#if LL_WINDOWS
|
||||
if (mIsIntel && mGLVersion <= 3.f)
|
||||
{ //never try to use framebuffer objects on older intel drivers (crashy)
|
||||
mHasFramebufferObject = FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (mHasFramebufferObject)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1248,7 +1248,12 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt
|
|||
if (pixels != nullptr)
|
||||
{
|
||||
use_scratch = true;
|
||||
scratch = new U32[width * height];
|
||||
scratch = new(std::nothrow) U32[width * height];
|
||||
if (!scratch)
|
||||
{
|
||||
LL_ERRS() << "Failed to allocate " << (U32)(width * height * sizeof(U32))
|
||||
<< " bytes for a manual image W" << width << " H" << height << LL_ENDL;
|
||||
}
|
||||
|
||||
U32 pixel_count = (U32)(width * height);
|
||||
for (U32 i = 0; i < pixel_count; i++)
|
||||
|
|
@ -1268,7 +1273,12 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt
|
|||
if (pixels != nullptr)
|
||||
{
|
||||
use_scratch = true;
|
||||
scratch = new U32[width * height];
|
||||
scratch = new(std::nothrow) U32[width * height];
|
||||
if (!scratch)
|
||||
{
|
||||
LL_ERRS() << "Failed to allocate " << (U32)(width * height * sizeof(U32))
|
||||
<< " bytes for a manual image W" << width << " H" << height << LL_ENDL;
|
||||
}
|
||||
|
||||
U32 pixel_count = (U32)(width * height);
|
||||
for (U32 i = 0; i < pixel_count; i++)
|
||||
|
|
@ -1291,7 +1301,12 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt
|
|||
if (pixels != nullptr)
|
||||
{
|
||||
use_scratch = true;
|
||||
scratch = new U32[width * height];
|
||||
scratch = new(std::nothrow) U32[width * height];
|
||||
if (!scratch)
|
||||
{
|
||||
LL_ERRS() << "Failed to allocate " << (U32)(width * height * sizeof(U32))
|
||||
<< " bytes for a manual image W" << width << " H" << height << LL_ENDL;
|
||||
}
|
||||
|
||||
U32 pixel_count = (U32)(width * height);
|
||||
for (U32 i = 0; i < pixel_count; i++)
|
||||
|
|
@ -2432,7 +2447,7 @@ void LLImageGLThread::run()
|
|||
// We must perform setup on this thread before actually servicing our
|
||||
// WorkQueue, likewise cleanup afterwards.
|
||||
mWindow->makeContextCurrent(mContext);
|
||||
gGL.init();
|
||||
gGL.init(false);
|
||||
ThreadPool::run();
|
||||
gGL.shutdown();
|
||||
mWindow->destroySharedContext(mContext);
|
||||
|
|
|
|||
|
|
@ -869,7 +869,7 @@ LLRender::~LLRender()
|
|||
shutdown();
|
||||
}
|
||||
|
||||
void LLRender::init()
|
||||
void LLRender::init(bool needs_vertex_buffer)
|
||||
{
|
||||
#if LL_WINDOWS
|
||||
if (gGLManager.mHasDebugOutput && gDebugGL)
|
||||
|
|
@ -897,15 +897,27 @@ void LLRender::init()
|
|||
#endif
|
||||
}
|
||||
|
||||
if (needs_vertex_buffer)
|
||||
{
|
||||
initVertexBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
llassert_always(mBuffer.isNull()) ;
|
||||
stop_glerror();
|
||||
mBuffer = new LLVertexBuffer(immediate_mask, 0);
|
||||
mBuffer->allocateBuffer(4096, 0, TRUE);
|
||||
mBuffer->getVertexStrider(mVerticesp);
|
||||
mBuffer->getTexCoord0Strider(mTexcoordsp);
|
||||
mBuffer->getColorStrider(mColorsp);
|
||||
stop_glerror();
|
||||
void LLRender::initVertexBuffer()
|
||||
{
|
||||
llassert_always(mBuffer.isNull());
|
||||
stop_glerror();
|
||||
mBuffer = new LLVertexBuffer(immediate_mask, 0);
|
||||
mBuffer->allocateBuffer(4096, 0, TRUE);
|
||||
mBuffer->getVertexStrider(mVerticesp);
|
||||
mBuffer->getTexCoord0Strider(mTexcoordsp);
|
||||
mBuffer->getColorStrider(mColorsp);
|
||||
stop_glerror();
|
||||
}
|
||||
|
||||
void LLRender::resetVertexBuffer()
|
||||
{
|
||||
mBuffer = NULL;
|
||||
}
|
||||
|
||||
void LLRender::shutdown()
|
||||
|
|
@ -923,7 +935,7 @@ void LLRender::shutdown()
|
|||
delete mLightState[i];
|
||||
}
|
||||
mLightState.clear();
|
||||
mBuffer = NULL ;
|
||||
resetVertexBuffer();
|
||||
}
|
||||
|
||||
void LLRender::refreshState(void)
|
||||
|
|
@ -1625,25 +1637,34 @@ void LLRender::flush()
|
|||
|
||||
mCount = 0;
|
||||
|
||||
if (mBuffer->useVBOs() && !mBuffer->isLocked())
|
||||
{ //hack to only flush the part of the buffer that was updated (relies on stream draw using buffersubdata)
|
||||
mBuffer->getVertexStrider(mVerticesp, 0, count);
|
||||
mBuffer->getTexCoord0Strider(mTexcoordsp, 0, count);
|
||||
mBuffer->getColorStrider(mColorsp, 0, count);
|
||||
}
|
||||
|
||||
mBuffer->flush();
|
||||
mBuffer->setBuffer(immediate_mask);
|
||||
if (mBuffer)
|
||||
{
|
||||
if (mBuffer->useVBOs() && !mBuffer->isLocked())
|
||||
{ //hack to only flush the part of the buffer that was updated (relies on stream draw using buffersubdata)
|
||||
mBuffer->getVertexStrider(mVerticesp, 0, count);
|
||||
mBuffer->getTexCoord0Strider(mTexcoordsp, 0, count);
|
||||
mBuffer->getColorStrider(mColorsp, 0, count);
|
||||
}
|
||||
|
||||
mBuffer->flush();
|
||||
mBuffer->setBuffer(immediate_mask);
|
||||
|
||||
if (mMode == LLRender::QUADS && sGLCoreProfile)
|
||||
{
|
||||
mBuffer->drawArrays(LLRender::TRIANGLES, 0, count);
|
||||
mQuadCycle = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
mBuffer->drawArrays(mMode, 0, count);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// mBuffer is present in main thread and not present in an image thread
|
||||
LL_ERRS() << "A flush call from outside main rendering thread" << LL_ENDL;
|
||||
}
|
||||
|
||||
if (mMode == LLRender::QUADS && sGLCoreProfile)
|
||||
{
|
||||
mBuffer->drawArrays(LLRender::TRIANGLES, 0, count);
|
||||
mQuadCycle = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
mBuffer->drawArrays(mMode, 0, count);
|
||||
}
|
||||
|
||||
mVerticesp[0] = mVerticesp[count];
|
||||
mTexcoordsp[0] = mTexcoordsp[count];
|
||||
|
|
|
|||
|
|
@ -354,7 +354,9 @@ public:
|
|||
|
||||
LLRender();
|
||||
~LLRender();
|
||||
void init() ;
|
||||
void init(bool needs_vertex_buffer);
|
||||
void initVertexBuffer();
|
||||
void resetVertexBuffer();
|
||||
void shutdown();
|
||||
|
||||
// Refreshes renderer state to the cached values
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@ bool LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, boo
|
|||
mUsage = usage;
|
||||
mUseDepth = depth;
|
||||
|
||||
if ((sUseFBO || use_fbo) && gGLManager.mHasFramebufferObject)
|
||||
if (sUseFBO || use_fbo)
|
||||
{
|
||||
if (depth)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -665,7 +665,7 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
|
|||
|
||||
if (file == NULL)
|
||||
{
|
||||
LL_SHADER_LOADING_WARNS() << "GLSL Shader file not found: " << open_file_name << LL_ENDL;
|
||||
LL_WARNS("ShaderLoading") << "GLSL Shader file not found: " << open_file_name << LL_ENDL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1061,7 +1061,7 @@ void LLVertexBuffer::releaseIndices()
|
|||
|
||||
bool LLVertexBuffer::createGLBuffer(U32 size)
|
||||
{
|
||||
if (mGLBuffer)
|
||||
if (mGLBuffer || mMappedData)
|
||||
{
|
||||
destroyGLBuffer();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -266,7 +266,6 @@ public:
|
|||
bool getTangentStrider(LLStrider<LLVector3>& strider, S32 index=0, S32 count = -1, bool map_range = false);
|
||||
bool getTangentStrider(LLStrider<LLVector4a>& strider, S32 index=0, S32 count = -1, bool map_range = false);
|
||||
bool getColorStrider(LLStrider<LLColor4U>& strider, S32 index=0, S32 count = -1, bool map_range = false);
|
||||
bool getTextureIndexStrider(LLStrider<LLColor4U>& strider, S32 index=0, S32 count = -1, bool map_range = false);
|
||||
bool getEmissiveStrider(LLStrider<LLColor4U>& strider, S32 index=0, S32 count = -1, bool map_range = false);
|
||||
bool getWeightStrider(LLStrider<F32>& strider, S32 index=0, S32 count = -1, bool map_range = false);
|
||||
bool getWeight4Strider(LLStrider<LLVector4>& strider, S32 index=0, S32 count = -1, bool map_range = false);
|
||||
|
|
|
|||
|
|
@ -102,6 +102,7 @@ LLButton::Params::Params()
|
|||
scale_image("scale_image", true),
|
||||
hover_glow_amount("hover_glow_amount"),
|
||||
commit_on_return("commit_on_return", true),
|
||||
commit_on_capture_lost("commit_on_capture_lost", false),
|
||||
display_pressed_state("display_pressed_state", true),
|
||||
use_draw_context_alpha("use_draw_context_alpha", true),
|
||||
badge("badge"),
|
||||
|
|
@ -165,6 +166,7 @@ LLButton::LLButton(const LLButton::Params& p)
|
|||
mBottomVPad(p.pad_bottom),
|
||||
mHoverGlowStrength(p.hover_glow_amount),
|
||||
mCommitOnReturn(p.commit_on_return),
|
||||
mCommitOnCaptureLost(p.commit_on_capture_lost),
|
||||
mFadeWhenDisabled(FALSE),
|
||||
mForcePressedState(false),
|
||||
mDisplayPressedState(p.display_pressed_state),
|
||||
|
|
@ -475,6 +477,10 @@ BOOL LLButton::handleMouseUp(S32 x, S32 y, MASK mask)
|
|||
// We only handle the click if the click both started and ended within us
|
||||
if( hasMouseCapture() )
|
||||
{
|
||||
// reset timers before focus change, to not cause
|
||||
// additional commits if mCommitOnCaptureLost.
|
||||
resetMouseDownTimer();
|
||||
|
||||
// Always release the mouse
|
||||
gFocusMgr.setMouseCapture( NULL );
|
||||
|
||||
|
|
@ -489,8 +495,6 @@ BOOL LLButton::handleMouseUp(S32 x, S32 y, MASK mask)
|
|||
// Regardless of where mouseup occurs, handle callback
|
||||
if(mMouseUpSignal) (*mMouseUpSignal)(this, LLSD());
|
||||
|
||||
resetMouseDownTimer();
|
||||
|
||||
// DO THIS AT THE VERY END to allow the button to be destroyed as a result of being clicked.
|
||||
// If mouseup in the widget, it's been clicked
|
||||
if (pointInView(x, y))
|
||||
|
|
@ -1195,6 +1199,18 @@ void LLButton::setImageOverlay(const LLUUID& image_id, LLFontGL::HAlign alignmen
|
|||
|
||||
void LLButton::onMouseCaptureLost()
|
||||
{
|
||||
if (mCommitOnCaptureLost
|
||||
&& mMouseDownTimer.getStarted())
|
||||
{
|
||||
if (mMouseUpSignal) (*mMouseUpSignal)(this, LLSD());
|
||||
|
||||
if (mIsToggle)
|
||||
{
|
||||
toggleState();
|
||||
}
|
||||
|
||||
LLUICtrl::onCommit();
|
||||
}
|
||||
resetMouseDownTimer();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -124,6 +124,7 @@ public:
|
|||
Optional<bool> is_toggle,
|
||||
scale_image,
|
||||
commit_on_return,
|
||||
commit_on_capture_lost,
|
||||
display_pressed_state;
|
||||
|
||||
Optional<F32> hover_glow_amount;
|
||||
|
|
@ -374,6 +375,7 @@ protected:
|
|||
F32 mCurGlowStrength;
|
||||
|
||||
bool mCommitOnReturn;
|
||||
bool mCommitOnCaptureLost;
|
||||
bool mFadeWhenDisabled;
|
||||
bool mForcePressedState;
|
||||
bool mDisplayPressedState;
|
||||
|
|
|
|||
|
|
@ -259,6 +259,7 @@ LLFloater::LLFloater(const LLSD& key, const LLFloater::Params& p)
|
|||
mMinHeight(p.min_height),
|
||||
mHeaderHeight(p.header_height),
|
||||
mLegacyHeaderHeight(p.legacy_header_height),
|
||||
mDefaultRectForGroup(true),
|
||||
mMinimized(FALSE),
|
||||
mForeground(FALSE),
|
||||
mFirstLook(TRUE),
|
||||
|
|
@ -761,17 +762,13 @@ void LLFloater::closeFloater(bool app_quitting)
|
|||
for(handle_set_iter_t dependent_it = mDependents.begin();
|
||||
dependent_it != mDependents.end(); )
|
||||
{
|
||||
|
||||
LLFloater* floaterp = dependent_it->get();
|
||||
if (floaterp)
|
||||
{
|
||||
++dependent_it;
|
||||
floaterp->closeFloater(app_quitting);
|
||||
}
|
||||
else
|
||||
{
|
||||
mDependents.erase(dependent_it++);
|
||||
}
|
||||
dependent_it = mDependents.erase(dependent_it);
|
||||
if (floaterp)
|
||||
{
|
||||
floaterp->mDependeeHandle = LLHandle<LLFloater>();
|
||||
floaterp->closeFloater(app_quitting);
|
||||
}
|
||||
}
|
||||
|
||||
cleanupHandles();
|
||||
|
|
@ -906,7 +903,10 @@ bool LLFloater::applyRectControl()
|
|||
if (last_in_group && last_in_group != this)
|
||||
{
|
||||
// other floaters in our group, position ourselves relative to them and don't save the rect
|
||||
mRectControl.clear();
|
||||
if (mDefaultRectForGroup)
|
||||
{
|
||||
mRectControl.clear();
|
||||
}
|
||||
mPositioning = LLFloaterEnums::POSITIONING_CASCADE_GROUP;
|
||||
}
|
||||
else
|
||||
|
|
@ -1439,7 +1439,7 @@ void LLFloater::cleanupHandles()
|
|||
LLFloater* floaterp = dependent_it->get();
|
||||
if (!floaterp)
|
||||
{
|
||||
mDependents.erase(dependent_it++);
|
||||
dependent_it = mDependents.erase(dependent_it);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -3481,8 +3481,15 @@ void LLFloater::stackWith(LLFloater& other)
|
|||
}
|
||||
next_rect.translate(floater_offset, -floater_offset);
|
||||
|
||||
next_rect.setLeftTopAndSize(next_rect.mLeft, next_rect.mTop, getRect().getWidth(), getRect().getHeight());
|
||||
|
||||
const LLRect& rect = getControlGroup()->getRect(mRectControl);
|
||||
if (rect.notEmpty() && !mDefaultRectForGroup && mResizable)
|
||||
{
|
||||
next_rect.setLeftTopAndSize(next_rect.mLeft, next_rect.mTop, llmax(mMinWidth, rect.getWidth()), llmax(mMinHeight, rect.getHeight()));
|
||||
}
|
||||
else
|
||||
{
|
||||
next_rect.setLeftTopAndSize(next_rect.mLeft, next_rect.mTop, getRect().getWidth(), getRect().getHeight());
|
||||
}
|
||||
setShape(next_rect);
|
||||
|
||||
if (!other.getHost())
|
||||
|
|
|
|||
|
|
@ -454,6 +454,7 @@ public:
|
|||
|
||||
protected:
|
||||
bool mSaveRect;
|
||||
bool mDefaultRectForGroup;
|
||||
std::string mRectControl;
|
||||
std::string mPosXControl;
|
||||
std::string mPosYControl;
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
#include "llui.h"
|
||||
#include "lluictrlfactory.h"
|
||||
#include "lluiimage.h"
|
||||
#include "llwindow.h"
|
||||
|
||||
static LLDefaultChildRegistry::Register<LLIconCtrl> r("icon");
|
||||
|
||||
|
|
@ -42,6 +43,7 @@ LLIconCtrl::Params::Params()
|
|||
: image("image_name"),
|
||||
color("color"),
|
||||
use_draw_context_alpha("use_draw_context_alpha", true),
|
||||
interactable("interactable", false),
|
||||
scale_image("scale_image"),
|
||||
min_width("min_width", 0),
|
||||
min_height("min_height", 0)
|
||||
|
|
@ -52,6 +54,7 @@ LLIconCtrl::LLIconCtrl(const LLIconCtrl::Params& p)
|
|||
mColor(p.color()),
|
||||
mImagep(p.image),
|
||||
mUseDrawContextAlpha(p.use_draw_context_alpha),
|
||||
mInteractable(p.interactable),
|
||||
mPriority(0),
|
||||
mMinWidth(p.min_width),
|
||||
mMinHeight(p.min_height),
|
||||
|
|
@ -81,6 +84,16 @@ void LLIconCtrl::draw()
|
|||
LLUICtrl::draw();
|
||||
}
|
||||
|
||||
BOOL LLIconCtrl::handleHover(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
if (mInteractable && getEnabled())
|
||||
{
|
||||
getWindow()->setCursor(UI_CURSOR_HAND);
|
||||
return TRUE;
|
||||
}
|
||||
return LLUICtrl::handleHover(x, y, mask);
|
||||
}
|
||||
|
||||
// virtual
|
||||
// value might be a string or a UUID
|
||||
void LLIconCtrl::setValue(const LLSD& value)
|
||||
|
|
|
|||
|
|
@ -48,7 +48,8 @@ public:
|
|||
{
|
||||
Optional<LLUIImage*> image;
|
||||
Optional<LLUIColor> color;
|
||||
Optional<bool> use_draw_context_alpha;
|
||||
Optional<bool> use_draw_context_alpha,
|
||||
interactable;
|
||||
Optional<S32> min_width,
|
||||
min_height;
|
||||
Ignored scale_image;
|
||||
|
|
@ -67,6 +68,9 @@ public:
|
|||
// llview overrides
|
||||
virtual void draw();
|
||||
|
||||
// llview overrides
|
||||
virtual BOOL handleHover(S32 x, S32 y, MASK mask);
|
||||
|
||||
// lluictrl overrides
|
||||
virtual void setValue(const LLSD& value );
|
||||
|
||||
|
|
@ -88,6 +92,7 @@ protected:
|
|||
// If set to true (default), use the draw context transparency.
|
||||
// If false, will use transparency returned by getCurrentTransparency(). See STORM-698.
|
||||
bool mUseDrawContextAlpha;
|
||||
bool mInteractable;
|
||||
|
||||
private:
|
||||
LLUIColor mColor;
|
||||
|
|
|
|||
|
|
@ -395,7 +395,6 @@ void LLLayoutStack::updateLayout()
|
|||
space_to_distribute += panelp ? ll_round((F32)mPanelSpacing * panelp->getVisibleAmount()) : 0;
|
||||
|
||||
S32 remaining_space = space_to_distribute;
|
||||
F32 fraction_distributed = 0.f;
|
||||
if (space_to_distribute > 0 && total_visible_fraction > 0.f)
|
||||
{ // give space proportionally to visible auto resize panels
|
||||
BOOST_FOREACH(LLLayoutPanel* panelp, mPanels)
|
||||
|
|
@ -404,7 +403,6 @@ void LLLayoutStack::updateLayout()
|
|||
{
|
||||
F32 fraction_to_distribute = (panelp->mFractionalSize * panelp->getAutoResizeFactor()) / (total_visible_fraction);
|
||||
S32 delta = ll_round((F32)space_to_distribute * fraction_to_distribute);
|
||||
fraction_distributed += fraction_to_distribute;
|
||||
panelp->mTargetDim += delta;
|
||||
remaining_space -= delta;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ void LLMenuButton::MenuPositions::declareValues()
|
|||
declare("topleft", MP_TOP_LEFT);
|
||||
declare("topright", MP_TOP_RIGHT);
|
||||
declare("bottomleft", MP_BOTTOM_LEFT);
|
||||
declare("bottomright", MP_BOTTOM_RIGHT);
|
||||
}
|
||||
|
||||
LLMenuButton::Params::Params()
|
||||
|
|
@ -212,6 +213,13 @@ void LLMenuButton::updateMenuOrigin()
|
|||
mY = rect.mBottom;
|
||||
break;
|
||||
}
|
||||
case MP_BOTTOM_RIGHT:
|
||||
{
|
||||
const LLRect& menu_rect = menu->getRect();
|
||||
mX = rect.mRight - menu_rect.getWidth();
|
||||
mY = rect.mBottom;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,7 +41,8 @@ public:
|
|||
{
|
||||
MP_TOP_LEFT,
|
||||
MP_TOP_RIGHT,
|
||||
MP_BOTTOM_LEFT
|
||||
MP_BOTTOM_LEFT,
|
||||
MP_BOTTOM_RIGHT
|
||||
} EMenuPosition;
|
||||
|
||||
struct MenuPositions
|
||||
|
|
|
|||
|
|
@ -3960,8 +3960,8 @@ void LLTearOffMenu::draw()
|
|||
{
|
||||
// animate towards target height
|
||||
reshape(getRect().getWidth(), llceil(lerp((F32)getRect().getHeight(), (F32)mTargetHeight, LLSmoothInterpolation::getInterpolant(0.05f))));
|
||||
mMenu->needsArrange();
|
||||
}
|
||||
mMenu->needsArrange();
|
||||
LLFloater::draw();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -100,7 +100,10 @@ void LLModalDialog::onOpen(const LLSD& key)
|
|||
if (!sModalStack.empty())
|
||||
{
|
||||
LLModalDialog* front = sModalStack.front();
|
||||
front->setVisible(FALSE);
|
||||
if (front != this)
|
||||
{
|
||||
front->setVisible(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
// This is a modal dialog. It sucks up all mouse and keyboard operations.
|
||||
|
|
@ -108,7 +111,14 @@ void LLModalDialog::onOpen(const LLSD& key)
|
|||
LLUI::getInstance()->addPopup(this);
|
||||
setFocus(TRUE);
|
||||
|
||||
sModalStack.push_front( this );
|
||||
std::list<LLModalDialog*>::iterator iter = std::find(sModalStack.begin(), sModalStack.end(), this);
|
||||
if (iter != sModalStack.end())
|
||||
{
|
||||
// if already present, we want to move it to front.
|
||||
sModalStack.erase(iter);
|
||||
}
|
||||
|
||||
sModalStack.push_front(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -69,16 +69,22 @@ void LLProgressBar::draw()
|
|||
static LLTimer timer;
|
||||
F32 alpha = getDrawContext().mAlpha;
|
||||
|
||||
LLColor4 image_bar_color = mColorBackground.get();
|
||||
image_bar_color.setAlpha(alpha);
|
||||
mImageBar->draw(getLocalRect(), image_bar_color);
|
||||
if (mImageBar) // optional according to parameters
|
||||
{
|
||||
LLColor4 image_bar_color = mColorBackground.get();
|
||||
image_bar_color.setAlpha(alpha);
|
||||
mImageBar->draw(getLocalRect(), image_bar_color);
|
||||
}
|
||||
|
||||
alpha *= 0.5f + 0.5f*0.5f*(1.f + (F32)sin(3.f*timer.getElapsedTimeF32()));
|
||||
LLColor4 bar_color = mColorBar.get();
|
||||
bar_color.mV[VALPHA] *= alpha; // modulate alpha
|
||||
LLRect progress_rect = getLocalRect();
|
||||
progress_rect.mRight = ll_round(getRect().getWidth() * (mPercentDone / 100.f));
|
||||
mImageFill->draw(progress_rect, bar_color);
|
||||
if (mImageFill)
|
||||
{
|
||||
alpha *= 0.5f + 0.5f*0.5f*(1.f + (F32)sin(3.f*timer.getElapsedTimeF32()));
|
||||
LLColor4 bar_color = mColorBar.get();
|
||||
bar_color.mV[VALPHA] *= alpha; // modulate alpha
|
||||
LLRect progress_rect = getLocalRect();
|
||||
progress_rect.mRight = ll_round(getRect().getWidth() * (mPercentDone / 100.f));
|
||||
mImageFill->draw(progress_rect, bar_color);
|
||||
}
|
||||
}
|
||||
|
||||
void LLProgressBar::setValue(const LLSD& value)
|
||||
|
|
|
|||
|
|
@ -1388,6 +1388,84 @@ BOOL LLScrollListCtrl::selectItemByPrefix(const LLWString& target, BOOL case_sen
|
|||
return found;
|
||||
}
|
||||
|
||||
U32 LLScrollListCtrl::searchItems(const std::string& substring, bool case_sensitive, bool focus)
|
||||
{
|
||||
return searchItems(utf8str_to_wstring(substring), case_sensitive, focus);
|
||||
}
|
||||
|
||||
U32 LLScrollListCtrl::searchItems(const LLWString& substring, bool case_sensitive, bool focus)
|
||||
{
|
||||
U32 found = 0;
|
||||
|
||||
LLWString substring_trimmed(substring);
|
||||
S32 len = substring_trimmed.size();
|
||||
|
||||
if (0 == len)
|
||||
{
|
||||
// at the moment search for empty element is not supported
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
deselectAllItems(TRUE);
|
||||
if (!case_sensitive)
|
||||
{
|
||||
// do comparisons in lower case
|
||||
LLWStringUtil::toLower(substring_trimmed);
|
||||
}
|
||||
|
||||
for (item_list::iterator iter = mItemList.begin(); iter != mItemList.end(); iter++)
|
||||
{
|
||||
LLScrollListItem* item = *iter;
|
||||
// Only select enabled items with matching names
|
||||
if (!item->getEnabled())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
LLScrollListCell* cellp = item->getColumn(getSearchColumn());
|
||||
if (!cellp)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
LLWString item_label = utf8str_to_wstring(cellp->getValue().asString());
|
||||
if (!case_sensitive)
|
||||
{
|
||||
LLWStringUtil::toLower(item_label);
|
||||
}
|
||||
// remove extraneous whitespace from searchable label
|
||||
LLWStringUtil::trim(item_label);
|
||||
|
||||
size_t found_iter = item_label.find(substring_trimmed);
|
||||
|
||||
if (found_iter != std::string::npos)
|
||||
{
|
||||
// find offset of matching text
|
||||
cellp->highlightText(found_iter, substring_trimmed.size());
|
||||
selectItem(item, -1, FALSE);
|
||||
|
||||
found++;
|
||||
|
||||
if (!mAllowMultipleSelection)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (focus && found != 0)
|
||||
{
|
||||
mNeedsScroll = true;
|
||||
}
|
||||
|
||||
if (mCommitOnSelectionChange)
|
||||
{
|
||||
commitIfChanged();
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
const std::string LLScrollListCtrl::getSelectedItemLabel(S32 column) const
|
||||
{
|
||||
LLScrollListItem* item;
|
||||
|
|
@ -1912,6 +1990,7 @@ BOOL LLScrollListCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask)
|
|||
registrar.add("Url.SendIM", boost::bind(&LLScrollListCtrl::sendIM, id));
|
||||
registrar.add("Url.AddFriend", boost::bind(&LLScrollListCtrl::addFriend, id));
|
||||
registrar.add("Url.RemoveFriend", boost::bind(&LLScrollListCtrl::removeFriend, id));
|
||||
registrar.add("Url.ReportAbuse", boost::bind(&LLScrollListCtrl::reportAbuse, id, is_group));
|
||||
registrar.add("Url.Execute", boost::bind(&LLScrollListCtrl::showNameDetails, id, is_group));
|
||||
registrar.add("Url.CopyLabel", boost::bind(&LLScrollListCtrl::copyNameToClipboard, id, is_group));
|
||||
registrar.add("Url.CopyUrl", boost::bind(&LLScrollListCtrl::copySLURLToClipboard, id, is_group));
|
||||
|
|
@ -1975,6 +2054,15 @@ void LLScrollListCtrl::removeFriend(std::string id)
|
|||
LLUrlAction::removeFriend(slurl);
|
||||
}
|
||||
|
||||
void LLScrollListCtrl::reportAbuse(std::string id, bool is_group)
|
||||
{
|
||||
if (!is_group)
|
||||
{
|
||||
std::string slurl = "secondlife:///app/agent/" + id + "/about";
|
||||
LLUrlAction::reportAbuse(slurl);
|
||||
}
|
||||
}
|
||||
|
||||
void LLScrollListCtrl::showNameDetails(std::string id, bool is_group)
|
||||
{
|
||||
// open the resident's details or the group details
|
||||
|
|
|
|||
|
|
@ -267,6 +267,14 @@ public:
|
|||
const std::string getSelectedItemLabel(S32 column = 0) const;
|
||||
LLSD getSelectedValue();
|
||||
|
||||
// If multi select is on, select all element that include substring,
|
||||
// otherwise select first match only.
|
||||
// If focus is true will scroll to selection.
|
||||
// Returns number of results.
|
||||
// Note: at the moment search happens in one go and is expensive
|
||||
U32 searchItems(const std::string& substring, bool case_sensitive = false, bool focus = true);
|
||||
U32 searchItems(const LLWString& substring, bool case_sensitive = false, bool focus = true);
|
||||
|
||||
// DEPRECATED: Use LLSD versions of setCommentText() and getSelectedValue().
|
||||
// "StringUUID" interface: use this when you're creating a list that contains non-unique strings each of which
|
||||
// has an associated, unique UUID, and only one of which can be selected at a time.
|
||||
|
|
@ -325,6 +333,7 @@ public:
|
|||
// support right-click context menus for avatar/group lists
|
||||
enum ContextMenuType { MENU_NONE, MENU_AVATAR, MENU_GROUP };
|
||||
void setContextMenu(const ContextMenuType &menu) { mContextMenuType = menu; }
|
||||
ContextMenuType getContextMenuType() { return mContextMenuType; }
|
||||
|
||||
// Overridden from LLView
|
||||
/*virtual*/ void draw();
|
||||
|
|
@ -460,6 +469,7 @@ private:
|
|||
static void sendIM(std::string id);
|
||||
static void addFriend(std::string id);
|
||||
static void removeFriend(std::string id);
|
||||
static void reportAbuse(std::string id, bool is_group);
|
||||
static void showNameDetails(std::string id, bool is_group);
|
||||
static void copyNameToClipboard(std::string id, bool is_group);
|
||||
static void copySLURLToClipboard(std::string id, bool is_group);
|
||||
|
|
|
|||
|
|
@ -103,6 +103,7 @@ LLSpinCtrl::LLSpinCtrl(const LLSpinCtrl::Params& p)
|
|||
up_button_params.rect = LLRect(btn_left, getRect().getHeight(), btn_right, getRect().getHeight() - spinctrl_btn_height);
|
||||
up_button_params.click_callback.function(boost::bind(&LLSpinCtrl::onUpBtn, this, _2));
|
||||
up_button_params.mouse_held_callback.function(boost::bind(&LLSpinCtrl::onUpBtn, this, _2));
|
||||
up_button_params.commit_on_capture_lost = true;
|
||||
|
||||
mUpBtn = LLUICtrlFactory::create<LLButton>(up_button_params);
|
||||
addChild(mUpBtn);
|
||||
|
|
@ -111,6 +112,7 @@ LLSpinCtrl::LLSpinCtrl(const LLSpinCtrl::Params& p)
|
|||
down_button_params.rect = LLRect(btn_left, getRect().getHeight() - spinctrl_btn_height, btn_right, getRect().getHeight() - 2 * spinctrl_btn_height);
|
||||
down_button_params.click_callback.function(boost::bind(&LLSpinCtrl::onDownBtn, this, _2));
|
||||
down_button_params.mouse_held_callback.function(boost::bind(&LLSpinCtrl::onDownBtn, this, _2));
|
||||
down_button_params.commit_on_capture_lost = true;
|
||||
mDownBtn = LLUICtrlFactory::create<LLButton>(down_button_params);
|
||||
addChild(mDownBtn);
|
||||
|
||||
|
|
|
|||
|
|
@ -402,9 +402,13 @@ void LLTabContainer::draw()
|
|||
S32 cur_scroll_pos = getScrollPos();
|
||||
if (cur_scroll_pos > 0)
|
||||
{
|
||||
S32 available_width_with_arrows = getRect().getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + tabcntr_arrow_btn_size + tabcntr_arrow_btn_size + 1);
|
||||
if (!mIsVertical)
|
||||
if (mIsVertical)
|
||||
{
|
||||
target_pixel_scroll = cur_scroll_pos * (BTN_HEIGHT + tabcntrv_pad);
|
||||
}
|
||||
else
|
||||
{
|
||||
S32 available_width_with_arrows = getRect().getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + tabcntr_arrow_btn_size + tabcntr_arrow_btn_size + 1);
|
||||
for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
|
||||
{
|
||||
if (cur_scroll_pos == 0)
|
||||
|
|
@ -1189,13 +1193,15 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel)
|
|||
sendChildToFront(mNextArrowBtn);
|
||||
sendChildToFront(mJumpPrevArrowBtn);
|
||||
sendChildToFront(mJumpNextArrowBtn);
|
||||
|
||||
|
||||
updateMaxScrollPos();
|
||||
|
||||
if( select )
|
||||
{
|
||||
selectLastTab();
|
||||
mScrollPos = mMaxScrollPos;
|
||||
}
|
||||
|
||||
updateMaxScrollPos();
|
||||
}
|
||||
|
||||
void LLTabContainer::addPlaceholder(LLPanel* child, const std::string& label)
|
||||
|
|
@ -2079,9 +2085,9 @@ void LLTabContainer::updateMaxScrollPos()
|
|||
if( tab_total_height > available_height )
|
||||
{
|
||||
static LLUICachedControl<S32> tabcntrv_arrow_btn_size ("UITabCntrvArrowBtnSize", 0);
|
||||
S32 available_height_with_arrows = getRect().getHeight() - 2*(tabcntrv_arrow_btn_size + 3*tabcntrv_pad);
|
||||
S32 available_height_with_arrows = getRect().getHeight() - 2*(tabcntrv_arrow_btn_size + 3*tabcntrv_pad) - mNextArrowBtn->getRect().mBottom;
|
||||
S32 additional_needed = tab_total_height - available_height_with_arrows;
|
||||
setMaxScrollPos((S32) ceil(additional_needed / float(BTN_HEIGHT) ) );
|
||||
setMaxScrollPos((S32) ceil(additional_needed / float(BTN_HEIGHT + tabcntrv_pad) ) );
|
||||
no_scroll = FALSE;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -163,6 +163,7 @@ LLTextBase::Params::Params()
|
|||
font_shadow("font_shadow"),
|
||||
wrap("wrap"),
|
||||
trusted_content("trusted_content", true),
|
||||
always_show_icons("always_show_icons", false),
|
||||
use_ellipses("use_ellipses", false),
|
||||
parse_urls("parse_urls", false),
|
||||
force_urls_external("force_urls_external", false),
|
||||
|
|
@ -212,6 +213,7 @@ LLTextBase::LLTextBase(const LLTextBase::Params &p)
|
|||
mClip(p.clip),
|
||||
mClipPartial(p.clip_partial && !p.allow_scroll),
|
||||
mTrustedContent(p.trusted_content),
|
||||
mAlwaysShowIcons(p.always_show_icons),
|
||||
mTrackEnd( p.track_end ),
|
||||
mScrollIndex(-1),
|
||||
mSelectionStart( 0 ),
|
||||
|
|
@ -448,8 +450,48 @@ void LLTextBase::drawSelectionBackground()
|
|||
++rect_it)
|
||||
{
|
||||
LLRect selection_rect = *rect_it;
|
||||
selection_rect = *rect_it;
|
||||
selection_rect.translate(mVisibleTextRect.mLeft - content_display_rect.mLeft, mVisibleTextRect.mBottom - content_display_rect.mBottom);
|
||||
if (mScroller)
|
||||
{
|
||||
// If scroller is On content_display_rect has correct rect and safe to use as is
|
||||
// Note: we might need to account for border
|
||||
selection_rect.translate(mVisibleTextRect.mLeft - content_display_rect.mLeft, mVisibleTextRect.mBottom - content_display_rect.mBottom);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If scroller is Off content_display_rect will have rect from document, adjusted to text width, heigh and position
|
||||
// and we have to acount for offset depending on position
|
||||
S32 v_delta = 0;
|
||||
S32 h_delta = 0;
|
||||
switch (mVAlign)
|
||||
{
|
||||
case LLFontGL::TOP:
|
||||
v_delta = mVisibleTextRect.mTop - content_display_rect.mTop - mVPad;
|
||||
break;
|
||||
case LLFontGL::VCENTER:
|
||||
v_delta = (llmax(mVisibleTextRect.getHeight() - content_display_rect.mTop, -content_display_rect.mBottom) + (mVisibleTextRect.mBottom - content_display_rect.mBottom)) / 2;
|
||||
break;
|
||||
case LLFontGL::BOTTOM:
|
||||
v_delta = mVisibleTextRect.mBottom - content_display_rect.mBottom;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch (mHAlign)
|
||||
{
|
||||
case LLFontGL::LEFT:
|
||||
h_delta = mVisibleTextRect.mLeft - content_display_rect.mLeft + mHPad;
|
||||
break;
|
||||
case LLFontGL::HCENTER:
|
||||
h_delta = (llmax(mVisibleTextRect.getWidth() - content_display_rect.mLeft, -content_display_rect.mRight) + (mVisibleTextRect.mRight - content_display_rect.mRight)) / 2;
|
||||
break;
|
||||
case LLFontGL::RIGHT:
|
||||
h_delta = mVisibleTextRect.mRight - content_display_rect.mRight;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
selection_rect.translate(h_delta, v_delta);
|
||||
}
|
||||
gl_rect_2d(selection_rect, selection_color);
|
||||
}
|
||||
}
|
||||
|
|
@ -2007,6 +2049,7 @@ void LLTextBase::createUrlContextMenu(S32 x, S32 y, const std::string &in_url)
|
|||
registrar.add("Url.ShowProfile", boost::bind(&LLUrlAction::showProfile, url));
|
||||
registrar.add("Url.AddFriend", boost::bind(&LLUrlAction::addFriend, url));
|
||||
registrar.add("Url.RemoveFriend", boost::bind(&LLUrlAction::removeFriend, url));
|
||||
registrar.add("Url.ReportAbuse", boost::bind(&LLUrlAction::reportAbuse, url));
|
||||
registrar.add("Url.SendIM", boost::bind(&LLUrlAction::sendIM, url));
|
||||
registrar.add("Url.ShowOnMap", boost::bind(&LLUrlAction::showLocationOnMap, url));
|
||||
registrar.add("Url.CopyLabel", boost::bind(&LLUrlAction::copyLabelToClipboard, url));
|
||||
|
|
@ -2116,7 +2159,7 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para
|
|||
LLUrlMatch match;
|
||||
std::string text = new_text;
|
||||
while ( LLUrlRegistry::instance().findUrl(text, match,
|
||||
boost::bind(&LLTextBase::replaceUrl, this, _1, _2, _3),isContentTrusted()))
|
||||
boost::bind(&LLTextBase::replaceUrl, this, _1, _2, _3),isContentTrusted() || mAlwaysShowIcons))
|
||||
{
|
||||
start = match.getStart();
|
||||
end = match.getEnd()+1;
|
||||
|
|
@ -2141,7 +2184,7 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para
|
|||
}
|
||||
|
||||
// add icon before url if need
|
||||
LLTextUtil::processUrlMatch(&match, this, isContentTrusted() || match.isTrusted());
|
||||
LLTextUtil::processUrlMatch(&match, this, isContentTrusted() || match.isTrusted() || mAlwaysShowIcons);
|
||||
if ((isContentTrusted() || match.isTrusted()) && !match.getIcon().empty() )
|
||||
{
|
||||
setLastSegmentToolTip(LLTrans::getString("TooltipSLIcon"));
|
||||
|
|
|
|||
|
|
@ -321,7 +321,8 @@ public:
|
|||
parse_highlights,
|
||||
clip,
|
||||
clip_partial,
|
||||
trusted_content;
|
||||
trusted_content,
|
||||
always_show_icons;
|
||||
|
||||
Optional<S32> v_pad,
|
||||
h_pad;
|
||||
|
|
@ -369,6 +370,8 @@ public:
|
|||
virtual void onFocusReceived();
|
||||
virtual void onFocusLost();
|
||||
|
||||
void setParseHTML(bool parse_html) { mParseHTML = parse_html; }
|
||||
|
||||
// LLSpellCheckMenuHandler overrides
|
||||
/*virtual*/ bool getSpellCheck() const;
|
||||
|
||||
|
|
@ -702,6 +705,8 @@ protected:
|
|||
bool mAutoIndent;
|
||||
S32 mMaxTextByteLength; // Maximum length mText is allowed to be in bytes
|
||||
bool mSkipTripleClick;
|
||||
bool mAlwaysShowIcons;
|
||||
|
||||
bool mSkipLinkUnderline;
|
||||
|
||||
// support widgets
|
||||
|
|
|
|||
|
|
@ -196,6 +196,7 @@ public:
|
|||
const LLUUID& getSourceID() const { return mSourceID; }
|
||||
|
||||
const LLTextSegmentPtr getPreviousSegment() const;
|
||||
const LLTextSegmentPtr getLastSegment() const;
|
||||
void getSelectedSegments(segment_vec_t& segments) const;
|
||||
|
||||
void setShowContextMenu(bool show) { mShowContextMenu = show; }
|
||||
|
|
|
|||
|
|
@ -76,22 +76,6 @@ void LLTextUtil::textboxSetGreyedVal(LLTextBox *txtbox, const LLStyle::Params& n
|
|||
txtbox->appendText(text.substr(greyed_begin + greyed_len), false, normal_style);
|
||||
}
|
||||
|
||||
const std::string& LLTextUtil::formatPhoneNumber(const std::string& phone_str)
|
||||
{
|
||||
static const std::string PHONE_SEPARATOR = LLUI::getInstance()->mSettingGroups["config"]->getString("AvalinePhoneSeparator");
|
||||
static const S32 PHONE_PART_LEN = 2;
|
||||
|
||||
static std::string formatted_phone_str;
|
||||
formatted_phone_str = phone_str;
|
||||
S32 separator_pos = (S32)(formatted_phone_str.size()) - PHONE_PART_LEN;
|
||||
for (; separator_pos >= PHONE_PART_LEN; separator_pos -= PHONE_PART_LEN)
|
||||
{
|
||||
formatted_phone_str.insert(separator_pos, PHONE_SEPARATOR);
|
||||
}
|
||||
|
||||
return formatted_phone_str;
|
||||
}
|
||||
|
||||
bool LLTextUtil::processUrlMatch(LLUrlMatch* match,LLTextBase* text_base, bool is_content_trusted)
|
||||
{
|
||||
if (match == 0 || text_base == 0)
|
||||
|
|
|
|||
|
|
@ -58,18 +58,6 @@ namespace LLTextUtil
|
|||
const std::string& text,
|
||||
const std::string& greyed);
|
||||
|
||||
/**
|
||||
* Formats passed phone number to be more human readable.
|
||||
*
|
||||
* It just divides the number on parts by two digits from right to left. The first left part
|
||||
* can have 2 or 3 digits, i.e. +44-33-33-44-55-66 or 12-34-56-78-90. Separator is set in
|
||||
* application settings (AvalinePhoneSeparator)
|
||||
*
|
||||
* @param[in] phone_str string with original phone number
|
||||
* @return reference to string with formatted phone number
|
||||
*/
|
||||
const std::string& formatPhoneNumber(const std::string& phone_str);
|
||||
|
||||
/**
|
||||
* Adds icon before url if need.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -222,6 +222,15 @@ void LLUrlAction::removeFriend(std::string url)
|
|||
}
|
||||
}
|
||||
|
||||
void LLUrlAction::reportAbuse(std::string url)
|
||||
{
|
||||
std::string id_str = getUserID(url);
|
||||
if (LLUUID::validate(id_str))
|
||||
{
|
||||
executeSLURL("secondlife:///app/agent/" + id_str + "/reportAbuse");
|
||||
}
|
||||
}
|
||||
|
||||
void LLUrlAction::blockObject(std::string url)
|
||||
{
|
||||
std::string object_id = getObjectId(url);
|
||||
|
|
|
|||
|
|
@ -82,6 +82,7 @@ public:
|
|||
static void sendIM(std::string url);
|
||||
static void addFriend(std::string url);
|
||||
static void removeFriend(std::string url);
|
||||
static void reportAbuse(std::string url);
|
||||
static void blockObject(std::string url);
|
||||
static void unblockObject(std::string url);
|
||||
|
||||
|
|
|
|||
|
|
@ -197,4 +197,10 @@ if (SDL_FOUND)
|
|||
endif (SDL_FOUND)
|
||||
|
||||
target_link_libraries (llwindow ${llwindow_LINK_LIBRARIES})
|
||||
|
||||
if (DARWIN)
|
||||
include(CMakeFindFrameworks)
|
||||
find_library(CARBON_LIBRARY Carbon)
|
||||
target_link_libraries(llwindow ${CARBON_LIBRARY})
|
||||
endif (DARWIN)
|
||||
|
||||
|
|
|
|||
|
|
@ -148,6 +148,22 @@ void LLKeyboard::addKeyName(KEY key, const std::string& name)
|
|||
sNamesToKeys[nameuc] = key;
|
||||
}
|
||||
|
||||
void LLKeyboard::resetKeyDownAndHandle()
|
||||
{
|
||||
MASK mask = currentMask(FALSE);
|
||||
for (S32 i = 0; i < KEY_COUNT; i++)
|
||||
{
|
||||
if (mKeyLevel[i])
|
||||
{
|
||||
mKeyDown[i] = FALSE;
|
||||
mKeyLevel[i] = FALSE;
|
||||
mKeyUp[i] = TRUE;
|
||||
mCurTranslatedKey = (KEY)i;
|
||||
mCallbacks->handleTranslatedKeyUp(i, mask);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// BUG this has to be called when an OS dialog is shown, otherwise modifier key state
|
||||
// is wrong because the keyup event is never received by the main window. JC
|
||||
void LLKeyboard::resetKeys()
|
||||
|
|
|
|||
|
|
@ -58,7 +58,8 @@ public:
|
|||
LLKeyboard();
|
||||
virtual ~LLKeyboard();
|
||||
|
||||
void resetKeys();
|
||||
void resetKeyDownAndHandle();
|
||||
void resetKeys();
|
||||
|
||||
|
||||
F32 getCurKeyElapsedTime() { return getKeyDown(mCurScanKey) ? getKeyElapsedTime( mCurScanKey ) : 0.f; }
|
||||
|
|
|
|||
|
|
@ -495,14 +495,14 @@ attributedStringInfo getSegments(NSAttributedString *str)
|
|||
// e.g. OS Window for upload something or Input Window...
|
||||
// mModifiers instance variable is for insertText: or insertText:replacementRange: (by Pell Smit)
|
||||
mModifiers = [theEvent modifierFlags];
|
||||
unichar ch = [[theEvent charactersIgnoringModifiers] characterAtIndex:0];
|
||||
bool acceptsText = mHasMarkedText ? false : callKeyDown(&eventData, keycode, mModifiers, ch);
|
||||
|
||||
bool acceptsText = mHasMarkedText ? false : callKeyDown(&eventData, keycode, mModifiers, [[theEvent characters] characterAtIndex:0]);
|
||||
unichar ch;
|
||||
if (acceptsText &&
|
||||
!mMarkedTextAllowed &&
|
||||
!(mModifiers & (NSControlKeyMask | NSCommandKeyMask)) && // commands don't invoke InputWindow
|
||||
![(LLAppDelegate*)[NSApp delegate] romanScript] &&
|
||||
(ch = [[theEvent charactersIgnoringModifiers] characterAtIndex:0]) > ' ' &&
|
||||
ch > ' ' &&
|
||||
ch != NSDeleteCharacter &&
|
||||
(ch < 0xF700 || ch > 0xF8FF)) // 0xF700-0xF8FF: reserved for function keys on the keyboard(from NSEvent.h)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -100,13 +100,13 @@ const unsigned short *copyFromPBoard()
|
|||
CursorRef createImageCursor(const char *fullpath, int hotspotX, int hotspotY)
|
||||
{
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
|
||||
// extra retain on the NSCursor since we want it to live for the lifetime of the app.
|
||||
NSCursor *cursor =
|
||||
[[[NSCursor alloc]
|
||||
initWithImage:
|
||||
[[[NSImage alloc] initWithContentsOfFile:
|
||||
[NSString stringWithFormat:@"%s", fullpath]
|
||||
[NSString stringWithUTF8String:fullpath]
|
||||
]autorelease]
|
||||
hotSpot:NSMakePoint(hotspotX, hotspotY)
|
||||
]retain];
|
||||
|
|
|
|||
|
|
@ -621,8 +621,6 @@ void LLWindowMacOSX::getMouseDeltas(float* delta)
|
|||
|
||||
BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, BOOL enable_vsync)
|
||||
{
|
||||
BOOL glNeedsInit = FALSE;
|
||||
|
||||
mFullscreen = fullscreen;
|
||||
|
||||
if (mWindow == NULL)
|
||||
|
|
@ -637,9 +635,6 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits
|
|||
mGLView = createOpenGLView(mWindow, mFSAASamples, enable_vsync);
|
||||
mContext = getCGLContextObj(mGLView);
|
||||
|
||||
// Since we just created the context, it needs to be set up.
|
||||
glNeedsInit = TRUE;
|
||||
|
||||
gGLManager.mVRAM = getVramSize(mGLView);
|
||||
}
|
||||
|
||||
|
|
@ -1666,7 +1661,7 @@ void LLWindowMacOSX::hideCursor()
|
|||
|
||||
void LLWindowMacOSX::showCursor()
|
||||
{
|
||||
if(mCursorHidden)
|
||||
if(mCursorHidden || !isCGCursorVisible())
|
||||
{
|
||||
// LL_INFOS() << "showCursor: showing" << LL_ENDL;
|
||||
mCursorHidden = FALSE;
|
||||
|
|
@ -1721,9 +1716,7 @@ void LLSplashScreenMacOSX::updateImpl(const std::string& mesg)
|
|||
{
|
||||
if(mWindow != NULL)
|
||||
{
|
||||
CFStringRef string = NULL;
|
||||
|
||||
string = CFStringCreateWithCString(NULL, mesg.c_str(), kCFStringEncodingUTF8);
|
||||
CFStringCreateWithCString(NULL, mesg.c_str(), kCFStringEncodingUTF8);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -874,21 +874,20 @@ void LLWindowWin32::close()
|
|||
// Restore gamma to the system values.
|
||||
restoreGamma();
|
||||
|
||||
if (mhDC)
|
||||
{
|
||||
if (!ReleaseDC(mWindowHandle, mhDC))
|
||||
{
|
||||
LL_WARNS("Window") << "Release of ghDC failed" << LL_ENDL;
|
||||
}
|
||||
mhDC = NULL;
|
||||
}
|
||||
|
||||
LL_DEBUGS("Window") << "Destroying Window" << LL_ENDL;
|
||||
|
||||
mWindowThread->post([=]()
|
||||
{
|
||||
if (IsWindow(mWindowHandle))
|
||||
{
|
||||
if (mhDC)
|
||||
{
|
||||
if (!ReleaseDC(mWindowHandle, mhDC))
|
||||
{
|
||||
LL_WARNS("Window") << "Release of ghDC failed!" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure we don't leave a blank toolbar button.
|
||||
ShowWindow(mWindowHandle, SW_HIDE);
|
||||
|
||||
|
|
@ -914,6 +913,7 @@ void LLWindowWin32::close()
|
|||
// Even though the above lambda might not yet have run, we've already
|
||||
// bound mWindowHandle into it by value, which should suffice for the
|
||||
// operations we're asking. That's the last time WE should touch it.
|
||||
mhDC = NULL;
|
||||
mWindowHandle = NULL;
|
||||
mWindowThread->close();
|
||||
}
|
||||
|
|
@ -1506,12 +1506,10 @@ const S32 max_format = (S32)num_formats - 1;
|
|||
{
|
||||
wglDeleteContext (mhRC); // Release The Rendering Context
|
||||
mhRC = 0; // Zero The Rendering Context
|
||||
|
||||
}
|
||||
ReleaseDC (mWindowHandle, mhDC); // Release The Device Context
|
||||
mhDC = 0; // Zero The Device Context
|
||||
}
|
||||
|
||||
// will release and recreate mhDC, mWindowHandle
|
||||
recreateWindow(window_rect, dw_ex_style, dw_style);
|
||||
|
||||
RECT rect;
|
||||
|
|
@ -1661,7 +1659,8 @@ const S32 max_format = (S32)num_formats - 1;
|
|||
|
||||
void LLWindowWin32::recreateWindow(RECT window_rect, DWORD dw_ex_style, DWORD dw_style)
|
||||
{
|
||||
auto oldHandle = mWindowHandle;
|
||||
auto oldWindowHandle = mWindowHandle;
|
||||
auto oldDCHandle = mhDC;
|
||||
|
||||
// zero out mWindowHandle and mhDC before destroying window so window
|
||||
// thread falls back to peekmessage
|
||||
|
|
@ -1673,7 +1672,8 @@ void LLWindowWin32::recreateWindow(RECT window_rect, DWORD dw_ex_style, DWORD dw
|
|||
auto window_work =
|
||||
[this,
|
||||
self=mWindowThread,
|
||||
oldHandle,
|
||||
oldWindowHandle,
|
||||
oldDCHandle,
|
||||
// bind CreateWindowEx() parameters by value instead of
|
||||
// back-referencing LLWindowWin32 members
|
||||
windowClassName=mWindowClassName,
|
||||
|
|
@ -1689,11 +1689,20 @@ void LLWindowWin32::recreateWindow(RECT window_rect, DWORD dw_ex_style, DWORD dw
|
|||
self->mWindowHandle = 0;
|
||||
self->mhDC = 0;
|
||||
|
||||
// important to call DestroyWindow() from the window thread
|
||||
if (oldHandle && !destroy_window_handler(oldHandle))
|
||||
if (oldWindowHandle)
|
||||
{
|
||||
LL_WARNS("Window") << "Failed to properly close window before recreating it!"
|
||||
<< LL_ENDL;
|
||||
if (oldDCHandle && !ReleaseDC(oldWindowHandle, oldDCHandle))
|
||||
{
|
||||
LL_WARNS("Window") << "Failed to ReleaseDC" << LL_ENDL;
|
||||
}
|
||||
|
||||
// important to call DestroyWindow() from the window thread
|
||||
if (!destroy_window_handler(oldWindowHandle))
|
||||
{
|
||||
|
||||
LL_WARNS("Window") << "Failed to properly close window before recreating it!"
|
||||
<< LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
auto handle = CreateWindowEx(dw_ex_style,
|
||||
|
|
@ -1731,7 +1740,7 @@ void LLWindowWin32::recreateWindow(RECT window_rect, DWORD dw_ex_style, DWORD dw
|
|||
};
|
||||
// But how we pass window_work to the window thread depends on whether we
|
||||
// already have a window handle.
|
||||
if (! oldHandle)
|
||||
if (!oldWindowHandle)
|
||||
{
|
||||
// Pass window_work using the WorkQueue: without an existing window
|
||||
// handle, the window thread can't call GetMessage().
|
||||
|
|
@ -1744,7 +1753,7 @@ void LLWindowWin32::recreateWindow(RECT window_rect, DWORD dw_ex_style, DWORD dw
|
|||
// PostMessage(oldHandle) because oldHandle won't be destroyed until
|
||||
// the window thread has retrieved and executed window_work.
|
||||
LL_DEBUGS("Window") << "posting window_work to message queue" << LL_ENDL;
|
||||
mWindowThread->Post(oldHandle, window_work);
|
||||
mWindowThread->Post(oldWindowHandle, window_work);
|
||||
}
|
||||
|
||||
auto future = promise.get_future();
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
#include "llplugininstance.h"
|
||||
#include "llpluginmessage.h"
|
||||
#include "llpluginmessageclasses.h"
|
||||
#include "llstring.h"
|
||||
#include "volume_catcher.h"
|
||||
#include "media_plugin_base.h"
|
||||
|
||||
|
|
@ -55,7 +56,7 @@ private:
|
|||
bool init();
|
||||
|
||||
void onPageChangedCallback(const unsigned char* pixels, int x, int y, const int width, const int height);
|
||||
void onCustomSchemeURLCallback(std::string url);
|
||||
void onCustomSchemeURLCallback(std::string url, bool user_gesture, bool is_redirect);
|
||||
void onConsoleMessageCallback(std::string message, std::string source, int line);
|
||||
void onStatusMessageCallback(std::string value);
|
||||
void onTitleChangeCallback(std::string title);
|
||||
|
|
@ -299,11 +300,18 @@ void MediaPluginCEF::onOpenPopupCallback(std::string url, std::string target)
|
|||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
void MediaPluginCEF::onCustomSchemeURLCallback(std::string url)
|
||||
void MediaPluginCEF::onCustomSchemeURLCallback(std::string url, bool user_gesture, bool is_redirect)
|
||||
{
|
||||
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_nofollow");
|
||||
message.setValue("uri", url);
|
||||
message.setValue("nav_type", "clicked"); // TODO: differentiate between click and navigate to
|
||||
message.setValue("uri", url);
|
||||
|
||||
// indicate if this interaction was from a user click (okay on a SLAPP) or
|
||||
// via a navigation (e.g. a data URL - see SL-18151) (not okay on a SLAPP)
|
||||
const std::string nav_type = user_gesture ? "clicked" : "navigated";
|
||||
|
||||
message.setValue("nav_type", nav_type);
|
||||
message.setValueBoolean("is_redirect", is_redirect);
|
||||
|
||||
sendMessage(message);
|
||||
}
|
||||
|
||||
|
|
@ -592,7 +600,7 @@ void MediaPluginCEF::receiveMessage(const char* message_string)
|
|||
{
|
||||
// event callbacks from Dullahan
|
||||
mCEFLib->setOnPageChangedCallback(std::bind(&MediaPluginCEF::onPageChangedCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5));
|
||||
mCEFLib->setOnCustomSchemeURLCallback(std::bind(&MediaPluginCEF::onCustomSchemeURLCallback, this, std::placeholders::_1));
|
||||
mCEFLib->setOnCustomSchemeURLCallback(std::bind(&MediaPluginCEF::onCustomSchemeURLCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||
mCEFLib->setOnConsoleMessageCallback(std::bind(&MediaPluginCEF::onConsoleMessageCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||
mCEFLib->setOnStatusMessageCallback(std::bind(&MediaPluginCEF::onStatusMessageCallback, this, std::placeholders::_1));
|
||||
mCEFLib->setOnTitleChangeCallback(std::bind(&MediaPluginCEF::onTitleChangeCallback, this, std::placeholders::_1));
|
||||
|
|
@ -616,9 +624,9 @@ void MediaPluginCEF::receiveMessage(const char* message_string)
|
|||
// dir as the executable that loaded it (SLPlugin.exe). The code in
|
||||
// Dullahan that tried to figure out the location automatically uses
|
||||
// the location of the exe which isn't helpful so we tell it explicitly.
|
||||
char cur_dir_str[MAX_PATH];
|
||||
GetCurrentDirectoryA(MAX_PATH, cur_dir_str);
|
||||
settings.host_process_path = std::string(cur_dir_str);
|
||||
std::vector<wchar_t> buffer(MAX_PATH + 1);
|
||||
GetCurrentDirectoryW(MAX_PATH, &buffer[0]);
|
||||
settings.host_process_path = ll_convert_wide_to_string(&buffer[0]);
|
||||
#endif
|
||||
settings.accept_language_list = mHostLanguage;
|
||||
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ private:
|
|||
static void display(void* data, void* id);
|
||||
|
||||
/*virtual*/ void setDirty(int left, int top, int right, int bottom) /* override, but that is not supported in gcc 4.6 */;
|
||||
void setDurationDirty();
|
||||
|
||||
static void eventCallbacks(const libvlc_event_t* event, void* ptr);
|
||||
|
||||
|
|
@ -93,8 +94,8 @@ private:
|
|||
|
||||
bool mIsLooping;
|
||||
|
||||
float mCurTime;
|
||||
float mDuration;
|
||||
F64 mCurTime;
|
||||
F64 mDuration;
|
||||
EStatus mVlcStatus;
|
||||
};
|
||||
|
||||
|
|
@ -213,6 +214,19 @@ void MediaPluginLibVLC::setDirty(int left, int top, int right, int bottom)
|
|||
sendMessage(message);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// *virtual*
|
||||
void MediaPluginLibVLC::setDurationDirty()
|
||||
{
|
||||
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "updated");
|
||||
|
||||
message.setValueReal("current_time", mCurTime);
|
||||
message.setValueReal("duration", mDuration);
|
||||
message.setValueReal("current_rate", 1.0f);
|
||||
|
||||
sendMessage(message);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
void MediaPluginLibVLC::eventCallbacks(const libvlc_event_t* event, void* ptr)
|
||||
|
|
@ -233,6 +247,7 @@ void MediaPluginLibVLC::eventCallbacks(const libvlc_event_t* event, void* ptr)
|
|||
parent->mDuration = (float)(libvlc_media_get_duration(parent->mLibVLCMedia)) / 1000.0f;
|
||||
parent->mVlcStatus = STATUS_PLAYING;
|
||||
parent->setVolumeVLC();
|
||||
parent->setDurationDirty();
|
||||
break;
|
||||
|
||||
case libvlc_MediaPlayerPaused:
|
||||
|
|
@ -245,6 +260,8 @@ void MediaPluginLibVLC::eventCallbacks(const libvlc_event_t* event, void* ptr)
|
|||
|
||||
case libvlc_MediaPlayerEndReached:
|
||||
parent->mVlcStatus = STATUS_DONE;
|
||||
parent->mCurTime = parent->mDuration;
|
||||
parent->setDurationDirty();
|
||||
break;
|
||||
|
||||
case libvlc_MediaPlayerEncounteredError:
|
||||
|
|
@ -253,6 +270,11 @@ void MediaPluginLibVLC::eventCallbacks(const libvlc_event_t* event, void* ptr)
|
|||
|
||||
case libvlc_MediaPlayerTimeChanged:
|
||||
parent->mCurTime = (float)libvlc_media_player_get_time(parent->mLibVLCMediaPlayer) / 1000.0f;
|
||||
if (parent->mVlcStatus == STATUS_DONE && libvlc_media_player_is_playing(parent->mLibVLCMediaPlayer))
|
||||
{
|
||||
parent->mVlcStatus = STATUS_PLAYING;
|
||||
}
|
||||
parent->setDurationDirty();
|
||||
break;
|
||||
|
||||
case libvlc_MediaPlayerPositionChanged:
|
||||
|
|
@ -260,6 +282,7 @@ void MediaPluginLibVLC::eventCallbacks(const libvlc_event_t* event, void* ptr)
|
|||
|
||||
case libvlc_MediaPlayerLengthChanged:
|
||||
parent->mDuration = (float)libvlc_media_get_duration(parent->mLibVLCMedia) / 1000.0f;
|
||||
parent->setDurationDirty();
|
||||
break;
|
||||
|
||||
case libvlc_MediaPlayerTitleChanged:
|
||||
|
|
@ -562,7 +585,24 @@ void MediaPluginLibVLC::receiveMessage(const char* message_string)
|
|||
mTextureWidth = texture_width;
|
||||
mTextureHeight = texture_height;
|
||||
|
||||
libvlc_time_t time = 1000.0 * mCurTime;
|
||||
|
||||
playMedia();
|
||||
|
||||
if (mLibVLCMediaPlayer)
|
||||
{
|
||||
libvlc_media_player_set_time(mLibVLCMediaPlayer, time);
|
||||
time = libvlc_media_player_get_time(mLibVLCMediaPlayer);
|
||||
if (time < 0)
|
||||
{
|
||||
// -1 if there is no media
|
||||
mCurTime = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
mCurTime = (F64)time / 1000.0;
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -594,6 +634,13 @@ void MediaPluginLibVLC::receiveMessage(const char* message_string)
|
|||
{
|
||||
if (mLibVLCMediaPlayer)
|
||||
{
|
||||
if (mVlcStatus == STATUS_DONE && !libvlc_media_player_is_playing(mLibVLCMediaPlayer))
|
||||
{
|
||||
// stop or vlc will ignore 'play', it will just
|
||||
// make an MediaPlayerEndReached event even if
|
||||
// seek was used
|
||||
libvlc_media_player_stop(mLibVLCMediaPlayer);
|
||||
}
|
||||
libvlc_media_player_play(mLibVLCMediaPlayer);
|
||||
}
|
||||
}
|
||||
|
|
@ -606,15 +653,32 @@ void MediaPluginLibVLC::receiveMessage(const char* message_string)
|
|||
}
|
||||
else if (message_name == "seek")
|
||||
{
|
||||
if (mDuration > 0)
|
||||
{
|
||||
F64 normalized_offset = message_in.getValueReal("time") / mDuration;
|
||||
libvlc_media_player_set_position(mLibVLCMediaPlayer, normalized_offset);
|
||||
}
|
||||
if (mLibVLCMediaPlayer)
|
||||
{
|
||||
libvlc_time_t time = 1000.0 * message_in.getValueReal("time");
|
||||
libvlc_media_player_set_time(mLibVLCMediaPlayer, time);
|
||||
time = libvlc_media_player_get_time(mLibVLCMediaPlayer);
|
||||
if (time < 0)
|
||||
{
|
||||
// -1 if there is no media
|
||||
mCurTime = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
mCurTime = (F64)time / 1000.0;
|
||||
}
|
||||
|
||||
if (!libvlc_media_player_is_playing(mLibVLCMediaPlayer))
|
||||
{
|
||||
// if paused, won't trigger update, update now
|
||||
setDurationDirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (message_name == "set_loop")
|
||||
{
|
||||
mIsLooping = true;
|
||||
bool loop = message_in.getValueBoolean("loop");
|
||||
mIsLooping = loop;
|
||||
}
|
||||
else if (message_name == "set_volume")
|
||||
{
|
||||
|
|
|
|||
|
|
@ -234,12 +234,14 @@ set(viewer_SOURCE_FILES
|
|||
llfloatercamera.cpp
|
||||
llfloatercamerapresets.cpp
|
||||
llfloaterchatvoicevolume.cpp
|
||||
llfloaterclassified.cpp
|
||||
llfloatercolorpicker.cpp
|
||||
llfloaterconversationlog.cpp
|
||||
llfloaterconversationpreview.cpp
|
||||
llfloatercreatelandmark.cpp
|
||||
llfloaterdeleteprefpreset.cpp
|
||||
llfloaterdestinations.cpp
|
||||
llfloaterdisplayname.cpp
|
||||
llfloatereditenvironmentbase.cpp
|
||||
llfloatereditextdaycycle.cpp
|
||||
llfloaterenvironmentadjust.cpp
|
||||
|
|
@ -295,9 +297,11 @@ set(viewer_SOURCE_FILES
|
|||
llfloaterpay.cpp
|
||||
llfloaterperms.cpp
|
||||
llfloaterpostprocess.cpp
|
||||
llfloaterprofile.cpp
|
||||
llfloaterpreference.cpp
|
||||
llfloaterpreferenceviewadvanced.cpp
|
||||
llfloaterpreviewtrash.cpp
|
||||
llfloaterprofiletexture.cpp
|
||||
llfloaterproperties.cpp
|
||||
llfloaterregiondebugconsole.cpp
|
||||
llfloaterregioninfo.cpp
|
||||
|
|
@ -330,7 +334,6 @@ set(viewer_SOURCE_FILES
|
|||
llfloatervoiceeffect.cpp
|
||||
llfloatervoicevolume.cpp
|
||||
llfloaterwebcontent.cpp
|
||||
llfloaterwebprofile.cpp
|
||||
llfloaterwhitelistentry.cpp
|
||||
llfloaterwindowsize.cpp
|
||||
llfloaterworldmap.cpp
|
||||
|
|
@ -476,7 +479,6 @@ set(viewer_SOURCE_FILES
|
|||
llpanelmediasettingsgeneral.cpp
|
||||
llpanelmediasettingspermissions.cpp
|
||||
llpanelmediasettingssecurity.cpp
|
||||
llpanelme.cpp
|
||||
llpanelnearbymedia.cpp
|
||||
llpanelobject.cpp
|
||||
llpanelobjectinventory.cpp
|
||||
|
|
@ -486,8 +488,6 @@ set(viewer_SOURCE_FILES
|
|||
llpanelpeople.cpp
|
||||
llpanelpeoplemenus.cpp
|
||||
llpanelpermissions.cpp
|
||||
llpanelpick.cpp
|
||||
llpanelpicks.cpp
|
||||
llpanelplaceinfo.cpp
|
||||
llpanelplaceprofile.cpp
|
||||
llpanelplaces.cpp
|
||||
|
|
@ -496,6 +496,8 @@ set(viewer_SOURCE_FILES
|
|||
llpanelpresetspulldown.cpp
|
||||
llpanelprimmediacontrols.cpp
|
||||
llpanelprofile.cpp
|
||||
llpanelprofileclassifieds.cpp
|
||||
llpanelprofilepicks.cpp
|
||||
llpanelsnapshot.cpp
|
||||
llpanelsnapshotinventory.cpp
|
||||
llpanelsnapshotlocal.cpp
|
||||
|
|
@ -657,6 +659,7 @@ set(viewer_SOURCE_FILES
|
|||
llviewercontrol.cpp
|
||||
llviewercontrollistener.cpp
|
||||
llviewerdisplay.cpp
|
||||
llviewerdisplayname.cpp
|
||||
llviewerfloaterreg.cpp
|
||||
llviewerfoldertype.cpp
|
||||
llviewergenericmessage.cpp
|
||||
|
|
@ -870,12 +873,14 @@ set(viewer_HEADER_FILES
|
|||
llfloatercamerapresets.h
|
||||
llfloatercamera.h
|
||||
llfloaterchatvoicevolume.h
|
||||
llfloaterclassified.h
|
||||
llfloatercolorpicker.h
|
||||
llfloaterconversationlog.h
|
||||
llfloaterconversationpreview.h
|
||||
llfloatercreatelandmark.h
|
||||
llfloaterdeleteprefpreset.h
|
||||
llfloaterdestinations.h
|
||||
llfloaterdisplayname.h
|
||||
llfloatereditenvironmentbase.h
|
||||
llfloatereditextdaycycle.h
|
||||
llfloaterenvironmentadjust.h
|
||||
|
|
@ -934,9 +939,11 @@ set(viewer_HEADER_FILES
|
|||
llfloaterpay.h
|
||||
llfloaterperms.h
|
||||
llfloaterpostprocess.h
|
||||
llfloaterprofile.h
|
||||
llfloaterpreference.h
|
||||
llfloaterpreferenceviewadvanced.h
|
||||
llfloaterpreviewtrash.h
|
||||
llfloaterprofiletexture.h
|
||||
llfloaterproperties.h
|
||||
llfloaterregiondebugconsole.h
|
||||
llfloaterregioninfo.h
|
||||
|
|
@ -969,7 +976,6 @@ set(viewer_HEADER_FILES
|
|||
llfloatervoiceeffect.h
|
||||
llfloatervoicevolume.h
|
||||
llfloaterwebcontent.h
|
||||
llfloaterwebprofile.h
|
||||
llfloaterwhitelistentry.h
|
||||
llfloaterwindowsize.h
|
||||
llfloaterworldmap.h
|
||||
|
|
@ -1105,7 +1111,6 @@ set(viewer_HEADER_FILES
|
|||
llpanelmediasettingsgeneral.h
|
||||
llpanelmediasettingspermissions.h
|
||||
llpanelmediasettingssecurity.h
|
||||
llpanelme.h
|
||||
llpanelnearbymedia.h
|
||||
llpanelobject.h
|
||||
llpanelobjectinventory.h
|
||||
|
|
@ -1115,8 +1120,6 @@ set(viewer_HEADER_FILES
|
|||
llpanelpeople.h
|
||||
llpanelpeoplemenus.h
|
||||
llpanelpermissions.h
|
||||
llpanelpick.h
|
||||
llpanelpicks.h
|
||||
llpanelplaceinfo.h
|
||||
llpanelplaceprofile.h
|
||||
llpanelplaces.h
|
||||
|
|
@ -1125,6 +1128,8 @@ set(viewer_HEADER_FILES
|
|||
llpanelpresetspulldown.h
|
||||
llpanelprimmediacontrols.h
|
||||
llpanelprofile.h
|
||||
llpanelprofileclassifieds.h
|
||||
llpanelprofilepicks.h
|
||||
llpanelsnapshot.h
|
||||
llpanelteleporthistory.h
|
||||
llpaneltiptoast.h
|
||||
|
|
@ -1287,6 +1292,7 @@ set(viewer_HEADER_FILES
|
|||
llviewercontrol.h
|
||||
llviewercontrollistener.h
|
||||
llviewerdisplay.h
|
||||
llviewerdisplayname.h
|
||||
llviewerfloaterreg.h
|
||||
llviewerfoldertype.h
|
||||
llviewergenericmessage.h
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
6.6.2
|
||||
6.6.8
|
||||
|
|
|
|||
|
|
@ -167,10 +167,8 @@
|
|||
icon="Command_Picks_Icon"
|
||||
label_ref="Command_Picks_Label"
|
||||
tooltip_ref="Command_Picks_Tooltip"
|
||||
execute_function="Floater.ToggleOrBringToFront"
|
||||
execute_parameters="picks"
|
||||
is_running_function="Floater.IsOpen"
|
||||
is_running_parameters="picks"
|
||||
execute_function="Avatar.TogglePicks"
|
||||
is_running_function="Avatar.IsPicksTabOpen"
|
||||
/>
|
||||
<command name="places"
|
||||
available_in_toybox="true"
|
||||
|
|
|
|||
|
|
@ -85,7 +85,6 @@
|
|||
<binding key="DOWN" mask="CTL_ALT_SHIFT" command="pan_down"/>
|
||||
|
||||
<binding key="" mask="NONE" mouse="MMB" command="toggle_voice"/>
|
||||
<binding key="" mask="NONE" mouse="LMB" command="walk_to"/>
|
||||
|
||||
<binding key="" mask="NONE" mouse="LMB" command="script_trigger_lbutton"/>
|
||||
</third_person>
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue