Merge branch 'DRTVWR-559' into DRTVWR-592
commit
a91f08ba84
|
|
@ -15,9 +15,6 @@ jobs:
|
|||
configuration: [ReleaseOS]
|
||||
addrsize: [64]
|
||||
include:
|
||||
- runner: windows-large
|
||||
configuration: ReleaseOS
|
||||
addrsize: 32
|
||||
- runner: macos-12-xl
|
||||
developer_dir: "/Applications/Xcode_14.0.1.app/Contents/Developer"
|
||||
runs-on: ${{ matrix.runner }}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
name: pre-commit
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches: [main, contribute]
|
||||
tags: [v*]
|
||||
|
||||
|
||||
jobs:
|
||||
pre-commit:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.x
|
||||
- uses: pre-commit/action@v3.0.0
|
||||
|
|
@ -15,8 +15,8 @@ jobs:
|
|||
- uses: actions/stale@v6
|
||||
id: stale
|
||||
with:
|
||||
stale-pr-message: This pull request is stale because it has been open 60 days with no activity. Remove stale label or comment or it will be closed in 7 days
|
||||
days-before-stale: 60
|
||||
stale-pr-message: This pull request is stale because it has been open 30 days with no activity. Remove stale label or comment or it will be closed in 7 days
|
||||
days-before-stale: 30
|
||||
days-before-close: 7
|
||||
exempt-pr-labels: blocked,must,should,keep
|
||||
stale-pr-label: stale
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
repos:
|
||||
- repo: https://bitbucket.org/lindenlab/git-hooks.git
|
||||
rev: v1.0.0-beta2
|
||||
- repo: https://github.com/secondlife/git-hooks.git
|
||||
rev: v1.0.0
|
||||
hooks:
|
||||
- id: opensource-license
|
||||
- id: jira-issue
|
||||
- id: llsd
|
||||
- id: no-trigraphs
|
||||
- id: copyright
|
||||
|
|
@ -11,7 +10,7 @@ repos:
|
|||
files: \.(cpp|c|h|py|glsl|cmake|txt)$
|
||||
exclude: language.txt
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v2.5.0
|
||||
rev: v4.4.0
|
||||
hooks:
|
||||
- id: check-xml
|
||||
- id: mixed-line-ending
|
||||
|
|
|
|||
|
|
@ -2759,9 +2759,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>9e1b5515ab59b4e9cfeef6626d65d03d</string>
|
||||
<string>8b091b1f13348eedadf66d7d81cb6bc1</string>
|
||||
<key>url</key>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/108609/945996/viewer_manager-3.0.577252-darwin64-577252.tar.bz2</string>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/116621/1003286/viewer_manager-3.0.580913-darwin64-580913.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>darwin64</string>
|
||||
|
|
@ -2771,9 +2771,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>a3c599595ecc8fb987a5499fca42520a</string>
|
||||
<string>647e86470e02509b1cf89829d08dfd46</string>
|
||||
<key>url</key>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/108610/946003/viewer_manager-3.0.577252-windows-577252.tar.bz2</string>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/116623/1003293/viewer_manager-3.0.580913-windows-580913.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows</string>
|
||||
|
|
@ -2784,7 +2784,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<key>source_type</key>
|
||||
<string>hg</string>
|
||||
<key>version</key>
|
||||
<string>3.0.577252</string>
|
||||
<string>3.0.580913</string>
|
||||
</map>
|
||||
<key>vlc-bin</key>
|
||||
<map>
|
||||
|
|
|
|||
|
|
@ -238,6 +238,7 @@ Ansariel Hiller
|
|||
SL-15227
|
||||
SL-15398
|
||||
SL-18432
|
||||
SL-19140
|
||||
SL-4126
|
||||
Aralara Rajal
|
||||
Arare Chantilly
|
||||
|
|
@ -594,6 +595,7 @@ Henri Beauchamp
|
|||
VWR-4157
|
||||
SL-15175
|
||||
SL-19110
|
||||
SL-19159
|
||||
herina Bode
|
||||
Hikkoshi Sakai
|
||||
VWR-429
|
||||
|
|
@ -894,6 +896,7 @@ Kitty Barnett
|
|||
STORM-2149
|
||||
MAINT-7581
|
||||
MAINT-7081
|
||||
SL-18988
|
||||
Kolor Fall
|
||||
Komiko Okamoto
|
||||
Korvel Noh
|
||||
|
|
@ -932,6 +935,8 @@ Lexi Frua
|
|||
Lillie Cordeaux
|
||||
Lilly Zenovka
|
||||
Lizzy Macarthur
|
||||
Logue Takacs
|
||||
INTL-490
|
||||
Luban Yiyuan
|
||||
Luc Starsider
|
||||
Luminous Luminos
|
||||
|
|
@ -1188,6 +1193,8 @@ PanteraPolnocy
|
|||
SL-18891
|
||||
SL-18904
|
||||
SL-18937
|
||||
SL-19207
|
||||
SL-19681
|
||||
Parvati Silverweb
|
||||
Patric Mills
|
||||
VWR-2645
|
||||
|
|
@ -1413,6 +1420,7 @@ Sovereign Engineer
|
|||
SL-18525
|
||||
SL-18534
|
||||
SL-19690
|
||||
SL-19336
|
||||
SpacedOut Frye
|
||||
VWR-34
|
||||
VWR-45
|
||||
|
|
|
|||
|
|
@ -171,6 +171,10 @@ if (DARWIN)
|
|||
## Really?? On developer machines too?
|
||||
##set(ENABLE_SIGNING TRUE)
|
||||
##set(SIGNING_IDENTITY "Developer ID Application: Linden Research, Inc.")
|
||||
|
||||
# required for clang-15/xcode-15 since our boost package still uses deprecated std::unary_function/binary_function
|
||||
# see https://developer.apple.com/documentation/xcode-release-notes/xcode-15-release-notes#C++-Standard-Library
|
||||
add_compile_definitions(_LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION)
|
||||
endif (DARWIN)
|
||||
|
||||
if (LINUX OR DARWIN)
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ set(llappearance_SOURCE_FILES
|
|||
lltexglobalcolor.cpp
|
||||
lltexlayer.cpp
|
||||
lltexlayerparams.cpp
|
||||
lltexturemanagerbridge.cpp
|
||||
llwearable.cpp
|
||||
llwearabledata.cpp
|
||||
llwearabletype.cpp
|
||||
|
|
@ -44,7 +43,6 @@ set(llappearance_HEADER_FILES
|
|||
lltexglobalcolor.h
|
||||
lltexlayer.h
|
||||
lltexlayerparams.h
|
||||
lltexturemanagerbridge.h
|
||||
llwearable.h
|
||||
llwearabledata.h
|
||||
llwearabletype.h
|
||||
|
|
|
|||
|
|
@ -1050,7 +1050,6 @@ BOOL LLAvatarAppearance::loadSkeletonNode ()
|
|||
mRoot->addChild(mMeshLOD[MESH_ID_UPPER_BODY]);
|
||||
mRoot->addChild(mMeshLOD[MESH_ID_LOWER_BODY]);
|
||||
mRoot->addChild(mMeshLOD[MESH_ID_SKIRT]);
|
||||
mRoot->addChild(mMeshLOD[MESH_ID_HEAD]);
|
||||
|
||||
LLAvatarJoint *skull = (LLAvatarJoint*)mRoot->findJoint("mSkull");
|
||||
if (skull)
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@
|
|||
#include "llsaleinfo.h"
|
||||
#include "llwearabletype.h"
|
||||
|
||||
class LLMD5;
|
||||
class LLVisualParam;
|
||||
class LLTexGlobalColorInfo;
|
||||
class LLTexGlobalColor;
|
||||
|
|
@ -110,9 +109,6 @@ public:
|
|||
// Something happened that requires the wearable to be updated (e.g. worn/unworn).
|
||||
virtual void setUpdated() const = 0;
|
||||
|
||||
// Update the baked texture hash.
|
||||
virtual void addToBakedTextureHash(LLMD5& hash) const = 0;
|
||||
|
||||
typedef std::map<S32, LLVisualParam *> visual_param_index_map_t;
|
||||
visual_param_index_map_t mVisualParamIndexMap;
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@
|
|||
#include "llavatarappearance.h"
|
||||
#include "llavatarappearancedefines.h"
|
||||
#include "lldriverparam.h"
|
||||
#include "llmd5.h"
|
||||
|
||||
LLWearableData::LLWearableData() :
|
||||
mAvatarAppearance(NULL)
|
||||
|
|
@ -343,42 +342,3 @@ U32 LLWearableData::getWearableCount(const U32 tex_index) const
|
|||
const LLWearableType::EType wearable_type = LLAvatarAppearance::getDictionary()->getTEWearableType((LLAvatarAppearanceDefines::ETextureIndex)tex_index);
|
||||
return getWearableCount(wearable_type);
|
||||
}
|
||||
|
||||
LLUUID LLWearableData::computeBakedTextureHash(LLAvatarAppearanceDefines::EBakedTextureIndex baked_index,
|
||||
BOOL generate_valid_hash) // Set to false if you want to upload the baked texture w/o putting it in the cache
|
||||
{
|
||||
LLUUID hash_id;
|
||||
bool hash_computed = false;
|
||||
LLMD5 hash;
|
||||
const LLAvatarAppearanceDictionary::BakedEntry *baked_dict = LLAvatarAppearance::getDictionary()->getBakedTexture(baked_index);
|
||||
|
||||
for (U8 i=0; i < baked_dict->mWearables.size(); i++)
|
||||
{
|
||||
const LLWearableType::EType baked_type = baked_dict->mWearables[i];
|
||||
const U32 num_wearables = getWearableCount(baked_type);
|
||||
for (U32 index = 0; index < num_wearables; ++index)
|
||||
{
|
||||
const LLWearable* wearable = getWearable(baked_type,index);
|
||||
if (wearable)
|
||||
{
|
||||
wearable->addToBakedTextureHash(hash);
|
||||
hash_computed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hash_computed)
|
||||
{
|
||||
hash.update((const unsigned char*)baked_dict->mWearablesHashID.mData, UUID_BYTES);
|
||||
|
||||
if (!generate_valid_hash)
|
||||
{
|
||||
invalidateBakedTextureHash(hash);
|
||||
}
|
||||
hash.finalize();
|
||||
hash.raw_digest(hash_id.mData);
|
||||
}
|
||||
|
||||
return hash_id;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -85,15 +85,6 @@ protected:
|
|||
private:
|
||||
void pullCrossWearableValues(const LLWearableType::EType type);
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Server Communication
|
||||
//--------------------------------------------------------------------
|
||||
public:
|
||||
LLUUID computeBakedTextureHash(LLAvatarAppearanceDefines::EBakedTextureIndex baked_index,
|
||||
BOOL generate_valid_hash = TRUE);
|
||||
protected:
|
||||
virtual void invalidateBakedTextureHash(LLMD5& hash) const {}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Member variables
|
||||
//--------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -204,7 +204,8 @@ std::string LLAudioEngine::getInternetStreamURL()
|
|||
{
|
||||
if (mStreamingAudioImpl)
|
||||
return mStreamingAudioImpl->getURL();
|
||||
else return std::string();
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -345,42 +346,43 @@ void LLAudioEngine::idle()
|
|||
}
|
||||
continue;
|
||||
}
|
||||
else
|
||||
|
||||
// Check to see if the current sound is done playing.
|
||||
if (!channelp->isPlaying())
|
||||
{
|
||||
// Check to see if the current sound is done playing, or looped.
|
||||
if (!channelp->isPlaying())
|
||||
sourcep->mCurrentDatap = sourcep->mQueuedDatap;
|
||||
sourcep->mQueuedDatap = NULL;
|
||||
|
||||
// Reset the timer so the source doesn't die.
|
||||
sourcep->mAgeTimer.reset();
|
||||
|
||||
// Make sure we have the buffer set up if we just decoded the data
|
||||
if (sourcep->mCurrentDatap)
|
||||
{
|
||||
updateBufferForData(sourcep->mCurrentDatap);
|
||||
}
|
||||
|
||||
// Actually play the associated data.
|
||||
sourcep->setupChannel();
|
||||
channelp->updateBuffer();
|
||||
sourcep->getChannel()->play();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check to see if the current sound is looped.
|
||||
if (sourcep->isLoop())
|
||||
{
|
||||
// It's a loop, we need to check and see if we're done with it.
|
||||
if (channelp->mLoopedThisFrame)
|
||||
{
|
||||
sourcep->mCurrentDatap = sourcep->mQueuedDatap;
|
||||
sourcep->mQueuedDatap = NULL;
|
||||
|
||||
// Reset the timer so the source doesn't die.
|
||||
sourcep->mAgeTimer.reset();
|
||||
|
||||
// Make sure we have the buffer set up if we just decoded the data
|
||||
if (sourcep->mCurrentDatap)
|
||||
{
|
||||
updateBufferForData(sourcep->mCurrentDatap);
|
||||
}
|
||||
|
||||
// Actually play the associated data.
|
||||
// Actually, should do a time sync so if we're a loop master/slave
|
||||
// we don't drift away.
|
||||
sourcep->setupChannel();
|
||||
channelp->updateBuffer();
|
||||
sourcep->getChannel()->play();
|
||||
}
|
||||
else if (sourcep->isLoop())
|
||||
{
|
||||
// It's a loop, we need to check and see if we're done with it.
|
||||
if (channelp->mLoopedThisFrame)
|
||||
{
|
||||
sourcep->mCurrentDatap = sourcep->mQueuedDatap;
|
||||
sourcep->mQueuedDatap = NULL;
|
||||
|
||||
// Actually, should do a time sync so if we're a loop master/slave
|
||||
// we don't drift away.
|
||||
sourcep->setupChannel();
|
||||
sourcep->getChannel()->play();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -396,18 +398,11 @@ void LLAudioEngine::idle()
|
|||
for (source_map::value_type& src_pair : mAllSources)
|
||||
{
|
||||
LLAudioSource *sourcep = src_pair.second;
|
||||
if (sourcep->isMuted())
|
||||
if (sourcep->isMuted() && sourcep->isSyncMaster() && sourcep->getPriority() > max_sm_priority)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (sourcep->isSyncMaster())
|
||||
{
|
||||
if (sourcep->getPriority() > max_sm_priority)
|
||||
{
|
||||
sync_masterp = sourcep;
|
||||
master_channelp = sync_masterp->getChannel();
|
||||
max_sm_priority = sourcep->getPriority();
|
||||
}
|
||||
sync_masterp = sourcep;
|
||||
master_channelp = sync_masterp->getChannel();
|
||||
max_sm_priority = sourcep->getPriority();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -737,7 +732,7 @@ F64 LLAudioEngine::mapWindVecToGain(LLVector3 wind_vec)
|
|||
}
|
||||
|
||||
return (gain);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
F64 LLAudioEngine::mapWindVecToPitch(LLVector3 wind_vec)
|
||||
|
|
@ -964,11 +959,10 @@ void LLAudioEngine::cleanupAudioSource(LLAudioSource *asp)
|
|||
else
|
||||
{
|
||||
LL_DEBUGS("AudioEngine") << "Cleaning up audio sources for "<< asp->getID() <<LL_ENDL;
|
||||
delete asp;
|
||||
mAllSources.erase(iter);
|
||||
delete asp;
|
||||
mAllSources.erase(iter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool LLAudioEngine::hasDecodedFile(const LLUUID &uuid)
|
||||
{
|
||||
|
|
@ -1687,19 +1681,18 @@ void LLAudioChannel::setSource(LLAudioSource *sourcep)
|
|||
{
|
||||
LL_DEBUGS("AudioEngine") << "( id: " << sourcep->getID() << ")" << LL_ENDL;
|
||||
|
||||
if (sourcep == mCurrentSourcep)
|
||||
{
|
||||
// Don't reallocate the channel, this will make FMOD goofy.
|
||||
//LL_INFOS() << "Calling setSource with same source!" << LL_ENDL;
|
||||
if (sourcep == mCurrentSourcep)
|
||||
{
|
||||
// Don't reallocate the channel, this will make FMOD goofy.
|
||||
//LL_INFOS() << "Calling setSource with same source!" << LL_ENDL;
|
||||
}
|
||||
|
||||
mCurrentSourcep = sourcep;
|
||||
|
||||
updateBuffer();
|
||||
update3DPosition();
|
||||
}
|
||||
|
||||
mCurrentSourcep = sourcep;
|
||||
|
||||
updateBuffer();
|
||||
update3DPosition();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool LLAudioChannel::updateBuffer()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -90,6 +90,7 @@ public:
|
|||
// initialization/startup/shutdown
|
||||
virtual bool init(void *userdata, const std::string &app_title);
|
||||
virtual std::string getDriverName(bool verbose) = 0;
|
||||
virtual LLStreamingAudioInterface *createDefaultStreamingAudioImpl() const = 0;
|
||||
virtual void shutdown();
|
||||
|
||||
// Used by the mechanics of the engine
|
||||
|
|
@ -468,13 +469,13 @@ struct SoundData
|
|||
const LLUUID& owner_id,
|
||||
const F32 gain,
|
||||
const S32 type = LLAudioEngine::AUDIO_TYPE_NONE,
|
||||
const LLVector3d &pos_global = LLVector3d::zero)
|
||||
const LLVector3d &pos_global = LLVector3d::zero) :
|
||||
audio_uuid(audio_uuid),
|
||||
owner_id(owner_id),
|
||||
gain(gain),
|
||||
type(type),
|
||||
pos_global(pos_global)
|
||||
{
|
||||
this->audio_uuid = audio_uuid;
|
||||
this->owner_id = owner_id;
|
||||
this->gain = gain;
|
||||
this->type = type;
|
||||
this->pos_global = pos_global;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -208,10 +208,6 @@ bool LLAudioEngine_FMODSTUDIO::init(void* userdata, const std::string &app_title
|
|||
}
|
||||
#endif
|
||||
|
||||
// set up our favourite FMOD-native streaming audio implementation if none has already been added
|
||||
if (!getStreamingAudioImpl()) // no existing implementation added
|
||||
setStreamingAudioImpl(new LLStreamingAudio_FMODSTUDIO(mSystem));
|
||||
|
||||
LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init() FMOD Studio initialized correctly" << LL_ENDL;
|
||||
|
||||
int r_numbuffers, r_samplerate, r_channels;
|
||||
|
|
@ -253,6 +249,13 @@ std::string LLAudioEngine_FMODSTUDIO::getDriverName(bool verbose)
|
|||
}
|
||||
|
||||
|
||||
// create our favourite FMOD-native streaming audio implementation
|
||||
LLStreamingAudioInterface *LLAudioEngine_FMODSTUDIO::createDefaultStreamingAudioImpl() const
|
||||
{
|
||||
return new LLStreamingAudio_FMODSTUDIO(mSystem);
|
||||
}
|
||||
|
||||
|
||||
void LLAudioEngine_FMODSTUDIO::allocateListener(void)
|
||||
{
|
||||
mListenerp = (LLListener *) new LLListener_FMODSTUDIO(mSystem);
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ public:
|
|||
// initialization/startup/shutdown
|
||||
virtual bool init(void *user_data, const std::string &app_title);
|
||||
virtual std::string getDriverName(bool verbose);
|
||||
virtual LLStreamingAudioInterface* createDefaultStreamingAudioImpl() const;
|
||||
virtual void allocateListener();
|
||||
|
||||
virtual void shutdown();
|
||||
|
|
|
|||
|
|
@ -1352,7 +1352,6 @@ BOOL LLBVHLoader::serialize(LLDataPacker& dp)
|
|||
dp.packS32(joint->mNumRotKeys, "num_rot_keys");
|
||||
|
||||
LLQuaternion::Order order = bvhStringToOrder( joint->mOrder );
|
||||
S32 outcount = 0;
|
||||
S32 frame = 0;
|
||||
for (Key& key : joint->mKeys)
|
||||
{
|
||||
|
|
@ -1418,7 +1417,6 @@ BOOL LLBVHLoader::serialize(LLDataPacker& dp)
|
|||
dp.packU16(x, "rot_angle_x");
|
||||
dp.packU16(y, "rot_angle_y");
|
||||
dp.packU16(z, "rot_angle_z");
|
||||
outcount++;
|
||||
frame++;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -497,13 +497,20 @@ LLMotion::LLMotionInitStatus LLKeyframeMotion::onInitialize(LLCharacter *charact
|
|||
// request asset
|
||||
mAssetStatus = ASSET_FETCHED;
|
||||
|
||||
LL_DEBUGS("Animation") << "Requesting data fetch for: " << mID << LL_ENDL;
|
||||
character_id = new LLUUID(mCharacter->getID());
|
||||
gAssetStorage->getAssetData(mID,
|
||||
LLAssetType::AT_ANIMATION,
|
||||
onLoadComplete,
|
||||
(void *)character_id,
|
||||
FALSE);
|
||||
if (mID.notNull())
|
||||
{
|
||||
LL_DEBUGS("Animation") << "Requesting data fetch for: " << mID << LL_ENDL;
|
||||
character_id = new LLUUID(mCharacter->getID());
|
||||
gAssetStorage->getAssetData(mID,
|
||||
LLAssetType::AT_ANIMATION,
|
||||
onLoadComplete,
|
||||
(void*)character_id,
|
||||
FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_INFOS("Animation") << "Attempted to fetch animation " << mName << " with null id for character " << mCharacter->getID() << LL_ENDL;
|
||||
}
|
||||
|
||||
return STATUS_HOLD;
|
||||
case ASSET_FETCHED:
|
||||
|
|
@ -1391,6 +1398,8 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp, const LLUUID& asset_id, boo
|
|||
// get number of joint motions
|
||||
//-------------------------------------------------------------------------
|
||||
U32 num_motions = 0;
|
||||
S32 rotation_dupplicates = 0;
|
||||
S32 position_dupplicates = 0;
|
||||
if (!dp.unpackU32(num_motions, "num_joints"))
|
||||
{
|
||||
LL_WARNS() << "can't read number of joints"
|
||||
|
|
@ -1621,6 +1630,12 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp, const LLUUID& asset_id, boo
|
|||
rCurve->mKeys[time] = rot_key;
|
||||
}
|
||||
|
||||
if (joint_motion->mRotationCurve.mNumKeys > joint_motion->mRotationCurve.mKeys.size())
|
||||
{
|
||||
rotation_dupplicates++;
|
||||
LL_INFOS() << "Motion: " << asset_id << " had dupplicate rotation keys that were removed" << LL_ENDL;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// scan position curve header
|
||||
//---------------------------------------------------------------------
|
||||
|
|
@ -1723,9 +1738,24 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp, const LLUUID& asset_id, boo
|
|||
}
|
||||
}
|
||||
|
||||
if (joint_motion->mPositionCurve.mNumKeys > joint_motion->mPositionCurve.mKeys.size())
|
||||
{
|
||||
position_dupplicates++;
|
||||
}
|
||||
|
||||
joint_motion->mUsage = joint_state->getUsage();
|
||||
}
|
||||
|
||||
if (rotation_dupplicates > 0)
|
||||
{
|
||||
LL_INFOS() << "Motion: " << asset_id << " had " << rotation_dupplicates << " dupplicate rotation keys that were removed" << LL_ENDL;
|
||||
}
|
||||
|
||||
if (position_dupplicates > 0)
|
||||
{
|
||||
LL_INFOS() << "Motion: " << asset_id << " had " << position_dupplicates << " dupplicate position keys that were removed" << LL_ENDL;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// get number of constraints
|
||||
//-------------------------------------------------------------------------
|
||||
|
|
@ -2005,10 +2035,13 @@ BOOL LLKeyframeMotion::serialize(LLDataPacker& dp) const
|
|||
JointMotion* joint_motionp = mJointMotionList->getJointMotion(i);
|
||||
success &= dp.packString(joint_motionp->mJointName, "joint_name");
|
||||
success &= dp.packS32(joint_motionp->mPriority, "joint_priority");
|
||||
success &= dp.packS32(joint_motionp->mRotationCurve.mNumKeys, "num_rot_keys");
|
||||
success &= dp.packS32(joint_motionp->mRotationCurve.mKeys.size(), "num_rot_keys");
|
||||
|
||||
LL_DEBUGS("BVH") << "Joint " << joint_motionp->mJointName << LL_ENDL;
|
||||
for (RotationCurve::key_map_t::value_type& rot_pair : joint_motionp->mRotationCurve.mKeys)
|
||||
LL_DEBUGS("BVH") << "Joint " << i
|
||||
<< " name: " << joint_motionp->mJointName
|
||||
<< " Rotation keys: " << joint_motionp->mRotationCurve.mKeys.size()
|
||||
<< " Position keys: " << joint_motionp->mPositionCurve.mKeys.size() << LL_ENDL;
|
||||
for (RotationCurve::key_map_t::value_type& rot_pair : joint_motionp->mRotationCurve.mKeys)
|
||||
{
|
||||
RotationKey& rot_key = rot_pair.second;
|
||||
U16 time_short = F32_to_U16(rot_key.mTime, 0.f, mJointMotionList->mDuration);
|
||||
|
|
@ -2028,7 +2061,7 @@ BOOL LLKeyframeMotion::serialize(LLDataPacker& dp) const
|
|||
LL_DEBUGS("BVH") << " rot: t " << rot_key.mTime << " angles " << rot_angles.mV[VX] <<","<< rot_angles.mV[VY] <<","<< rot_angles.mV[VZ] << LL_ENDL;
|
||||
}
|
||||
|
||||
success &= dp.packS32(joint_motionp->mPositionCurve.mNumKeys, "num_pos_keys");
|
||||
success &= dp.packS32(joint_motionp->mPositionCurve.mKeys.size(), "num_pos_keys");
|
||||
for (PositionCurve::key_map_t::value_type& pos_pair : joint_motionp->mPositionCurve.mKeys)
|
||||
{
|
||||
PositionKey& pos_key = pos_pair.second;
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@ set(llcommon_SOURCE_FILES
|
|||
lldependencies.cpp
|
||||
lldictionary.cpp
|
||||
llerror.cpp
|
||||
llerrorthread.cpp
|
||||
llevent.cpp
|
||||
lleventapi.cpp
|
||||
lleventcoro.cpp
|
||||
|
|
@ -153,7 +152,6 @@ set(llcommon_HEADER_FILES
|
|||
llendianswizzle.h
|
||||
llerror.h
|
||||
llerrorcontrol.h
|
||||
llerrorthread.h
|
||||
llevent.h
|
||||
lleventapi.h
|
||||
lleventcoro.h
|
||||
|
|
|
|||
|
|
@ -96,6 +96,15 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
// Make this class no-copy (it would be possible, with custom copy
|
||||
// operators, but it is not trivially copyable, because of the mState
|
||||
// pointer): it does not really make sense to allow copying it anyway,
|
||||
// since all we care about is the resulting digest (so you should only
|
||||
// need and care about storing/copying the digest and not a class
|
||||
// instance).
|
||||
HBXXH64(const HBXXH64&) noexcept = delete;
|
||||
HBXXH64& operator=(const HBXXH64&) noexcept = delete;
|
||||
|
||||
~HBXXH64();
|
||||
|
||||
void update(const void* buffer, size_t len);
|
||||
|
|
@ -199,6 +208,15 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
// Make this class no-copy (it would be possible, with custom copy
|
||||
// operators, but it is not trivially copyable, because of the mState
|
||||
// pointer): it does not really make sense to allow copying it anyway,
|
||||
// since all we care about is the resulting digest (so you should only
|
||||
// need and care about storing/copying the digest and not a class
|
||||
// instance).
|
||||
HBXXH128(const HBXXH128&) noexcept = delete;
|
||||
HBXXH128& operator=(const HBXXH128&) noexcept = delete;
|
||||
|
||||
~HBXXH128();
|
||||
|
||||
void update(const void* buffer, size_t len);
|
||||
|
|
|
|||
|
|
@ -345,6 +345,7 @@ const U8 CLICK_ACTION_PLAY = 5;
|
|||
const U8 CLICK_ACTION_OPEN_MEDIA = 6;
|
||||
const U8 CLICK_ACTION_ZOOM = 7;
|
||||
const U8 CLICK_ACTION_DISABLED = 8;
|
||||
const U8 CLICK_ACTION_IGNORE = 9;
|
||||
// DO NOT CHANGE THE SEQUENCE OF THIS LIST!!
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,6 @@
|
|||
#include "llcommon.h"
|
||||
#include "llapr.h"
|
||||
#include "llerrorcontrol.h"
|
||||
#include "llerrorthread.h"
|
||||
#include "llframetimer.h"
|
||||
#include "lllivefile.h"
|
||||
#include "llmemory.h"
|
||||
|
|
@ -108,12 +107,7 @@ LLAppErrorHandler LLApp::sErrorHandler = NULL;
|
|||
BOOL LLApp::sErrorThreadRunning = FALSE;
|
||||
|
||||
|
||||
LLApp::LLApp() : mThreadErrorp(NULL)
|
||||
{
|
||||
commonCtor();
|
||||
}
|
||||
|
||||
void LLApp::commonCtor()
|
||||
LLApp::LLApp()
|
||||
{
|
||||
// Set our status to running
|
||||
setStatus(APP_STATUS_RUNNING);
|
||||
|
|
@ -143,12 +137,6 @@ void LLApp::commonCtor()
|
|||
mCrashReportPipeStr = L"\\\\.\\pipe\\LLCrashReporterPipe";
|
||||
}
|
||||
|
||||
LLApp::LLApp(LLErrorThread *error_thread) :
|
||||
mThreadErrorp(error_thread)
|
||||
{
|
||||
commonCtor();
|
||||
}
|
||||
|
||||
|
||||
LLApp::~LLApp()
|
||||
{
|
||||
|
|
@ -158,13 +146,6 @@ LLApp::~LLApp()
|
|||
mLiveFiles.clear();
|
||||
|
||||
setStopped();
|
||||
// HACK: wait for the error thread to clean itself
|
||||
ms_sleep(20);
|
||||
if (mThreadErrorp)
|
||||
{
|
||||
delete mThreadErrorp;
|
||||
mThreadErrorp = NULL;
|
||||
}
|
||||
|
||||
SUBSYSTEM_CLEANUP_DBG(LLCommon);
|
||||
}
|
||||
|
|
@ -393,27 +374,6 @@ void LLApp::setupErrorHandling(bool second_instance)
|
|||
#endif // ! LL_BUGSPLAT
|
||||
|
||||
#endif // ! LL_WINDOWS
|
||||
|
||||
#ifdef LL_BUGSPLAT
|
||||
// do not start our own error thread
|
||||
#else // ! LL_BUGSPLAT
|
||||
startErrorThread();
|
||||
#endif
|
||||
}
|
||||
|
||||
void LLApp::startErrorThread()
|
||||
{
|
||||
//
|
||||
// Start the error handling thread, which is responsible for taking action
|
||||
// when the app goes into the APP_STATUS_ERROR state
|
||||
//
|
||||
if(!mThreadErrorp)
|
||||
{
|
||||
LL_INFOS() << "Starting error thread" << LL_ENDL;
|
||||
mThreadErrorp = new LLErrorThread();
|
||||
mThreadErrorp->setUserData((void *) this);
|
||||
mThreadErrorp->start();
|
||||
}
|
||||
}
|
||||
|
||||
void LLApp::setErrorHandler(LLAppErrorHandler handler)
|
||||
|
|
@ -476,7 +436,7 @@ void LLApp::setStatus(EAppStatus status)
|
|||
// static
|
||||
void LLApp::setError()
|
||||
{
|
||||
// set app status to ERROR so that the LLErrorThread notices
|
||||
// set app status to ERROR
|
||||
setStatus(APP_STATUS_ERROR);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@
|
|||
#include <atomic>
|
||||
#include <chrono>
|
||||
// Forward declarations
|
||||
class LLErrorThread;
|
||||
class LLLiveFile;
|
||||
#if LL_LINUX
|
||||
#include <signal.h>
|
||||
|
|
@ -53,7 +52,6 @@ void clear_signals();
|
|||
|
||||
class LL_COMMON_API LLApp
|
||||
{
|
||||
friend class LLErrorThread;
|
||||
public:
|
||||
typedef enum e_app_status
|
||||
{
|
||||
|
|
@ -67,11 +65,6 @@ public:
|
|||
LLApp();
|
||||
virtual ~LLApp();
|
||||
|
||||
protected:
|
||||
LLApp(LLErrorThread* error_thread);
|
||||
void commonCtor();
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Return the static app instance if one was created.
|
||||
*/
|
||||
|
|
@ -257,14 +250,14 @@ public:
|
|||
void setupErrorHandling(bool mSecondInstance=false);
|
||||
|
||||
void setErrorHandler(LLAppErrorHandler handler);
|
||||
static void runErrorHandler(); // run shortly after we detect an error, ran in the relatively robust context of the LLErrorThread - preferred.
|
||||
static void runErrorHandler(); // run shortly after we detect an error
|
||||
//@}
|
||||
|
||||
|
||||
// the maximum length of the minidump filename returned by getMiniDumpFilename()
|
||||
static const U32 MAX_MINDUMP_PATH_LENGTH = 256;
|
||||
|
||||
// change the directory where Breakpad minidump files are written to
|
||||
void setDebugFileNames(const std::string &path);
|
||||
void setDebugFileNames(const std::string &path);
|
||||
|
||||
// Return the Google Breakpad minidump filename after a crash.
|
||||
char *getMiniDumpFilename() { return mMinidumpPath; }
|
||||
|
|
@ -310,13 +303,11 @@ protected:
|
|||
void stepFrame();
|
||||
|
||||
private:
|
||||
void startErrorThread();
|
||||
|
||||
// Contains the filename of the minidump file after a crash.
|
||||
char mMinidumpPath[MAX_MINDUMP_PATH_LENGTH];
|
||||
|
||||
std::string mStaticDebugFileName;
|
||||
std::string mDynamicDebugFileName;
|
||||
std::string mStaticDebugFileName;
|
||||
std::string mDynamicDebugFileName;
|
||||
|
||||
// *NOTE: On Windows, we need a routine to reset the structured
|
||||
// exception handler when some evil driver has taken it over for
|
||||
|
|
@ -324,9 +315,6 @@ private:
|
|||
typedef int(*signal_handler_func)(int signum);
|
||||
static LLAppErrorHandler sErrorHandler;
|
||||
|
||||
// Default application threads
|
||||
LLErrorThread* mThreadErrorp; // Waits for app to go to status ERROR, then runs the error callback
|
||||
|
||||
// This is the application level runnable scheduler.
|
||||
LLRunner mRunner;
|
||||
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ void LLCallbackList::addFunction( callback_t func, void *data)
|
|||
|
||||
// only add one callback per func/data pair
|
||||
//
|
||||
if (containsFunction(func))
|
||||
if (containsFunction(func, data))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -167,48 +167,34 @@ const U32 MAXADDRSTR = 17; // 123.567.901.345 = 15 chars + \0 + 1 for good luc
|
|||
//
|
||||
// defined for U16, U32, U64, S16, S32, S64, :
|
||||
// llclampb(a) // clamps a to [0 .. 255]
|
||||
//
|
||||
//
|
||||
|
||||
template <typename T1, typename T2>
|
||||
inline auto llmax(T1 d1, T2 d2)
|
||||
// recursion tail
|
||||
template <typename T>
|
||||
inline auto llmax(T data)
|
||||
{
|
||||
return (d1 > d2) ? d1 : d2;
|
||||
return data;
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3>
|
||||
inline auto llmax(T1 d1, T2 d2, T3 d3)
|
||||
template <typename T0, typename T1, typename... Ts>
|
||||
inline auto llmax(T0 d0, T1 d1, Ts... rest)
|
||||
{
|
||||
auto r = llmax(d1,d2);
|
||||
return llmax(r, d3);
|
||||
auto maxrest = llmax(d1, rest...);
|
||||
return (d0 > maxrest)? d0 : maxrest;
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3, typename T4>
|
||||
inline auto llmax(T1 d1, T2 d2, T3 d3, T4 d4)
|
||||
// recursion tail
|
||||
template <typename T>
|
||||
inline auto llmin(T data)
|
||||
{
|
||||
auto r1 = llmax(d1,d2);
|
||||
auto r2 = llmax(d3,d4);
|
||||
return llmax(r1, r2);
|
||||
return data;
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
inline auto llmin(T1 d1, T2 d2)
|
||||
template <typename T0, typename T1, typename... Ts>
|
||||
inline auto llmin(T0 d0, T1 d1, Ts... rest)
|
||||
{
|
||||
return (d1 < d2) ? d1 : d2;
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3>
|
||||
inline auto llmin(T1 d1, T2 d2, T3 d3)
|
||||
{
|
||||
auto r = llmin(d1,d2);
|
||||
return (r < d3 ? r : d3);
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3, typename T4>
|
||||
inline auto llmin(T1 d1, T2 d2, T3 d3, T4 d4)
|
||||
{
|
||||
auto r1 = llmin(d1,d2);
|
||||
auto r2 = llmin(d3,d4);
|
||||
return llmin(r1, r2);
|
||||
auto minrest = llmin(d1, rest...);
|
||||
return (d0 < minrest) ? d0 : minrest;
|
||||
}
|
||||
|
||||
template <typename A, typename MIN, typename MAX>
|
||||
|
|
|
|||
|
|
@ -276,7 +276,6 @@ namespace LLError
|
|||
// used to indicate no class info known for logging
|
||||
|
||||
//LLCallStacks keeps track of call stacks and output the call stacks to log file
|
||||
//when LLAppViewer::handleViewerCrash() is triggered.
|
||||
//
|
||||
//Note: to be simple, efficient and necessary to keep track of correct call stacks,
|
||||
//LLCallStacks is designed not to be thread-safe.
|
||||
|
|
|
|||
|
|
@ -1,133 +0,0 @@
|
|||
/**
|
||||
* @file llerrorthread.cpp
|
||||
*
|
||||
* $LicenseInfo:firstyear=2004&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, 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$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
#include "llerrorthread.h"
|
||||
|
||||
#include "llapp.h"
|
||||
#include "lltimer.h" // ms_sleep()
|
||||
|
||||
LLErrorThread::LLErrorThread()
|
||||
: LLThread("Error"),
|
||||
mUserDatap(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
LLErrorThread::~LLErrorThread()
|
||||
{
|
||||
}
|
||||
|
||||
void LLErrorThread::setUserData(void* user_data)
|
||||
{
|
||||
mUserDatap = user_data;
|
||||
}
|
||||
|
||||
|
||||
void* LLErrorThread::getUserData() const
|
||||
{
|
||||
return mUserDatap;
|
||||
}
|
||||
|
||||
#if !LL_WINDOWS
|
||||
//
|
||||
// Various signal/error handling functions that can't be put into the class
|
||||
//
|
||||
void get_child_status(const int waitpid_status, int &process_status, bool &exited, bool do_logging)
|
||||
{
|
||||
exited = false;
|
||||
process_status = -1;
|
||||
// The child process exited. Call its callback, and then clean it up
|
||||
if (WIFEXITED(waitpid_status))
|
||||
{
|
||||
process_status = WEXITSTATUS(waitpid_status);
|
||||
exited = true;
|
||||
if (do_logging)
|
||||
{
|
||||
LL_INFOS() << "get_child_status - Child exited cleanly with return of " << process_status << LL_ENDL;
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (WIFSIGNALED(waitpid_status))
|
||||
{
|
||||
process_status = WTERMSIG(waitpid_status);
|
||||
exited = true;
|
||||
if (do_logging)
|
||||
{
|
||||
LL_INFOS() << "get_child_status - Child died because of uncaught signal " << process_status << LL_ENDL;
|
||||
#ifdef WCOREDUMP
|
||||
if (WCOREDUMP(waitpid_status))
|
||||
{
|
||||
LL_INFOS() << "get_child_status - Child dumped core" << LL_ENDL;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_INFOS() << "get_child_status - Child didn't dump core" << LL_ENDL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (do_logging)
|
||||
{
|
||||
// This is weird. I just dump the waitpid status into the status code,
|
||||
// not that there's any way of telling what it is...
|
||||
LL_INFOS() << "get_child_status - Got SIGCHILD but child didn't exit" << LL_ENDL;
|
||||
process_status = waitpid_status;
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
void LLErrorThread::run()
|
||||
{
|
||||
LLApp::sErrorThreadRunning = TRUE;
|
||||
// This thread sits and waits for the sole purpose
|
||||
// of waiting for the signal/exception handlers to flag the
|
||||
// application state as APP_STATUS_ERROR.
|
||||
LL_INFOS() << "thread_error - Waiting for an error" << LL_ENDL;
|
||||
|
||||
S32 counter = 0;
|
||||
while (! (LLApp::isError() || LLApp::isStopped()))
|
||||
{
|
||||
ms_sleep(10);
|
||||
counter++;
|
||||
}
|
||||
if (LLApp::isError())
|
||||
{
|
||||
// The app is in an error state, run the application's error handler.
|
||||
//LL_INFOS() << "thread_error - An error has occurred, running error callback!" << LL_ENDL;
|
||||
// Run the error handling callback
|
||||
LLApp::runErrorHandler();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Everything is okay, a clean exit.
|
||||
//LL_INFOS() << "thread_error - Application exited cleanly" << LL_ENDL;
|
||||
}
|
||||
|
||||
//LL_INFOS() << "thread_error - Exiting" << LL_ENDL;
|
||||
LLApp::sErrorThreadRunning = FALSE;
|
||||
}
|
||||
|
||||
|
|
@ -204,30 +204,35 @@ public:
|
|||
LLSD packet(LLSDMap("pump", pump)("data", data));
|
||||
|
||||
std::ostringstream buffer;
|
||||
buffer << LLSDNotationStreamer(packet);
|
||||
// SL-18330: for large data blocks, it's much faster to parse binary
|
||||
// LLSD than notation LLSD. Use serialize(LLSD_BINARY) rather than
|
||||
// directly calling LLSDBinaryFormatter because, unlike the latter,
|
||||
// serialize() prepends the relevant header, needed by a general-
|
||||
// purpose LLSD parser to distinguish binary from notation.
|
||||
LLSDSerialize::serialize(packet, buffer, LLSDSerialize::LLSD_BINARY,
|
||||
LLSDFormatter::OPTIONS_NONE);
|
||||
|
||||
/*==========================================================================*|
|
||||
// DEBUGGING ONLY: don't copy str() if we can avoid it.
|
||||
std::string strdata(buffer.str());
|
||||
if (std::size_t(buffer.tellp()) != strdata.length())
|
||||
{
|
||||
LL_ERRS("LLLeap") << "tellp() -> " << buffer.tellp() << " != "
|
||||
LL_ERRS("LLLeap") << "tellp() -> " << static_cast<U64>(buffer.tellp()) << " != "
|
||||
<< "str().length() -> " << strdata.length() << LL_ENDL;
|
||||
}
|
||||
// DEBUGGING ONLY: reading back is terribly inefficient.
|
||||
std::istringstream readback(strdata);
|
||||
LLSD echo;
|
||||
LLPointer<LLSDParser> parser(new LLSDNotationParser());
|
||||
S32 parse_status(parser->parse(readback, echo, strdata.length()));
|
||||
if (parse_status == LLSDParser::PARSE_FAILURE)
|
||||
bool parse_status(LLSDSerialize::deserialize(echo, readback, strdata.length()));
|
||||
if (! parse_status)
|
||||
{
|
||||
LL_ERRS("LLLeap") << "LLSDNotationParser() cannot parse output of "
|
||||
<< "LLSDNotationStreamer()" << LL_ENDL;
|
||||
LL_ERRS("LLLeap") << "LLSDSerialize::deserialize() cannot parse output of "
|
||||
<< "LLSDSerialize::serialize(LLSD_BINARY)" << LL_ENDL;
|
||||
}
|
||||
if (! llsd_equals(echo, packet))
|
||||
{
|
||||
LL_ERRS("LLLeap") << "LLSDNotationParser() produced different LLSD "
|
||||
<< "than passed to LLSDNotationStreamer()" << LL_ENDL;
|
||||
LL_ERRS("LLLeap") << "LLSDSerialize::deserialize() returned different LLSD "
|
||||
<< "than passed to LLSDSerialize::serialize()" << LL_ENDL;
|
||||
}
|
||||
|*==========================================================================*/
|
||||
|
||||
|
|
@ -314,9 +319,17 @@ public:
|
|||
LL_DEBUGS("LLLeap") << "needed " << mExpect << " bytes, got "
|
||||
<< childout.size() << ", parsing LLSD" << LL_ENDL;
|
||||
LLSD data;
|
||||
#if 1
|
||||
// specifically require notation LLSD from child
|
||||
LLPointer<LLSDParser> parser(new LLSDNotationParser());
|
||||
S32 parse_status(parser->parse(childout.get_istream(), data, mExpect));
|
||||
if (parse_status == LLSDParser::PARSE_FAILURE)
|
||||
#else
|
||||
// SL-18330: accept any valid LLSD serialization format from child
|
||||
// Unfortunately this runs into trouble we have not yet debugged.
|
||||
bool parse_status(LLSDSerialize::deserialize(data, childout.get_istream(), mExpect));
|
||||
if (! parse_status)
|
||||
#endif
|
||||
{
|
||||
bad_protocol("unparseable LLSD data");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ LLMD5::LLMD5()
|
|||
// operation, processing another message block, and updating the
|
||||
// context.
|
||||
|
||||
void LLMD5::update (const uint1 *input, const size_t input_length) {
|
||||
void LLMD5::update (const uint8_t *input, const size_t input_length) {
|
||||
|
||||
size_t input_index, buffer_index;
|
||||
size_t buffer_space; // how much space is left in buffer
|
||||
|
|
@ -189,7 +189,7 @@ void LLMD5::finalize (){
|
|||
|
||||
unsigned char bits[8]; /* Flawfinder: ignore */
|
||||
size_t index, padLen;
|
||||
static uint1 PADDING[64]={
|
||||
static uint8_t PADDING[64]={
|
||||
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
|
|
@ -201,8 +201,8 @@ void LLMD5::finalize (){
|
|||
}
|
||||
|
||||
// Save number of bits.
|
||||
// Treat count, a uint64_t, as uint4[2].
|
||||
encode (bits, reinterpret_cast<uint4*>(&count), 8);
|
||||
// Treat count, a uint64_t, as uint32_t[2].
|
||||
encode (bits, reinterpret_cast<uint32_t*>(&count), 8);
|
||||
|
||||
// Pad out to 56 mod 64.
|
||||
index = size_t((count >> 3) & 0x3f);
|
||||
|
|
@ -412,7 +412,7 @@ Rotation is separate from addition to prevent recomputation.
|
|||
// LLMD5 basic transformation. Transforms state based on block.
|
||||
void LLMD5::transform (const U8 block[64]){
|
||||
|
||||
uint4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
|
||||
uint32_t a = state[0], b = state[1], c = state[2], d = state[3], x[16];
|
||||
|
||||
decode (x, block, 64);
|
||||
|
||||
|
|
@ -496,38 +496,38 @@ void LLMD5::transform (const U8 block[64]){
|
|||
state[3] += d;
|
||||
|
||||
// Zeroize sensitive information.
|
||||
memset ( (uint1 *) x, 0, sizeof(x));
|
||||
memset ( (uint8_t *) x, 0, sizeof(x));
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Encodes input (UINT4) into output (unsigned char). Assumes len is
|
||||
// Encodes input (uint32_t) into output (unsigned char). Assumes len is
|
||||
// a multiple of 4.
|
||||
void LLMD5::encode (uint1 *output, const uint4 *input, const size_t len) {
|
||||
void LLMD5::encode (uint8_t *output, const uint32_t *input, const size_t len) {
|
||||
|
||||
size_t i, j;
|
||||
|
||||
for (i = 0, j = 0; j < len; i++, j += 4) {
|
||||
output[j] = (uint1) (input[i] & 0xff);
|
||||
output[j+1] = (uint1) ((input[i] >> 8) & 0xff);
|
||||
output[j+2] = (uint1) ((input[i] >> 16) & 0xff);
|
||||
output[j+3] = (uint1) ((input[i] >> 24) & 0xff);
|
||||
output[j] = (uint8_t) (input[i] & 0xff);
|
||||
output[j+1] = (uint8_t) ((input[i] >> 8) & 0xff);
|
||||
output[j+2] = (uint8_t) ((input[i] >> 16) & 0xff);
|
||||
output[j+3] = (uint8_t) ((input[i] >> 24) & 0xff);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Decodes input (unsigned char) into output (UINT4). Assumes len is
|
||||
// Decodes input (unsigned char) into output (uint32_t). Assumes len is
|
||||
// a multiple of 4.
|
||||
void LLMD5::decode (uint4 *output, const uint1 *input, const size_t len){
|
||||
void LLMD5::decode (uint32_t *output, const uint8_t *input, const size_t len){
|
||||
|
||||
size_t i, j;
|
||||
|
||||
for (i = 0, j = 0; j < len; i++, j += 4)
|
||||
output[i] = ((uint4)input[j]) | (((uint4)input[j+1]) << 8) |
|
||||
(((uint4)input[j+2]) << 16) | (((uint4)input[j+3]) << 24);
|
||||
output[i] = ((uint32_t)input[j]) | (((uint32_t)input[j+1]) << 8) |
|
||||
(((uint32_t)input[j+2]) << 16) | (((uint32_t)input[j+3]) << 24);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -67,6 +67,8 @@ documentation and/or software.
|
|||
|
||||
*/
|
||||
|
||||
#include <cstdint> // uint32_t et al.
|
||||
|
||||
// use for the raw digest output
|
||||
const int MD5RAW_BYTES = 16;
|
||||
|
||||
|
|
@ -75,18 +77,13 @@ const int MD5HEX_STR_SIZE = 33; // char hex[MD5HEX_STR_SIZE]; with null
|
|||
const int MD5HEX_STR_BYTES = 32; // message system fixed size
|
||||
|
||||
class LL_COMMON_API LLMD5 {
|
||||
// first, some types:
|
||||
typedef unsigned int uint4; // assumes integer is 4 words long
|
||||
typedef unsigned short int uint2; // assumes short integer is 2 words long
|
||||
typedef unsigned char uint1; // assumes char is 1 word long
|
||||
|
||||
// how many bytes to grab at a time when checking files
|
||||
static const int BLOCK_LEN;
|
||||
|
||||
public:
|
||||
// methods for controlled operation:
|
||||
LLMD5 (); // simple initializer
|
||||
void update (const uint1 *input, const size_t input_length);
|
||||
void update (const uint8_t *input, const size_t input_length);
|
||||
void update (std::istream& stream);
|
||||
void update (FILE *file);
|
||||
void update (const std::string& str);
|
||||
|
|
@ -109,19 +106,19 @@ private:
|
|||
|
||||
|
||||
// next, the private data:
|
||||
uint4 state[4];
|
||||
uint32_t state[4];
|
||||
uint64_t count; // number of *bits*, mod 2^64
|
||||
uint1 buffer[64]; // input buffer
|
||||
uint1 digest[16];
|
||||
uint1 finalized;
|
||||
uint8_t buffer[64]; // input buffer
|
||||
uint8_t digest[16];
|
||||
uint8_t finalized;
|
||||
|
||||
// last, the private methods, mostly static:
|
||||
void init (); // called by all constructors
|
||||
void transform (const uint1 *buffer); // does the real update work. Note
|
||||
void transform (const uint8_t *buffer); // does the real update work. Note
|
||||
// that length is implied to be 64.
|
||||
|
||||
static void encode (uint1 *dest, const uint4 *src, const size_t length);
|
||||
static void decode (uint4 *dest, const uint1 *src, const size_t length);
|
||||
static void encode (uint8_t *dest, const uint32_t *src, const size_t length);
|
||||
static void decode (uint32_t *dest, const uint8_t *src, const size_t length);
|
||||
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@
|
|||
#endif
|
||||
|
||||
#include "lldate.h"
|
||||
#include "llmemorystream.h"
|
||||
#include "llsd.h"
|
||||
#include "llstring.h"
|
||||
#include "lluri.h"
|
||||
|
|
@ -64,6 +65,23 @@ const std::string LLSD_NOTATION_HEADER("llsd/notation");
|
|||
#define windowBits 15
|
||||
#define ENABLE_ZLIB_GZIP 32
|
||||
|
||||
// If we published this in llsdserialize.h, we could use it in the
|
||||
// implementation of LLSDOStreamer's operator<<().
|
||||
template <class Formatter>
|
||||
void format_using(const LLSD& data, std::ostream& ostr,
|
||||
LLSDFormatter::EFormatterOptions options=LLSDFormatter::OPTIONS_PRETTY_BINARY)
|
||||
{
|
||||
LLPointer<Formatter> f{ new Formatter };
|
||||
f->format(data, ostr, options);
|
||||
}
|
||||
|
||||
template <class Parser>
|
||||
S32 parse_using(std::istream& istr, LLSD& data, size_t max_bytes, S32 max_depth=-1)
|
||||
{
|
||||
LLPointer<Parser> p{ new Parser };
|
||||
return p->parse(istr, data, max_bytes, max_depth);
|
||||
}
|
||||
|
||||
/**
|
||||
* LLSDSerialize
|
||||
*/
|
||||
|
|
@ -86,10 +104,10 @@ void LLSDSerialize::serialize(const LLSD& sd, std::ostream& str, ELLSD_Serialize
|
|||
f = new LLSDXMLFormatter;
|
||||
break;
|
||||
|
||||
case LLSD_NOTATION:
|
||||
str << "<? " << LLSD_NOTATION_HEADER << " ?>\n";
|
||||
f = new LLSDNotationFormatter;
|
||||
break;
|
||||
case LLSD_NOTATION:
|
||||
str << "<? " << LLSD_NOTATION_HEADER << " ?>\n";
|
||||
f = new LLSDNotationFormatter;
|
||||
break;
|
||||
|
||||
default:
|
||||
LL_WARNS() << "serialize request for unknown ELLSD_Serialize" << LL_ENDL;
|
||||
|
|
@ -104,18 +122,37 @@ void LLSDSerialize::serialize(const LLSD& sd, std::ostream& str, ELLSD_Serialize
|
|||
// static
|
||||
bool LLSDSerialize::deserialize(LLSD& sd, std::istream& str, llssize max_bytes)
|
||||
{
|
||||
LLPointer<LLSDParser> p = NULL;
|
||||
char hdr_buf[MAX_HDR_LEN + 1] = ""; /* Flawfinder: ignore */
|
||||
int i;
|
||||
int inbuf = 0;
|
||||
bool legacy_no_header = false;
|
||||
bool fail_if_not_legacy = false;
|
||||
std::string header;
|
||||
|
||||
/*
|
||||
* Get the first line before anything.
|
||||
*/
|
||||
str.get(hdr_buf, MAX_HDR_LEN, '\n');
|
||||
/*
|
||||
* Get the first line before anything. Don't read more than max_bytes:
|
||||
* this get() overload reads no more than (count-1) bytes into the
|
||||
* specified buffer. In the usual case when max_bytes exceeds
|
||||
* sizeof(hdr_buf), get() will read no more than sizeof(hdr_buf)-2.
|
||||
*/
|
||||
llssize max_hdr_read = MAX_HDR_LEN;
|
||||
if (max_bytes != LLSDSerialize::SIZE_UNLIMITED)
|
||||
{
|
||||
max_hdr_read = llmin(max_bytes + 1, max_hdr_read);
|
||||
}
|
||||
str.get(hdr_buf, max_hdr_read, '\n');
|
||||
auto inbuf = str.gcount();
|
||||
|
||||
// https://en.cppreference.com/w/cpp/io/basic_istream/get
|
||||
// When the get() above sees the specified delimiter '\n', it stops there
|
||||
// without pulling it from the stream. If it turns out that the stream
|
||||
// does NOT contain a header, and the content includes meaningful '\n',
|
||||
// it's important to pull that into hdr_buf too.
|
||||
if (inbuf < max_bytes && str.get(hdr_buf[inbuf]))
|
||||
{
|
||||
// got the delimiting '\n'
|
||||
++inbuf;
|
||||
// None of the following requires that hdr_buf contain a final '\0'
|
||||
// byte. We could store one if needed, since even the incremented
|
||||
// inbuf won't exceed sizeof(hdr_buf)-1, but there's no need.
|
||||
}
|
||||
std::string header{ hdr_buf, static_cast<std::string::size_type>(inbuf) };
|
||||
if (str.fail())
|
||||
{
|
||||
str.clear();
|
||||
|
|
@ -123,79 +160,97 @@ bool LLSDSerialize::deserialize(LLSD& sd, std::istream& str, llssize max_bytes)
|
|||
}
|
||||
|
||||
if (!strncasecmp(LEGACY_NON_HEADER, hdr_buf, strlen(LEGACY_NON_HEADER))) /* Flawfinder: ignore */
|
||||
{
|
||||
legacy_no_header = true;
|
||||
inbuf = (int)str.gcount();
|
||||
{ // Create a LLSD XML parser, and parse the first chunk read above.
|
||||
LLSDXMLParser x;
|
||||
x.parsePart(hdr_buf, inbuf); // Parse the first part that was already read
|
||||
auto parsed = x.parse(str, sd, max_bytes - inbuf); // Parse the rest of it
|
||||
// Formally we should probably check (parsed != PARSE_FAILURE &&
|
||||
// parsed > 0), but since PARSE_FAILURE is -1, this suffices.
|
||||
return (parsed > 0);
|
||||
}
|
||||
else
|
||||
|
||||
if (fail_if_not_legacy)
|
||||
{
|
||||
if (fail_if_not_legacy)
|
||||
goto fail;
|
||||
/*
|
||||
* Remove the newline chars
|
||||
*/
|
||||
for (i = 0; i < MAX_HDR_LEN; i++)
|
||||
{
|
||||
if (hdr_buf[i] == 0 || hdr_buf[i] == '\r' ||
|
||||
hdr_buf[i] == '\n')
|
||||
{
|
||||
hdr_buf[i] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
header = hdr_buf;
|
||||
LL_WARNS() << "deserialize LLSD parse failure" << LL_ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string::size_type start = std::string::npos;
|
||||
std::string::size_type end = std::string::npos;
|
||||
start = header.find_first_not_of("<? ");
|
||||
if (start != std::string::npos)
|
||||
{
|
||||
end = header.find_first_of(" ?", start);
|
||||
}
|
||||
if ((start == std::string::npos) || (end == std::string::npos))
|
||||
goto fail;
|
||||
/*
|
||||
* Remove the newline chars
|
||||
*/
|
||||
std::string::size_type lastchar = header.find_last_not_of("\r\n");
|
||||
if (lastchar != std::string::npos)
|
||||
{
|
||||
// It's important that find_last_not_of() returns size_type, which is
|
||||
// why lastchar explicitly declares the type above. erase(size_type)
|
||||
// erases from that offset to the end of the string, whereas
|
||||
// erase(iterator) erases only a single character.
|
||||
header.erase(lastchar+1);
|
||||
}
|
||||
|
||||
header = header.substr(start, end - start);
|
||||
ws(str);
|
||||
// trim off the <? ... ?> header syntax
|
||||
auto start = header.find_first_not_of("<? ");
|
||||
if (start != std::string::npos)
|
||||
{
|
||||
auto end = header.find_first_of(" ?", start);
|
||||
if (end != std::string::npos)
|
||||
{
|
||||
header = header.substr(start, end - start);
|
||||
ws(str);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Create the parser as appropriate
|
||||
*/
|
||||
if (legacy_no_header)
|
||||
{ // Create a LLSD XML parser, and parse the first chunk read above
|
||||
LLSDXMLParser* x = new LLSDXMLParser();
|
||||
x->parsePart(hdr_buf, inbuf); // Parse the first part that was already read
|
||||
x->parseLines(str, sd); // Parse the rest of it
|
||||
delete x;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (header == LLSD_BINARY_HEADER)
|
||||
if (0 == LLStringUtil::compareInsensitive(header, LLSD_BINARY_HEADER))
|
||||
{
|
||||
p = new LLSDBinaryParser;
|
||||
return (parse_using<LLSDBinaryParser>(str, sd, max_bytes-inbuf) > 0);
|
||||
}
|
||||
else if (header == LLSD_XML_HEADER)
|
||||
else if (0 == LLStringUtil::compareInsensitive(header, LLSD_XML_HEADER))
|
||||
{
|
||||
p = new LLSDXMLParser;
|
||||
return (parse_using<LLSDXMLParser>(str, sd, max_bytes-inbuf) > 0);
|
||||
}
|
||||
else if (header == LLSD_NOTATION_HEADER)
|
||||
else if (0 == LLStringUtil::compareInsensitive(header, LLSD_NOTATION_HEADER))
|
||||
{
|
||||
p = new LLSDNotationParser;
|
||||
return (parse_using<LLSDNotationParser>(str, sd, max_bytes-inbuf) > 0);
|
||||
}
|
||||
else
|
||||
else // no header we recognize
|
||||
{
|
||||
LL_WARNS() << "deserialize request for unknown ELLSD_Serialize" << LL_ENDL;
|
||||
LLPointer<LLSDParser> p;
|
||||
if (inbuf && hdr_buf[0] == '<')
|
||||
{
|
||||
// looks like XML
|
||||
LL_DEBUGS() << "deserialize request with no header, assuming XML" << LL_ENDL;
|
||||
p = new LLSDXMLParser;
|
||||
}
|
||||
else
|
||||
{
|
||||
// assume notation
|
||||
LL_DEBUGS() << "deserialize request with no header, assuming notation" << LL_ENDL;
|
||||
p = new LLSDNotationParser;
|
||||
}
|
||||
// Since we've already read 'inbuf' bytes into 'hdr_buf', prepend that
|
||||
// data to whatever remains in 'str'.
|
||||
LLMemoryStreamBuf already(reinterpret_cast<const U8*>(hdr_buf), inbuf);
|
||||
cat_streambuf prebuff(&already, str.rdbuf());
|
||||
std::istream prepend(&prebuff);
|
||||
#if 1
|
||||
return (p->parse(prepend, sd, max_bytes) > 0);
|
||||
#else
|
||||
// debugging the reconstituted 'prepend' stream
|
||||
// allocate a buffer that we hope is big enough for the whole thing
|
||||
std::vector<char> wholemsg((max_bytes == size_t(SIZE_UNLIMITED))? 1024 : max_bytes);
|
||||
prepend.read(wholemsg.data(), std::min(max_bytes, wholemsg.size()));
|
||||
LLMemoryStream replay(reinterpret_cast<const U8*>(wholemsg.data()), prepend.gcount());
|
||||
auto success{ p->parse(replay, sd, prepend.gcount()) > 0 };
|
||||
{
|
||||
LL_DEBUGS() << (success? "parsed: $$" : "failed: '")
|
||||
<< std::string(wholemsg.data(), llmin(prepend.gcount(), 100)) << "$$"
|
||||
<< LL_ENDL;
|
||||
}
|
||||
return success;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (p.notNull())
|
||||
{
|
||||
p->parse(str, sd, max_bytes);
|
||||
return true;
|
||||
}
|
||||
|
||||
fail:
|
||||
LL_WARNS() << "deserialize LLSD parse failure" << LL_ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2193,9 +2248,9 @@ LLUZipHelper::EZipRresult LLUZipHelper::unzip_llsd(LLSD& data, std::istream& is,
|
|||
LLUZipHelper::EZipRresult LLUZipHelper::unzip_llsd(LLSD& data, const U8* in, S32 size)
|
||||
{
|
||||
U8* result = NULL;
|
||||
U32 cur_size = 0;
|
||||
llssize cur_size = 0;
|
||||
z_stream strm;
|
||||
|
||||
|
||||
constexpr U32 CHUNK = 1024 * 512;
|
||||
|
||||
static thread_local std::unique_ptr<U8[]> out;
|
||||
|
|
@ -2388,7 +2443,7 @@ U8* unzip_llsdNavMesh( bool& valid, size_t& outsize, std::istream& is, S32 size
|
|||
return result;
|
||||
}
|
||||
|
||||
char* strip_deprecated_header(char* in, U32& cur_size, U32* header_size)
|
||||
char* strip_deprecated_header(char* in, llssize& cur_size, llssize* header_size)
|
||||
{
|
||||
const char* deprecated_header = "<? LLSD/Binary ?>";
|
||||
constexpr size_t deprecated_header_size = 17;
|
||||
|
|
|
|||
|
|
@ -873,5 +873,5 @@ LL_COMMON_API std::string zip_llsd(LLSD& data);
|
|||
LL_COMMON_API U8* unzip_llsdNavMesh( bool& valid, size_t& outsize,std::istream& is, S32 size);
|
||||
|
||||
// returns a pointer to the array or past the array if the deprecated header exists
|
||||
LL_COMMON_API char* strip_deprecated_header(char* in, U32& cur_size, U32* header_size = nullptr);
|
||||
LL_COMMON_API char* strip_deprecated_header(char* in, llssize& cur_size, llssize* header_size = nullptr);
|
||||
#endif // LL_LLSDSERIALIZE_H
|
||||
|
|
|
|||
|
|
@ -513,3 +513,29 @@ std::istream& operator>>(std::istream& str, const char *tocheck)
|
|||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
int cat_streambuf::underflow()
|
||||
{
|
||||
if (gptr() == egptr())
|
||||
{
|
||||
// here because our buffer is empty
|
||||
std::streamsize size = 0;
|
||||
// Until we've run out of mInputs, try reading the first of them
|
||||
// into mBuffer. If that fetches some characters, break the loop.
|
||||
while (! mInputs.empty()
|
||||
&& ! (size = mInputs.front()->sgetn(mBuffer.data(), mBuffer.size())))
|
||||
{
|
||||
// We tried to read mInputs.front() but got zero characters.
|
||||
// Discard the first streambuf and try the next one.
|
||||
mInputs.pop_front();
|
||||
}
|
||||
// Either we ran out of mInputs or we succeeded in reading some
|
||||
// characters, that is, size != 0. Tell base class what we have.
|
||||
setg(mBuffer.data(), mBuffer.data(), mBuffer.data() + size);
|
||||
}
|
||||
// If we fell out of the above loop with mBuffer still empty, return
|
||||
// eof(), otherwise return the next character.
|
||||
return (gptr() == egptr())
|
||||
? std::char_traits<char>::eof()
|
||||
: std::char_traits<char>::to_int_type(*gptr());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,8 +27,10 @@
|
|||
#ifndef LL_STREAM_TOOLS_H
|
||||
#define LL_STREAM_TOOLS_H
|
||||
|
||||
#include <deque>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// unless specifed otherwise these all return input_stream.good()
|
||||
|
||||
|
|
@ -113,6 +115,27 @@ LL_COMMON_API std::streamsize fullread(
|
|||
|
||||
LL_COMMON_API std::istream& operator>>(std::istream& str, const char *tocheck);
|
||||
|
||||
/**
|
||||
* cat_streambuf is a std::streambuf subclass that accepts a variadic number
|
||||
* of std::streambuf* (e.g. some_istream.rdbuf()) and virtually concatenates
|
||||
* their contents.
|
||||
*/
|
||||
// derived from https://stackoverflow.com/a/49441066/5533635
|
||||
class cat_streambuf: public std::streambuf
|
||||
{
|
||||
private:
|
||||
std::deque<std::streambuf*> mInputs;
|
||||
std::vector<char> mBuffer;
|
||||
|
||||
public:
|
||||
// only valid for std::streambuf* arguments
|
||||
template <typename... Inputs>
|
||||
cat_streambuf(Inputs... inputs):
|
||||
mInputs{inputs...},
|
||||
mBuffer(1024)
|
||||
{}
|
||||
|
||||
int underflow() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -577,10 +577,12 @@ S32 Recording::getSampleCount( const StatType<EventAccumulator>& stat )
|
|||
// PeriodicRecording
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
|
||||
PeriodicRecording::PeriodicRecording( S32 num_periods, EPlayState state)
|
||||
PeriodicRecording::PeriodicRecording( size_t num_periods, EPlayState state)
|
||||
: mAutoResize(num_periods == 0),
|
||||
mCurPeriod(0),
|
||||
mNumRecordedPeriods(0),
|
||||
// This guarantee that mRecordingPeriods cannot be empty is essential for
|
||||
// code in several methods.
|
||||
mRecordingPeriods(num_periods ? num_periods : 1)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
|
|
@ -596,18 +598,19 @@ PeriodicRecording::~PeriodicRecording()
|
|||
|
||||
void PeriodicRecording::nextPeriod()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
if (mAutoResize)
|
||||
{
|
||||
mRecordingPeriods.push_back(Recording());
|
||||
}
|
||||
|
||||
Recording& old_recording = getCurRecording();
|
||||
mCurPeriod = (mCurPeriod + 1) % mRecordingPeriods.size();
|
||||
inci(mCurPeriod);
|
||||
old_recording.splitTo(getCurRecording());
|
||||
|
||||
mNumRecordedPeriods = mRecordingPeriods.empty()? 0 :
|
||||
llmin(mRecordingPeriods.size() - 1, mNumRecordedPeriods + 1);
|
||||
// Since mRecordingPeriods always has at least one entry, we can always
|
||||
// safely subtract 1 from its size().
|
||||
mNumRecordedPeriods = llmin(mRecordingPeriods.size() - 1, mNumRecordedPeriods + 1);
|
||||
}
|
||||
|
||||
void PeriodicRecording::appendRecording(Recording& recording)
|
||||
|
|
@ -620,31 +623,29 @@ void PeriodicRecording::appendRecording(Recording& recording)
|
|||
|
||||
void PeriodicRecording::appendPeriodicRecording( PeriodicRecording& other )
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
if (other.mRecordingPeriods.empty()) return;
|
||||
|
||||
getCurRecording().update();
|
||||
other.getCurRecording().update();
|
||||
|
||||
const auto other_recording_slots = other.mRecordingPeriods.size();
|
||||
|
||||
const auto other_num_recordings = other.getNumRecordedPeriods();
|
||||
const auto other_current_recording_index = other.mCurPeriod;
|
||||
const auto other_oldest_recording_index = (other_current_recording_index + other_recording_slots - other_num_recordings) % other_recording_slots;
|
||||
const auto other_oldest_recording_index = other.previ(other_current_recording_index, other_num_recordings);
|
||||
|
||||
// append first recording into our current slot
|
||||
getCurRecording().appendRecording(other.mRecordingPeriods[other_oldest_recording_index]);
|
||||
|
||||
// from now on, add new recordings for everything after the first
|
||||
auto other_index = (other_oldest_recording_index + 1) % other_recording_slots;
|
||||
auto other_index = other.nexti(other_oldest_recording_index);
|
||||
|
||||
if (mAutoResize)
|
||||
{
|
||||
// push back recordings for everything in the middle
|
||||
auto other_index = (other_oldest_recording_index + 1) % other_recording_slots;
|
||||
while (other_index != other_current_recording_index)
|
||||
{
|
||||
mRecordingPeriods.push_back(other.mRecordingPeriods[other_index]);
|
||||
other_index = (other_index + 1) % other_recording_slots;
|
||||
other.inci(other_index);
|
||||
}
|
||||
|
||||
// add final recording, if it wasn't already added as the first
|
||||
|
|
@ -653,36 +654,25 @@ void PeriodicRecording::appendPeriodicRecording( PeriodicRecording& other )
|
|||
mRecordingPeriods.push_back(other.mRecordingPeriods[other_current_recording_index]);
|
||||
}
|
||||
|
||||
mCurPeriod = mRecordingPeriods.empty()? 0 : mRecordingPeriods.size() - 1;
|
||||
// mRecordingPeriods is never empty()
|
||||
mCurPeriod = mRecordingPeriods.size() - 1;
|
||||
mNumRecordedPeriods = mCurPeriod;
|
||||
}
|
||||
else
|
||||
{
|
||||
S32 num_to_copy = llmin((S32)mRecordingPeriods.size(), (S32)other_num_recordings);
|
||||
|
||||
std::vector<Recording>::iterator src_it = other.mRecordingPeriods.begin() + other_index ;
|
||||
std::vector<Recording>::iterator dest_it = mRecordingPeriods.begin() + mCurPeriod;
|
||||
|
||||
auto num_to_copy = llmin(mRecordingPeriods.size(), other_num_recordings);
|
||||
// already consumed the first recording from other, so start counting at 1
|
||||
for(S32 i = 1; i < num_to_copy; i++)
|
||||
for (size_t n = 1, srci = other_index, dsti = mCurPeriod;
|
||||
n < num_to_copy;
|
||||
++n, other.inci(srci), inci(dsti))
|
||||
{
|
||||
*dest_it = *src_it;
|
||||
|
||||
if (++src_it == other.mRecordingPeriods.end())
|
||||
{
|
||||
src_it = other.mRecordingPeriods.begin();
|
||||
}
|
||||
|
||||
if (++dest_it == mRecordingPeriods.end())
|
||||
{
|
||||
dest_it = mRecordingPeriods.begin();
|
||||
}
|
||||
mRecordingPeriods[dsti] = other.mRecordingPeriods[srci];
|
||||
}
|
||||
|
||||
|
||||
// want argument to % to be positive, otherwise result could be negative and thus out of bounds
|
||||
llassert(num_to_copy >= 1);
|
||||
// advance to last recording period copied, and make that our current period
|
||||
mCurPeriod = (mCurPeriod + num_to_copy - 1) % mRecordingPeriods.size();
|
||||
inci(mCurPeriod, num_to_copy - 1);
|
||||
mNumRecordedPeriods = llmin(mRecordingPeriods.size() - 1, mNumRecordedPeriods + num_to_copy - 1);
|
||||
}
|
||||
|
||||
|
|
@ -694,13 +684,11 @@ void PeriodicRecording::appendPeriodicRecording( PeriodicRecording& other )
|
|||
|
||||
F64Seconds PeriodicRecording::getDuration() const
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
F64Seconds duration;
|
||||
auto num_periods = mRecordingPeriods.size();
|
||||
for (size_t i = 1; i <= num_periods; i++)
|
||||
for (size_t n = 0; n < mRecordingPeriods.size(); ++n)
|
||||
{
|
||||
auto index = (mCurPeriod + num_periods - i) % num_periods;
|
||||
duration += mRecordingPeriods[index].getDuration();
|
||||
duration += mRecordingPeriods[nexti(mCurPeriod, n)].getDuration();
|
||||
}
|
||||
return duration;
|
||||
}
|
||||
|
|
@ -737,16 +725,14 @@ const Recording& PeriodicRecording::getCurRecording() const
|
|||
|
||||
Recording& PeriodicRecording::getPrevRecording( size_t offset )
|
||||
{
|
||||
auto num_periods = mRecordingPeriods.size();
|
||||
offset = llclamp(offset, 0, num_periods - 1);
|
||||
return mRecordingPeriods[(mCurPeriod + num_periods - offset) % num_periods];
|
||||
// reuse const implementation, but return non-const reference
|
||||
return const_cast<Recording&>(
|
||||
const_cast<const PeriodicRecording*>(this)->getPrevRecording(offset));
|
||||
}
|
||||
|
||||
const Recording& PeriodicRecording::getPrevRecording( size_t offset ) const
|
||||
{
|
||||
auto num_periods = mRecordingPeriods.size();
|
||||
offset = llclamp(offset, 0, num_periods - 1);
|
||||
return mRecordingPeriods[(mCurPeriod + num_periods - offset) % num_periods];
|
||||
return mRecordingPeriods[previ(mCurPeriod, offset)];
|
||||
}
|
||||
|
||||
void PeriodicRecording::handleStart()
|
||||
|
|
@ -789,14 +775,14 @@ void PeriodicRecording::handleSplitTo(PeriodicRecording& other)
|
|||
getCurRecording().splitTo(other.getCurRecording());
|
||||
}
|
||||
|
||||
F64 PeriodicRecording::getPeriodMin( const StatType<EventAccumulator>& stat, size_t num_periods /*= S32_MAX*/ )
|
||||
F64 PeriodicRecording::getPeriodMin( const StatType<EventAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/ )
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
num_periods = llmin(num_periods, getNumRecordedPeriods());
|
||||
|
||||
bool has_value = false;
|
||||
F64 min_val = std::numeric_limits<F64>::max();
|
||||
for (S32 i = 1; i <= num_periods; i++)
|
||||
for (size_t i = 1; i <= num_periods; i++)
|
||||
{
|
||||
Recording& recording = getPrevRecording(i);
|
||||
if (recording.hasValue(stat))
|
||||
|
|
@ -811,14 +797,14 @@ F64 PeriodicRecording::getPeriodMin( const StatType<EventAccumulator>& stat, siz
|
|||
: NaN;
|
||||
}
|
||||
|
||||
F64 PeriodicRecording::getPeriodMax( const StatType<EventAccumulator>& stat, size_t num_periods /*= S32_MAX*/ )
|
||||
F64 PeriodicRecording::getPeriodMax( const StatType<EventAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/ )
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
num_periods = llmin(num_periods, getNumRecordedPeriods());
|
||||
|
||||
bool has_value = false;
|
||||
F64 max_val = std::numeric_limits<F64>::min();
|
||||
for (S32 i = 1; i <= num_periods; i++)
|
||||
for (size_t i = 1; i <= num_periods; i++)
|
||||
{
|
||||
Recording& recording = getPrevRecording(i);
|
||||
if (recording.hasValue(stat))
|
||||
|
|
@ -834,7 +820,7 @@ F64 PeriodicRecording::getPeriodMax( const StatType<EventAccumulator>& stat, siz
|
|||
}
|
||||
|
||||
// calculates means using aggregates per period
|
||||
F64 PeriodicRecording::getPeriodMean( const StatType<EventAccumulator>& stat, size_t num_periods /*= S32_MAX*/ )
|
||||
F64 PeriodicRecording::getPeriodMean( const StatType<EventAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/ )
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
num_periods = llmin(num_periods, getNumRecordedPeriods());
|
||||
|
|
@ -842,7 +828,7 @@ F64 PeriodicRecording::getPeriodMean( const StatType<EventAccumulator>& stat, si
|
|||
F64 mean = 0;
|
||||
S32 valid_period_count = 0;
|
||||
|
||||
for (S32 i = 1; i <= num_periods; i++)
|
||||
for (size_t i = 1; i <= num_periods; i++)
|
||||
{
|
||||
Recording& recording = getPrevRecording(i);
|
||||
if (recording.hasValue(stat))
|
||||
|
|
@ -857,7 +843,7 @@ F64 PeriodicRecording::getPeriodMean( const StatType<EventAccumulator>& stat, si
|
|||
: NaN;
|
||||
}
|
||||
|
||||
F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<EventAccumulator>& stat, size_t num_periods /*= S32_MAX*/ )
|
||||
F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<EventAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/ )
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
num_periods = llmin(num_periods, getNumRecordedPeriods());
|
||||
|
|
@ -866,7 +852,7 @@ F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<EventAccumulat
|
|||
F64 sum_of_squares = 0;
|
||||
S32 valid_period_count = 0;
|
||||
|
||||
for (S32 i = 1; i <= num_periods; i++)
|
||||
for (size_t i = 1; i <= num_periods; i++)
|
||||
{
|
||||
Recording& recording = getPrevRecording(i);
|
||||
if (recording.hasValue(stat))
|
||||
|
|
@ -882,14 +868,14 @@ F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<EventAccumulat
|
|||
: NaN;
|
||||
}
|
||||
|
||||
F64 PeriodicRecording::getPeriodMin( const StatType<SampleAccumulator>& stat, size_t num_periods /*= S32_MAX*/ )
|
||||
F64 PeriodicRecording::getPeriodMin( const StatType<SampleAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/ )
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
num_periods = llmin(num_periods, getNumRecordedPeriods());
|
||||
|
||||
bool has_value = false;
|
||||
F64 min_val = std::numeric_limits<F64>::max();
|
||||
for (S32 i = 1; i <= num_periods; i++)
|
||||
for (size_t i = 1; i <= num_periods; i++)
|
||||
{
|
||||
Recording& recording = getPrevRecording(i);
|
||||
if (recording.hasValue(stat))
|
||||
|
|
@ -904,14 +890,14 @@ F64 PeriodicRecording::getPeriodMin( const StatType<SampleAccumulator>& stat, si
|
|||
: NaN;
|
||||
}
|
||||
|
||||
F64 PeriodicRecording::getPeriodMax(const StatType<SampleAccumulator>& stat, size_t num_periods /*= S32_MAX*/)
|
||||
F64 PeriodicRecording::getPeriodMax(const StatType<SampleAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
num_periods = llmin(num_periods, getNumRecordedPeriods());
|
||||
|
||||
bool has_value = false;
|
||||
F64 max_val = std::numeric_limits<F64>::min();
|
||||
for (S32 i = 1; i <= num_periods; i++)
|
||||
for (size_t i = 1; i <= num_periods; i++)
|
||||
{
|
||||
Recording& recording = getPrevRecording(i);
|
||||
if (recording.hasValue(stat))
|
||||
|
|
@ -927,7 +913,7 @@ F64 PeriodicRecording::getPeriodMax(const StatType<SampleAccumulator>& stat, siz
|
|||
}
|
||||
|
||||
|
||||
F64 PeriodicRecording::getPeriodMean( const StatType<SampleAccumulator>& stat, size_t num_periods /*= S32_MAX*/ )
|
||||
F64 PeriodicRecording::getPeriodMean( const StatType<SampleAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/ )
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
num_periods = llmin(num_periods, getNumRecordedPeriods());
|
||||
|
|
@ -935,7 +921,7 @@ F64 PeriodicRecording::getPeriodMean( const StatType<SampleAccumulator>& stat, s
|
|||
S32 valid_period_count = 0;
|
||||
F64 mean = 0;
|
||||
|
||||
for (S32 i = 1; i <= num_periods; i++)
|
||||
for (size_t i = 1; i <= num_periods; i++)
|
||||
{
|
||||
Recording& recording = getPrevRecording(i);
|
||||
if (recording.hasValue(stat))
|
||||
|
|
@ -950,13 +936,13 @@ F64 PeriodicRecording::getPeriodMean( const StatType<SampleAccumulator>& stat, s
|
|||
: NaN;
|
||||
}
|
||||
|
||||
F64 PeriodicRecording::getPeriodMedian( const StatType<SampleAccumulator>& stat, size_t num_periods /*= S32_MAX*/ )
|
||||
F64 PeriodicRecording::getPeriodMedian( const StatType<SampleAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/ )
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
num_periods = llmin(num_periods, getNumRecordedPeriods());
|
||||
|
||||
std::vector<F64> buf;
|
||||
for (S32 i = 1; i <= num_periods; i++)
|
||||
for (size_t i = 1; i <= num_periods; i++)
|
||||
{
|
||||
Recording& recording = getPrevRecording(i);
|
||||
if (recording.getDuration() > (F32Seconds)0.f)
|
||||
|
|
@ -976,7 +962,7 @@ F64 PeriodicRecording::getPeriodMedian( const StatType<SampleAccumulator>& stat,
|
|||
return F64((buf.size() % 2 == 0) ? (buf[buf.size() / 2 - 1] + buf[buf.size() / 2]) / 2 : buf[buf.size() / 2]);
|
||||
}
|
||||
|
||||
F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<SampleAccumulator>& stat, size_t num_periods /*= S32_MAX*/ )
|
||||
F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<SampleAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/ )
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
num_periods = llmin(num_periods, getNumRecordedPeriods());
|
||||
|
|
@ -985,7 +971,7 @@ F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<SampleAccumula
|
|||
S32 valid_period_count = 0;
|
||||
F64 sum_of_squares = 0;
|
||||
|
||||
for (S32 i = 1; i <= num_periods; i++)
|
||||
for (size_t i = 1; i <= num_periods; i++)
|
||||
{
|
||||
Recording& recording = getPrevRecording(i);
|
||||
if (recording.hasValue(stat))
|
||||
|
|
@ -1002,13 +988,13 @@ F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<SampleAccumula
|
|||
}
|
||||
|
||||
|
||||
F64Kilobytes PeriodicRecording::getPeriodMin( const StatType<MemAccumulator>& stat, size_t num_periods /*= S32_MAX*/ )
|
||||
F64Kilobytes PeriodicRecording::getPeriodMin( const StatType<MemAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/ )
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
num_periods = llmin(num_periods, getNumRecordedPeriods());
|
||||
|
||||
F64Kilobytes min_val(std::numeric_limits<F64>::max());
|
||||
for (S32 i = 1; i <= num_periods; i++)
|
||||
for (size_t i = 1; i <= num_periods; i++)
|
||||
{
|
||||
Recording& recording = getPrevRecording(i);
|
||||
min_val = llmin(min_val, recording.getMin(stat));
|
||||
|
|
@ -1022,13 +1008,13 @@ F64Kilobytes PeriodicRecording::getPeriodMin(const MemStatHandle& stat, size_t n
|
|||
return getPeriodMin(static_cast<const StatType<MemAccumulator>&>(stat), num_periods);
|
||||
}
|
||||
|
||||
F64Kilobytes PeriodicRecording::getPeriodMax(const StatType<MemAccumulator>& stat, size_t num_periods /*= S32_MAX*/)
|
||||
F64Kilobytes PeriodicRecording::getPeriodMax(const StatType<MemAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
num_periods = llmin(num_periods, getNumRecordedPeriods());
|
||||
|
||||
F64Kilobytes max_val(0.0);
|
||||
for (S32 i = 1; i <= num_periods; i++)
|
||||
for (size_t i = 1; i <= num_periods; i++)
|
||||
{
|
||||
Recording& recording = getPrevRecording(i);
|
||||
max_val = llmax(max_val, recording.getMax(stat));
|
||||
|
|
@ -1042,14 +1028,14 @@ F64Kilobytes PeriodicRecording::getPeriodMax(const MemStatHandle& stat, size_t n
|
|||
return getPeriodMax(static_cast<const StatType<MemAccumulator>&>(stat), num_periods);
|
||||
}
|
||||
|
||||
F64Kilobytes PeriodicRecording::getPeriodMean( const StatType<MemAccumulator>& stat, size_t num_periods /*= S32_MAX*/ )
|
||||
F64Kilobytes PeriodicRecording::getPeriodMean( const StatType<MemAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/ )
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
num_periods = llmin(num_periods, getNumRecordedPeriods());
|
||||
|
||||
F64Kilobytes mean(0);
|
||||
|
||||
for (S32 i = 1; i <= num_periods; i++)
|
||||
for (size_t i = 1; i <= num_periods; i++)
|
||||
{
|
||||
Recording& recording = getPrevRecording(i);
|
||||
mean += recording.getMean(stat);
|
||||
|
|
@ -1063,7 +1049,7 @@ F64Kilobytes PeriodicRecording::getPeriodMean(const MemStatHandle& stat, size_t
|
|||
return getPeriodMean(static_cast<const StatType<MemAccumulator>&>(stat), num_periods);
|
||||
}
|
||||
|
||||
F64Kilobytes PeriodicRecording::getPeriodStandardDeviation( const StatType<MemAccumulator>& stat, size_t num_periods /*= S32_MAX*/ )
|
||||
F64Kilobytes PeriodicRecording::getPeriodStandardDeviation( const StatType<MemAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/ )
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
num_periods = llmin(num_periods, getNumRecordedPeriods());
|
||||
|
|
@ -1072,7 +1058,7 @@ F64Kilobytes PeriodicRecording::getPeriodStandardDeviation( const StatType<MemAc
|
|||
S32 valid_period_count = 0;
|
||||
F64 sum_of_squares = 0;
|
||||
|
||||
for (S32 i = 1; i <= num_periods; i++)
|
||||
for (size_t i = 1; i <= num_periods; i++)
|
||||
{
|
||||
Recording& recording = getPrevRecording(i);
|
||||
if (recording.hasValue(stat))
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
#include "lltimer.h"
|
||||
#include "lltraceaccumulators.h"
|
||||
#include "llpointer.h"
|
||||
#include <limits>
|
||||
|
||||
class LLStopWatchControlsMixinCommon
|
||||
{
|
||||
|
|
@ -330,7 +331,7 @@ namespace LLTrace
|
|||
: public LLStopWatchControlsMixin<PeriodicRecording>
|
||||
{
|
||||
public:
|
||||
PeriodicRecording(S32 num_periods, EPlayState state = STOPPED);
|
||||
PeriodicRecording(size_t num_periods, EPlayState state = STOPPED);
|
||||
~PeriodicRecording();
|
||||
|
||||
void nextPeriod();
|
||||
|
|
@ -353,7 +354,7 @@ namespace LLTrace
|
|||
Recording snapshotCurRecording() const;
|
||||
|
||||
template <typename T>
|
||||
auto getSampleCount(const StatType<T>& stat, size_t num_periods = S32_MAX)
|
||||
auto getSampleCount(const StatType<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
num_periods = llmin(num_periods, getNumRecordedPeriods());
|
||||
|
|
@ -373,14 +374,14 @@ namespace LLTrace
|
|||
|
||||
// catch all for stats that have a defined sum
|
||||
template <typename T>
|
||||
typename T::value_t getPeriodMin(const StatType<T>& stat, size_t num_periods = S32_MAX)
|
||||
typename T::value_t getPeriodMin(const StatType<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
num_periods = llmin(num_periods, getNumRecordedPeriods());
|
||||
|
||||
bool has_value = false;
|
||||
typename T::value_t min_val(std::numeric_limits<typename T::value_t>::max());
|
||||
for (S32 i = 1; i <= num_periods; i++)
|
||||
for (size_t i = 1; i <= num_periods; i++)
|
||||
{
|
||||
Recording& recording = getPrevRecording(i);
|
||||
if (recording.hasValue(stat))
|
||||
|
|
@ -396,39 +397,39 @@ namespace LLTrace
|
|||
}
|
||||
|
||||
template<typename T>
|
||||
T getPeriodMin(const CountStatHandle<T>& stat, size_t num_periods = S32_MAX)
|
||||
T getPeriodMin(const CountStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
return T(getPeriodMin(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
|
||||
}
|
||||
|
||||
F64 getPeriodMin(const StatType<SampleAccumulator>& stat, size_t num_periods = S32_MAX);
|
||||
F64 getPeriodMin(const StatType<SampleAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max());
|
||||
template<typename T>
|
||||
T getPeriodMin(const SampleStatHandle<T>& stat, size_t num_periods = S32_MAX)
|
||||
T getPeriodMin(const SampleStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
return T(getPeriodMin(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods));
|
||||
}
|
||||
|
||||
F64 getPeriodMin(const StatType<EventAccumulator>& stat, size_t num_periods = S32_MAX);
|
||||
F64 getPeriodMin(const StatType<EventAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max());
|
||||
template<typename T>
|
||||
T getPeriodMin(const EventStatHandle<T>& stat, size_t num_periods = S32_MAX)
|
||||
T getPeriodMin(const EventStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
return T(getPeriodMin(static_cast<const StatType<EventAccumulator>&>(stat), num_periods));
|
||||
}
|
||||
|
||||
F64Kilobytes getPeriodMin(const StatType<MemAccumulator>& stat, size_t num_periods = S32_MAX);
|
||||
F64Kilobytes getPeriodMin(const MemStatHandle& stat, size_t num_periods = S32_MAX);
|
||||
F64Kilobytes getPeriodMin(const StatType<MemAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max());
|
||||
F64Kilobytes getPeriodMin(const MemStatHandle& stat, size_t num_periods = std::numeric_limits<size_t>::max());
|
||||
|
||||
template <typename T>
|
||||
typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMinPerSec(const StatType<T>& stat, size_t num_periods = S32_MAX)
|
||||
typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMinPerSec(const StatType<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
num_periods = llmin(num_periods, getNumRecordedPeriods());
|
||||
|
||||
typename RelatedTypes<typename T::value_t>::fractional_t min_val(std::numeric_limits<F64>::max());
|
||||
for (S32 i = 1; i <= num_periods; i++)
|
||||
for (size_t i = 1; i <= num_periods; i++)
|
||||
{
|
||||
Recording& recording = getPrevRecording(i);
|
||||
min_val = llmin(min_val, recording.getPerSec(stat));
|
||||
|
|
@ -437,7 +438,7 @@ namespace LLTrace
|
|||
}
|
||||
|
||||
template<typename T>
|
||||
typename RelatedTypes<T>::fractional_t getPeriodMinPerSec(const CountStatHandle<T>& stat, size_t num_periods = S32_MAX)
|
||||
typename RelatedTypes<T>::fractional_t getPeriodMinPerSec(const CountStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
return typename RelatedTypes<T>::fractional_t(getPeriodMinPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
|
||||
|
|
@ -449,14 +450,14 @@ namespace LLTrace
|
|||
|
||||
// catch all for stats that have a defined sum
|
||||
template <typename T>
|
||||
typename T::value_t getPeriodMax(const StatType<T>& stat, size_t num_periods = S32_MAX)
|
||||
typename T::value_t getPeriodMax(const StatType<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
num_periods = llmin(num_periods, getNumRecordedPeriods());
|
||||
|
||||
bool has_value = false;
|
||||
typename T::value_t max_val(std::numeric_limits<typename T::value_t>::min());
|
||||
for (S32 i = 1; i <= num_periods; i++)
|
||||
for (size_t i = 1; i <= num_periods; i++)
|
||||
{
|
||||
Recording& recording = getPrevRecording(i);
|
||||
if (recording.hasValue(stat))
|
||||
|
|
@ -472,39 +473,39 @@ namespace LLTrace
|
|||
}
|
||||
|
||||
template<typename T>
|
||||
T getPeriodMax(const CountStatHandle<T>& stat, size_t num_periods = S32_MAX)
|
||||
T getPeriodMax(const CountStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
return T(getPeriodMax(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
|
||||
}
|
||||
|
||||
F64 getPeriodMax(const StatType<SampleAccumulator>& stat, size_t num_periods = S32_MAX);
|
||||
F64 getPeriodMax(const StatType<SampleAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max());
|
||||
template<typename T>
|
||||
T getPeriodMax(const SampleStatHandle<T>& stat, size_t num_periods = S32_MAX)
|
||||
T getPeriodMax(const SampleStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
return T(getPeriodMax(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods));
|
||||
}
|
||||
|
||||
F64 getPeriodMax(const StatType<EventAccumulator>& stat, size_t num_periods = S32_MAX);
|
||||
F64 getPeriodMax(const StatType<EventAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max());
|
||||
template<typename T>
|
||||
T getPeriodMax(const EventStatHandle<T>& stat, size_t num_periods = S32_MAX)
|
||||
T getPeriodMax(const EventStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
return T(getPeriodMax(static_cast<const StatType<EventAccumulator>&>(stat), num_periods));
|
||||
}
|
||||
|
||||
F64Kilobytes getPeriodMax(const StatType<MemAccumulator>& stat, size_t num_periods = S32_MAX);
|
||||
F64Kilobytes getPeriodMax(const MemStatHandle& stat, size_t num_periods = S32_MAX);
|
||||
F64Kilobytes getPeriodMax(const StatType<MemAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max());
|
||||
F64Kilobytes getPeriodMax(const MemStatHandle& stat, size_t num_periods = std::numeric_limits<size_t>::max());
|
||||
|
||||
template <typename T>
|
||||
typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMaxPerSec(const StatType<T>& stat, size_t num_periods = S32_MAX)
|
||||
typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMaxPerSec(const StatType<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
num_periods = llmin(num_periods, getNumRecordedPeriods());
|
||||
|
||||
F64 max_val = std::numeric_limits<F64>::min();
|
||||
for (S32 i = 1; i <= num_periods; i++)
|
||||
for (size_t i = 1; i <= num_periods; i++)
|
||||
{
|
||||
Recording& recording = getPrevRecording(i);
|
||||
max_val = llmax(max_val, recording.getPerSec(stat));
|
||||
|
|
@ -513,7 +514,7 @@ namespace LLTrace
|
|||
}
|
||||
|
||||
template<typename T>
|
||||
typename RelatedTypes<T>::fractional_t getPeriodMaxPerSec(const CountStatHandle<T>& stat, size_t num_periods = S32_MAX)
|
||||
typename RelatedTypes<T>::fractional_t getPeriodMaxPerSec(const CountStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
return typename RelatedTypes<T>::fractional_t(getPeriodMaxPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
|
||||
|
|
@ -525,14 +526,14 @@ namespace LLTrace
|
|||
|
||||
// catch all for stats that have a defined sum
|
||||
template <typename T>
|
||||
typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMean(const StatType<T >& stat, size_t num_periods = S32_MAX)
|
||||
typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMean(const StatType<T >& stat, size_t num_periods = std::numeric_limits<size_t>::max())
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
num_periods = llmin(num_periods, getNumRecordedPeriods());
|
||||
|
||||
typename RelatedTypes<typename T::value_t>::fractional_t mean(0);
|
||||
|
||||
for (S32 i = 1; i <= num_periods; i++)
|
||||
for (size_t i = 1; i <= num_periods; i++)
|
||||
{
|
||||
Recording& recording = getPrevRecording(i);
|
||||
if (recording.getDuration() > (F32Seconds)0.f)
|
||||
|
|
@ -546,39 +547,39 @@ namespace LLTrace
|
|||
}
|
||||
|
||||
template<typename T>
|
||||
typename RelatedTypes<T>::fractional_t getPeriodMean(const CountStatHandle<T>& stat, size_t num_periods = S32_MAX)
|
||||
typename RelatedTypes<T>::fractional_t getPeriodMean(const CountStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
return typename RelatedTypes<T>::fractional_t(getPeriodMean(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
|
||||
}
|
||||
F64 getPeriodMean(const StatType<SampleAccumulator>& stat, size_t num_periods = S32_MAX);
|
||||
F64 getPeriodMean(const StatType<SampleAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max());
|
||||
template<typename T>
|
||||
typename RelatedTypes<T>::fractional_t getPeriodMean(const SampleStatHandle<T>& stat, size_t num_periods = S32_MAX)
|
||||
typename RelatedTypes<T>::fractional_t getPeriodMean(const SampleStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
return typename RelatedTypes<T>::fractional_t(getPeriodMean(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods));
|
||||
}
|
||||
|
||||
F64 getPeriodMean(const StatType<EventAccumulator>& stat, size_t num_periods = S32_MAX);
|
||||
F64 getPeriodMean(const StatType<EventAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max());
|
||||
template<typename T>
|
||||
typename RelatedTypes<T>::fractional_t getPeriodMean(const EventStatHandle<T>& stat, size_t num_periods = S32_MAX)
|
||||
typename RelatedTypes<T>::fractional_t getPeriodMean(const EventStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
return typename RelatedTypes<T>::fractional_t(getPeriodMean(static_cast<const StatType<EventAccumulator>&>(stat), num_periods));
|
||||
}
|
||||
|
||||
F64Kilobytes getPeriodMean(const StatType<MemAccumulator>& stat, size_t num_periods = S32_MAX);
|
||||
F64Kilobytes getPeriodMean(const MemStatHandle& stat, size_t num_periods = S32_MAX);
|
||||
F64Kilobytes getPeriodMean(const StatType<MemAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max());
|
||||
F64Kilobytes getPeriodMean(const MemStatHandle& stat, size_t num_periods = std::numeric_limits<size_t>::max());
|
||||
|
||||
template <typename T>
|
||||
typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMeanPerSec(const StatType<T>& stat, size_t num_periods = S32_MAX)
|
||||
typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMeanPerSec(const StatType<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
num_periods = llmin(num_periods, getNumRecordedPeriods());
|
||||
|
||||
typename RelatedTypes<typename T::value_t>::fractional_t mean = 0;
|
||||
|
||||
for (S32 i = 1; i <= num_periods; i++)
|
||||
for (size_t i = 1; i <= num_periods; i++)
|
||||
{
|
||||
Recording& recording = getPrevRecording(i);
|
||||
if (recording.getDuration() > (F32Seconds)0.f)
|
||||
|
|
@ -593,64 +594,64 @@ namespace LLTrace
|
|||
}
|
||||
|
||||
template<typename T>
|
||||
typename RelatedTypes<T>::fractional_t getPeriodMeanPerSec(const CountStatHandle<T>& stat, size_t num_periods = S32_MAX)
|
||||
typename RelatedTypes<T>::fractional_t getPeriodMeanPerSec(const CountStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
return typename RelatedTypes<T>::fractional_t(getPeriodMeanPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
|
||||
}
|
||||
|
||||
F64 getPeriodMedian( const StatType<SampleAccumulator>& stat, size_t num_periods = S32_MAX);
|
||||
F64 getPeriodMedian( const StatType<SampleAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max());
|
||||
|
||||
template <typename T>
|
||||
typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMedianPerSec(const StatType<T>& stat, size_t num_periods = S32_MAX)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
num_periods = llmin(num_periods, getNumRecordedPeriods());
|
||||
template <typename T>
|
||||
typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMedianPerSec(const StatType<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
num_periods = llmin(num_periods, getNumRecordedPeriods());
|
||||
|
||||
std::vector <typename RelatedTypes<typename T::value_t>::fractional_t> buf;
|
||||
for (S32 i = 1; i <= num_periods; i++)
|
||||
{
|
||||
Recording& recording = getPrevRecording(i);
|
||||
if (recording.getDuration() > (F32Seconds)0.f)
|
||||
{
|
||||
buf.push_back(recording.getPerSec(stat));
|
||||
}
|
||||
}
|
||||
std::sort(buf.begin(), buf.end());
|
||||
std::vector <typename RelatedTypes<typename T::value_t>::fractional_t> buf;
|
||||
for (size_t i = 1; i <= num_periods; i++)
|
||||
{
|
||||
Recording& recording = getPrevRecording(i);
|
||||
if (recording.getDuration() > (F32Seconds)0.f)
|
||||
{
|
||||
buf.push_back(recording.getPerSec(stat));
|
||||
}
|
||||
}
|
||||
std::sort(buf.begin(), buf.end());
|
||||
|
||||
return typename RelatedTypes<T>::fractional_t((buf.size() % 2 == 0) ? (buf[buf.size() / 2 - 1] + buf[buf.size() / 2]) / 2 : buf[buf.size() / 2]);
|
||||
}
|
||||
return typename RelatedTypes<T>::fractional_t((buf.size() % 2 == 0) ? (buf[buf.size() / 2 - 1] + buf[buf.size() / 2]) / 2 : buf[buf.size() / 2]);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
typename RelatedTypes<T>::fractional_t getPeriodMedianPerSec(const CountStatHandle<T>& stat, size_t num_periods = S32_MAX)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
return typename RelatedTypes<T>::fractional_t(getPeriodMedianPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
|
||||
}
|
||||
template<typename T>
|
||||
typename RelatedTypes<T>::fractional_t getPeriodMedianPerSec(const CountStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
return typename RelatedTypes<T>::fractional_t(getPeriodMedianPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
|
||||
}
|
||||
|
||||
//
|
||||
// PERIODIC STANDARD DEVIATION
|
||||
//
|
||||
|
||||
F64 getPeriodStandardDeviation(const StatType<SampleAccumulator>& stat, size_t num_periods = S32_MAX);
|
||||
F64 getPeriodStandardDeviation(const StatType<SampleAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max());
|
||||
|
||||
template<typename T>
|
||||
typename RelatedTypes<T>::fractional_t getPeriodStandardDeviation(const SampleStatHandle<T>& stat, size_t num_periods = S32_MAX)
|
||||
typename RelatedTypes<T>::fractional_t getPeriodStandardDeviation(const SampleStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
return typename RelatedTypes<T>::fractional_t(getPeriodStandardDeviation(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods));
|
||||
}
|
||||
|
||||
F64 getPeriodStandardDeviation(const StatType<EventAccumulator>& stat, size_t num_periods = S32_MAX);
|
||||
F64 getPeriodStandardDeviation(const StatType<EventAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max());
|
||||
template<typename T>
|
||||
typename RelatedTypes<T>::fractional_t getPeriodStandardDeviation(const EventStatHandle<T>& stat, size_t num_periods = S32_MAX)
|
||||
typename RelatedTypes<T>::fractional_t getPeriodStandardDeviation(const EventStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
return typename RelatedTypes<T>::fractional_t(getPeriodStandardDeviation(static_cast<const StatType<EventAccumulator>&>(stat), num_periods));
|
||||
}
|
||||
|
||||
F64Kilobytes getPeriodStandardDeviation(const StatType<MemAccumulator>& stat, size_t num_periods = S32_MAX);
|
||||
F64Kilobytes getPeriodStandardDeviation(const MemStatHandle& stat, size_t num_periods = S32_MAX);
|
||||
F64Kilobytes getPeriodStandardDeviation(const StatType<MemAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max());
|
||||
F64Kilobytes getPeriodStandardDeviation(const MemStatHandle& stat, size_t num_periods = std::numeric_limits<size_t>::max());
|
||||
|
||||
private:
|
||||
// implementation for LLStopWatchControlsMixin
|
||||
|
|
@ -659,6 +660,35 @@ namespace LLTrace
|
|||
/*virtual*/ void handleReset();
|
||||
/*virtual*/ void handleSplitTo(PeriodicRecording& other);
|
||||
|
||||
// helper methods for wraparound ring-buffer arithmetic
|
||||
inline
|
||||
size_t wrapi(size_t i) const
|
||||
{
|
||||
return i % mRecordingPeriods.size();
|
||||
}
|
||||
|
||||
inline
|
||||
size_t nexti(size_t i, size_t offset=1) const
|
||||
{
|
||||
return wrapi(i + offset);
|
||||
}
|
||||
|
||||
inline
|
||||
size_t previ(size_t i, size_t offset=1) const
|
||||
{
|
||||
auto num_periods = mRecordingPeriods.size();
|
||||
// constrain offset
|
||||
offset = llclamp(offset, 0, num_periods - 1);
|
||||
// add size() so expression can't go (unsigned) "negative"
|
||||
return wrapi(i + num_periods - offset);
|
||||
}
|
||||
|
||||
inline
|
||||
void inci(size_t& i, size_t offset=1) const
|
||||
{
|
||||
i = nexti(i, offset);
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<Recording> mRecordingPeriods;
|
||||
const bool mAutoResize;
|
||||
|
|
|
|||
|
|
@ -885,7 +885,7 @@ U32 LLUUID::getRandomSeed()
|
|||
seed[7] = (unsigned char)(pid);
|
||||
getSystemTime((uuid_time_t*)(&seed[8]));
|
||||
|
||||
U64 seed64 = HBXXH64((const void*)seed, 16).digest();
|
||||
U64 seed64 = HBXXH64::digest((const void*)seed, 16);
|
||||
return U32(seed64) ^ U32(seed64 >> 32);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -116,6 +116,14 @@ public:
|
|||
U16 getCRC16() const;
|
||||
U32 getCRC32() const;
|
||||
|
||||
// Returns a 64 bits digest of the UUID, by XORing its two 64 bits long
|
||||
// words. HB
|
||||
inline U64 getDigest64() const
|
||||
{
|
||||
U64* tmp = (U64*)mData;
|
||||
return tmp[0] ^ tmp[1];
|
||||
}
|
||||
|
||||
static BOOL validate(const std::string& in_string); // Validate that the UUID string is legal.
|
||||
|
||||
static const LLUUID null;
|
||||
|
|
@ -165,36 +173,22 @@ public:
|
|||
LLAssetID makeAssetID(const LLUUID& session) const;
|
||||
};
|
||||
|
||||
// Generate a hash of an LLUUID object using the boost hash templates.
|
||||
template <>
|
||||
struct boost::hash<LLUUID>
|
||||
{
|
||||
typedef LLUUID argument_type;
|
||||
typedef std::size_t result_type;
|
||||
result_type operator()(argument_type const& s) const
|
||||
{
|
||||
result_type seed(0);
|
||||
|
||||
for (S32 i = 0; i < UUID_BYTES; ++i)
|
||||
{
|
||||
boost::hash_combine(seed, s.mData[i]);
|
||||
}
|
||||
|
||||
return seed;
|
||||
}
|
||||
};
|
||||
|
||||
// Adapt boost hash to std hash
|
||||
// std::hash implementation for LLUUID
|
||||
namespace std
|
||||
{
|
||||
template<> struct hash<LLUUID>
|
||||
{
|
||||
std::size_t operator()(LLUUID const& s) const noexcept
|
||||
{
|
||||
return boost::hash<LLUUID>()(s);
|
||||
}
|
||||
};
|
||||
template<> struct hash<LLUUID>
|
||||
{
|
||||
inline size_t operator()(const LLUUID& id) const noexcept
|
||||
{
|
||||
return (size_t)id.getDigest64();
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
// For use with boost containers.
|
||||
inline size_t hash_value(const LLUUID& id) noexcept
|
||||
{
|
||||
return (size_t)id.getDigest64();
|
||||
}
|
||||
|
||||
#endif // LL_LLUUID_H
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ typedef unsigned int U32;
|
|||
|
||||
// to express an index that might go negative
|
||||
// (ssize_t is provided by SOME compilers, don't collide)
|
||||
typedef typename std::make_signed<size_t>::type llssize;
|
||||
typedef typename std::make_signed<std::size_t>::type llssize;
|
||||
|
||||
#if LL_WINDOWS
|
||||
// https://docs.microsoft.com/en-us/cpp/build/reference/zc-wchar-t-wchar-t-is-native-type
|
||||
|
|
|
|||
|
|
@ -109,7 +109,12 @@ namespace tut
|
|||
"import os\n"
|
||||
"import sys\n"
|
||||
"\n"
|
||||
"from llbase import llsd\n"
|
||||
"try:\n"
|
||||
// new freestanding llsd package
|
||||
" import llsd\n"
|
||||
"except ImportError:\n"
|
||||
// older llbase.llsd module
|
||||
" from llbase import llsd\n"
|
||||
"\n"
|
||||
"class ProtocolError(Exception):\n"
|
||||
" def __init__(self, msg, data):\n"
|
||||
|
|
@ -120,26 +125,26 @@ namespace tut
|
|||
" pass\n"
|
||||
"\n"
|
||||
"def get():\n"
|
||||
" hdr = ''\n"
|
||||
" while ':' not in hdr and len(hdr) < 20:\n"
|
||||
" hdr += sys.stdin.read(1)\n"
|
||||
" hdr = []\n"
|
||||
" while b':' not in hdr and len(hdr) < 20:\n"
|
||||
" hdr.append(sys.stdin.buffer.read(1))\n"
|
||||
" if not hdr:\n"
|
||||
" sys.exit(0)\n"
|
||||
" if not hdr.endswith(':'):\n"
|
||||
" if not hdr[-1] == b':':\n"
|
||||
" raise ProtocolError('Expected len:data, got %r' % hdr, hdr)\n"
|
||||
" try:\n"
|
||||
" length = int(hdr[:-1])\n"
|
||||
" length = int(b''.join(hdr[:-1]))\n"
|
||||
" except ValueError:\n"
|
||||
" raise ProtocolError('Non-numeric len %r' % hdr[:-1], hdr[:-1])\n"
|
||||
" parts = []\n"
|
||||
" received = 0\n"
|
||||
" while received < length:\n"
|
||||
" parts.append(sys.stdin.read(length - received))\n"
|
||||
" parts.append(sys.stdin.buffer.read(length - received))\n"
|
||||
" received += len(parts[-1])\n"
|
||||
" data = ''.join(parts)\n"
|
||||
" data = b''.join(parts)\n"
|
||||
" assert len(data) == length\n"
|
||||
" try:\n"
|
||||
" return llsd.parse(data.encode())\n"
|
||||
" return llsd.parse(data)\n"
|
||||
// Seems the old indra.base.llsd module didn't properly
|
||||
// convert IndexError (from running off end of string) to
|
||||
// LLSDParseError.
|
||||
|
|
@ -179,11 +184,11 @@ namespace tut
|
|||
" return _reply\n"
|
||||
"\n"
|
||||
"def put(req):\n"
|
||||
" sys.stdout.write(':'.join((str(len(req)), req)))\n"
|
||||
" sys.stdout.buffer.write(b'%d:%b' % (len(req), req))\n"
|
||||
" sys.stdout.flush()\n"
|
||||
"\n"
|
||||
"def send(pump, data):\n"
|
||||
" put(llsd.format_notation(dict(pump=pump, data=data)).decode())\n"
|
||||
" put(llsd.format_notation(dict(pump=pump, data=data)))\n"
|
||||
"\n"
|
||||
"def request(pump, data):\n"
|
||||
" # we expect 'data' is a dict\n"
|
||||
|
|
|
|||
|
|
@ -46,20 +46,24 @@ typedef U32 uint32_t;
|
|||
|
||||
#include "boost/range.hpp"
|
||||
#include "boost/foreach.hpp"
|
||||
#include "boost/function.hpp"
|
||||
#include "boost/bind.hpp"
|
||||
#include "boost/phoenix/bind/bind_function.hpp"
|
||||
#include "boost/phoenix/core/argument.hpp"
|
||||
using namespace boost::phoenix;
|
||||
|
||||
#include "../llsd.h"
|
||||
#include "../llsdserialize.h"
|
||||
#include "llsd.h"
|
||||
#include "llsdserialize.h"
|
||||
#include "llsdutil.h"
|
||||
#include "../llformat.h"
|
||||
#include "llformat.h"
|
||||
#include "llmemorystream.h"
|
||||
|
||||
#include "../test/lltut.h"
|
||||
#include "../test/namedtempfile.h"
|
||||
#include "stringize.h"
|
||||
#include <functional>
|
||||
|
||||
typedef std::function<void(const LLSD& data, std::ostream& str)> FormatterFunction;
|
||||
typedef std::function<bool(std::istream& istr, LLSD& data, llssize max_bytes)> ParserFunction;
|
||||
|
||||
std::vector<U8> string_to_vector(const std::string& str)
|
||||
{
|
||||
|
|
@ -112,7 +116,7 @@ namespace tut
|
|||
mSD = LLUUID::null;
|
||||
expected = "<llsd><uuid /></llsd>\n";
|
||||
xml_test("null uuid", expected);
|
||||
|
||||
|
||||
mSD = LLUUID("c96f9b1e-f589-4100-9774-d98643ce0bed");
|
||||
expected = "<llsd><uuid>c96f9b1e-f589-4100-9774-d98643ce0bed</uuid></llsd>\n";
|
||||
xml_test("uuid", expected);
|
||||
|
|
@ -136,7 +140,7 @@ namespace tut
|
|||
expected = "<llsd><binary encoding=\"base64\">aGVsbG8=</binary></llsd>\n";
|
||||
xml_test("binary", expected);
|
||||
}
|
||||
|
||||
|
||||
template<> template<>
|
||||
void sd_xml_object::test<2>()
|
||||
{
|
||||
|
|
@ -225,7 +229,7 @@ namespace tut
|
|||
expected = "<llsd><map><key>baz</key><undef /><key>foo</key><string>bar</string></map></llsd>\n";
|
||||
xml_test("2 element map", expected);
|
||||
}
|
||||
|
||||
|
||||
template<> template<>
|
||||
void sd_xml_object::test<6>()
|
||||
{
|
||||
|
|
@ -241,7 +245,7 @@ namespace tut
|
|||
expected = "<llsd><binary encoding=\"base64\">Nnw2fGFzZGZoYXBweWJveHw2MGU0NGVjNS0zMDVjLTQzYzItOWExOS1iNGI4OWIxYWUyYTZ8NjBlNDRlYzUtMzA1Yy00M2MyLTlhMTktYjRiODliMWFlMmE2fDYwZTQ0ZWM1LTMwNWMtNDNjMi05YTE5LWI0Yjg5YjFhZTJhNnwwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDB8N2ZmZmZmZmZ8N2ZmZmZmZmZ8MHwwfDgyMDAwfDQ1MGZlMzk0LTI5MDQtYzlhZC0yMTRjLWEwN2ViN2ZlZWMyOXwoTm8gRGVzY3JpcHRpb24pfDB8MTB8MA==</binary></llsd>\n";
|
||||
xml_test("binary", expected);
|
||||
}
|
||||
|
||||
|
||||
class TestLLSDSerializeData
|
||||
{
|
||||
public:
|
||||
|
|
@ -250,9 +254,34 @@ namespace tut
|
|||
|
||||
void doRoundTripTests(const std::string&);
|
||||
void checkRoundTrip(const std::string&, const LLSD& v);
|
||||
|
||||
LLPointer<LLSDFormatter> mFormatter;
|
||||
LLPointer<LLSDParser> mParser;
|
||||
|
||||
void setFormatterParser(LLPointer<LLSDFormatter> formatter, LLPointer<LLSDParser> parser)
|
||||
{
|
||||
mFormatter = [formatter](const LLSD& data, std::ostream& str)
|
||||
{
|
||||
formatter->format(data, str);
|
||||
};
|
||||
// this lambda must be mutable since otherwise the bound 'parser'
|
||||
// is assumed to point to a const LLSDParser
|
||||
mParser = [parser](std::istream& istr, LLSD& data, llssize max_bytes) mutable
|
||||
{
|
||||
// reset() call is needed since test code re-uses parser object
|
||||
parser->reset();
|
||||
return (parser->parse(istr, data, max_bytes) > 0);
|
||||
};
|
||||
}
|
||||
|
||||
void setParser(bool (*parser)(LLSD&, std::istream&, llssize))
|
||||
{
|
||||
// why does LLSDSerialize::deserialize() reverse the parse() params??
|
||||
mParser = [parser](std::istream& istr, LLSD& data, llssize max_bytes)
|
||||
{
|
||||
return parser(data, istr, max_bytes);
|
||||
};
|
||||
}
|
||||
|
||||
FormatterFunction mFormatter;
|
||||
ParserFunction mParser;
|
||||
};
|
||||
|
||||
TestLLSDSerializeData::TestLLSDSerializeData()
|
||||
|
|
@ -265,12 +294,11 @@ namespace tut
|
|||
|
||||
void TestLLSDSerializeData::checkRoundTrip(const std::string& msg, const LLSD& v)
|
||||
{
|
||||
std::stringstream stream;
|
||||
mFormatter->format(v, stream);
|
||||
std::stringstream stream;
|
||||
mFormatter(v, stream);
|
||||
//LL_INFOS() << "checkRoundTrip: length " << stream.str().length() << LL_ENDL;
|
||||
LLSD w;
|
||||
mParser->reset(); // reset() call is needed since test code re-uses mParser
|
||||
mParser->parse(stream, w, stream.str().size());
|
||||
mParser(stream, w, stream.str().size());
|
||||
|
||||
try
|
||||
{
|
||||
|
|
@ -299,52 +327,52 @@ namespace tut
|
|||
fillmap(root[key], width, depth - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TestLLSDSerializeData::doRoundTripTests(const std::string& msg)
|
||||
{
|
||||
LLSD v;
|
||||
checkRoundTrip(msg + " undefined", v);
|
||||
|
||||
|
||||
v = true;
|
||||
checkRoundTrip(msg + " true bool", v);
|
||||
|
||||
|
||||
v = false;
|
||||
checkRoundTrip(msg + " false bool", v);
|
||||
|
||||
|
||||
v = 1;
|
||||
checkRoundTrip(msg + " positive int", v);
|
||||
|
||||
|
||||
v = 0;
|
||||
checkRoundTrip(msg + " zero int", v);
|
||||
|
||||
|
||||
v = -1;
|
||||
checkRoundTrip(msg + " negative int", v);
|
||||
|
||||
|
||||
v = 1234.5f;
|
||||
checkRoundTrip(msg + " positive float", v);
|
||||
|
||||
|
||||
v = 0.0f;
|
||||
checkRoundTrip(msg + " zero float", v);
|
||||
|
||||
|
||||
v = -1234.5f;
|
||||
checkRoundTrip(msg + " negative float", v);
|
||||
|
||||
|
||||
// FIXME: need a NaN test
|
||||
|
||||
|
||||
v = LLUUID::null;
|
||||
checkRoundTrip(msg + " null uuid", v);
|
||||
|
||||
|
||||
LLUUID newUUID;
|
||||
newUUID.generate();
|
||||
v = newUUID;
|
||||
checkRoundTrip(msg + " new uuid", v);
|
||||
|
||||
|
||||
v = "";
|
||||
checkRoundTrip(msg + " empty string", v);
|
||||
|
||||
|
||||
v = "some string";
|
||||
checkRoundTrip(msg + " non-empty string", v);
|
||||
|
||||
|
||||
v =
|
||||
"Second Life is a 3-D virtual world entirely built and owned by its residents. "
|
||||
"Since opening to the public in 2003, it has grown explosively and today is "
|
||||
|
|
@ -372,7 +400,7 @@ namespace tut
|
|||
for (U32 block = 0x000000; block <= 0x10ffff; block += block_size)
|
||||
{
|
||||
std::ostringstream out;
|
||||
|
||||
|
||||
for (U32 c = block; c < block + block_size; ++c)
|
||||
{
|
||||
if (c <= 0x000001f
|
||||
|
|
@ -386,7 +414,7 @@ namespace tut
|
|||
if (0x00fdd0 <= c && c <= 0x00fdef) { continue; }
|
||||
if ((c & 0x00fffe) == 0x00fffe) { continue; }
|
||||
// see Unicode standard, section 15.8
|
||||
|
||||
|
||||
if (c <= 0x00007f)
|
||||
{
|
||||
out << (char)(c & 0x7f);
|
||||
|
|
@ -410,55 +438,55 @@ namespace tut
|
|||
out << (char)(0x80 | ((c >> 0) & 0x3f));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
v = out.str();
|
||||
|
||||
std::ostringstream blockmsg;
|
||||
blockmsg << msg << " unicode string block 0x" << std::hex << block;
|
||||
checkRoundTrip(blockmsg.str(), v);
|
||||
}
|
||||
|
||||
|
||||
LLDate epoch;
|
||||
v = epoch;
|
||||
checkRoundTrip(msg + " epoch date", v);
|
||||
|
||||
|
||||
LLDate aDay("2002-12-07T05:07:15.00Z");
|
||||
v = aDay;
|
||||
checkRoundTrip(msg + " date", v);
|
||||
|
||||
|
||||
LLURI path("http://slurl.com/secondlife/Ambleside/57/104/26/");
|
||||
v = path;
|
||||
checkRoundTrip(msg + " url", v);
|
||||
|
||||
|
||||
const char source[] = "it must be a blue moon again";
|
||||
std::vector<U8> data;
|
||||
// note, includes terminating '\0'
|
||||
copy(&source[0], &source[sizeof(source)], back_inserter(data));
|
||||
|
||||
|
||||
v = data;
|
||||
checkRoundTrip(msg + " binary", v);
|
||||
|
||||
|
||||
v = LLSD::emptyMap();
|
||||
checkRoundTrip(msg + " empty map", v);
|
||||
|
||||
|
||||
v = LLSD::emptyMap();
|
||||
v["name"] = "luke"; //v.insert("name", "luke");
|
||||
v["age"] = 3; //v.insert("age", 3);
|
||||
checkRoundTrip(msg + " map", v);
|
||||
|
||||
|
||||
v.clear();
|
||||
v["a"]["1"] = true;
|
||||
v["b"]["0"] = false;
|
||||
checkRoundTrip(msg + " nested maps", v);
|
||||
|
||||
|
||||
v = LLSD::emptyArray();
|
||||
checkRoundTrip(msg + " empty array", v);
|
||||
|
||||
|
||||
v = LLSD::emptyArray();
|
||||
v.append("ali");
|
||||
v.append(28);
|
||||
checkRoundTrip(msg + " array", v);
|
||||
|
||||
|
||||
v.clear();
|
||||
v[0][0] = true;
|
||||
v[1][0] = false;
|
||||
|
|
@ -468,7 +496,7 @@ namespace tut
|
|||
fillmap(v, 10, 3); // 10^6 maps
|
||||
checkRoundTrip(msg + " many nested maps", v);
|
||||
}
|
||||
|
||||
|
||||
typedef tut::test_group<TestLLSDSerializeData> TestLLSDSerializeGroup;
|
||||
typedef TestLLSDSerializeGroup::object TestLLSDSerializeObject;
|
||||
TestLLSDSerializeGroup gTestLLSDSerializeGroup("llsd serialization");
|
||||
|
|
@ -476,35 +504,106 @@ namespace tut
|
|||
template<> template<>
|
||||
void TestLLSDSerializeObject::test<1>()
|
||||
{
|
||||
mFormatter = new LLSDNotationFormatter(false, "", LLSDFormatter::OPTIONS_PRETTY_BINARY);
|
||||
mParser = new LLSDNotationParser();
|
||||
setFormatterParser(new LLSDNotationFormatter(false, "", LLSDFormatter::OPTIONS_PRETTY_BINARY),
|
||||
new LLSDNotationParser());
|
||||
doRoundTripTests("pretty binary notation serialization");
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void TestLLSDSerializeObject::test<2>()
|
||||
{
|
||||
mFormatter = new LLSDNotationFormatter(false, "", LLSDFormatter::OPTIONS_NONE);
|
||||
mParser = new LLSDNotationParser();
|
||||
setFormatterParser(new LLSDNotationFormatter(false, "", LLSDFormatter::OPTIONS_NONE),
|
||||
new LLSDNotationParser());
|
||||
doRoundTripTests("raw binary notation serialization");
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void TestLLSDSerializeObject::test<3>()
|
||||
{
|
||||
mFormatter = new LLSDXMLFormatter();
|
||||
mParser = new LLSDXMLParser();
|
||||
setFormatterParser(new LLSDXMLFormatter(), new LLSDXMLParser());
|
||||
doRoundTripTests("xml serialization");
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void TestLLSDSerializeObject::test<4>()
|
||||
{
|
||||
mFormatter = new LLSDBinaryFormatter();
|
||||
mParser = new LLSDBinaryParser();
|
||||
setFormatterParser(new LLSDBinaryFormatter(), new LLSDBinaryParser());
|
||||
doRoundTripTests("binary serialization");
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void TestLLSDSerializeObject::test<5>()
|
||||
{
|
||||
mFormatter = [](const LLSD& sd, std::ostream& str)
|
||||
{
|
||||
LLSDSerialize::serialize(sd, str, LLSDSerialize::LLSD_BINARY);
|
||||
};
|
||||
setParser(LLSDSerialize::deserialize);
|
||||
doRoundTripTests("serialize(LLSD_BINARY)");
|
||||
};
|
||||
|
||||
template<> template<>
|
||||
void TestLLSDSerializeObject::test<6>()
|
||||
{
|
||||
mFormatter = [](const LLSD& sd, std::ostream& str)
|
||||
{
|
||||
LLSDSerialize::serialize(sd, str, LLSDSerialize::LLSD_XML);
|
||||
};
|
||||
setParser(LLSDSerialize::deserialize);
|
||||
doRoundTripTests("serialize(LLSD_XML)");
|
||||
};
|
||||
|
||||
template<> template<>
|
||||
void TestLLSDSerializeObject::test<7>()
|
||||
{
|
||||
mFormatter = [](const LLSD& sd, std::ostream& str)
|
||||
{
|
||||
LLSDSerialize::serialize(sd, str, LLSDSerialize::LLSD_NOTATION);
|
||||
};
|
||||
setParser(LLSDSerialize::deserialize);
|
||||
// In this test, serialize(LLSD_NOTATION) emits a header recognized by
|
||||
// deserialize().
|
||||
doRoundTripTests("serialize(LLSD_NOTATION)");
|
||||
};
|
||||
|
||||
template<> template<>
|
||||
void TestLLSDSerializeObject::test<8>()
|
||||
{
|
||||
setFormatterParser(new LLSDNotationFormatter(false, "", LLSDFormatter::OPTIONS_NONE),
|
||||
new LLSDNotationParser());
|
||||
setParser(LLSDSerialize::deserialize);
|
||||
// This is an interesting test because LLSDNotationFormatter does not
|
||||
// emit an llsd/notation header.
|
||||
doRoundTripTests("LLSDNotationFormatter -> deserialize");
|
||||
};
|
||||
|
||||
template<> template<>
|
||||
void TestLLSDSerializeObject::test<9>()
|
||||
{
|
||||
setFormatterParser(new LLSDXMLFormatter(false, "", LLSDFormatter::OPTIONS_NONE),
|
||||
new LLSDXMLParser());
|
||||
setParser(LLSDSerialize::deserialize);
|
||||
// This is an interesting test because LLSDXMLFormatter does not
|
||||
// emit an LLSD/XML header.
|
||||
doRoundTripTests("LLSDXMLFormatter -> deserialize");
|
||||
};
|
||||
|
||||
/*==========================================================================*|
|
||||
// We do not expect this test to succeed. Without a header, neither
|
||||
// notation LLSD nor binary LLSD reliably start with a distinct character,
|
||||
// the way XML LLSD starts with '<'. By convention, we default to notation
|
||||
// rather than binary.
|
||||
template<> template<>
|
||||
void TestLLSDSerializeObject::test<10>()
|
||||
{
|
||||
setFormatterParser(new LLSDBinaryFormatter(false, "", LLSDFormatter::OPTIONS_NONE),
|
||||
new LLSDBinaryParser());
|
||||
setParser(LLSDSerialize::deserialize);
|
||||
// This is an interesting test because LLSDBinaryFormatter does not
|
||||
// emit an LLSD/Binary header.
|
||||
doRoundTripTests("LLSDBinaryFormatter -> deserialize");
|
||||
};
|
||||
|*==========================================================================*/
|
||||
|
||||
/**
|
||||
* @class TestLLSDParsing
|
||||
|
|
@ -555,7 +654,7 @@ namespace tut
|
|||
public:
|
||||
TestLLSDXMLParsing() {}
|
||||
};
|
||||
|
||||
|
||||
typedef tut::test_group<TestLLSDXMLParsing> TestLLSDXMLParsingGroup;
|
||||
typedef TestLLSDXMLParsingGroup::object TestLLSDXMLParsingObject;
|
||||
TestLLSDXMLParsingGroup gTestLLSDXMLParsingGroup("llsd XML parsing");
|
||||
|
|
@ -586,8 +685,8 @@ namespace tut
|
|||
LLSD(),
|
||||
LLSDParser::PARSE_FAILURE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
template<> template<>
|
||||
void TestLLSDXMLParsingObject::test<2>()
|
||||
{
|
||||
|
|
@ -596,7 +695,7 @@ namespace tut
|
|||
v["amy"] = 23;
|
||||
v["bob"] = LLSD();
|
||||
v["cam"] = 1.23;
|
||||
|
||||
|
||||
ensureParse(
|
||||
"unknown data type",
|
||||
"<llsd><map>"
|
||||
|
|
@ -607,16 +706,16 @@ namespace tut
|
|||
v,
|
||||
v.size() + 1);
|
||||
}
|
||||
|
||||
|
||||
template<> template<>
|
||||
void TestLLSDXMLParsingObject::test<3>()
|
||||
{
|
||||
// test handling of nested bad data
|
||||
|
||||
|
||||
LLSD v;
|
||||
v["amy"] = 23;
|
||||
v["cam"] = 1.23;
|
||||
|
||||
|
||||
ensureParse(
|
||||
"map with html",
|
||||
"<llsd><map>"
|
||||
|
|
@ -626,7 +725,7 @@ namespace tut
|
|||
"</map></llsd>",
|
||||
v,
|
||||
v.size() + 1);
|
||||
|
||||
|
||||
v.clear();
|
||||
v["amy"] = 23;
|
||||
v["cam"] = 1.23;
|
||||
|
|
@ -639,7 +738,7 @@ namespace tut
|
|||
"</map></llsd>",
|
||||
v,
|
||||
v.size() + 1);
|
||||
|
||||
|
||||
v.clear();
|
||||
v["amy"] = 23;
|
||||
v["bob"] = LLSD::emptyMap();
|
||||
|
|
@ -661,7 +760,7 @@ namespace tut
|
|||
v[0] = 23;
|
||||
v[1] = LLSD();
|
||||
v[2] = 1.23;
|
||||
|
||||
|
||||
ensureParse(
|
||||
"array value of html",
|
||||
"<llsd><array>"
|
||||
|
|
@ -671,7 +770,7 @@ namespace tut
|
|||
"</array></llsd>",
|
||||
v,
|
||||
v.size() + 1);
|
||||
|
||||
|
||||
v.clear();
|
||||
v[0] = 23;
|
||||
v[1] = LLSD::emptyMap();
|
||||
|
|
@ -1225,7 +1324,7 @@ namespace tut
|
|||
vec[0] = 'a'; vec[1] = 'b'; vec[2] = 'c';
|
||||
vec[3] = '3'; vec[4] = '2'; vec[5] = '1';
|
||||
LLSD value = vec;
|
||||
|
||||
|
||||
vec.resize(11);
|
||||
vec[0] = 'b'; // for binary
|
||||
vec[5] = 'a'; vec[6] = 'b'; vec[7] = 'c';
|
||||
|
|
@ -1694,85 +1793,83 @@ namespace tut
|
|||
ensureBinaryAndXML("map", test);
|
||||
}
|
||||
|
||||
struct TestPythonCompatible
|
||||
// helper for TestPythonCompatible
|
||||
static std::string import_llsd("import os.path\n"
|
||||
"import sys\n"
|
||||
"try:\n"
|
||||
// new freestanding llsd package
|
||||
" import llsd\n"
|
||||
"except ImportError:\n"
|
||||
// older llbase.llsd module
|
||||
" from llbase import llsd\n");
|
||||
|
||||
// helper for TestPythonCompatible
|
||||
template <typename CONTENT>
|
||||
void python(const std::string& desc, const CONTENT& script, int expect=0)
|
||||
{
|
||||
TestPythonCompatible():
|
||||
// Note the peculiar insertion of __FILE__ into this string. Since
|
||||
// this script is being written into a platform-dependent temp
|
||||
// directory, we can't locate indra/lib/python relative to
|
||||
// Python's __file__. Use __FILE__ instead, navigating relative
|
||||
// to this C++ source file. Use Python raw-string syntax so
|
||||
// Windows pathname backslashes won't mislead Python's string
|
||||
// scanner.
|
||||
import_llsd("import os.path\n"
|
||||
"import sys\n"
|
||||
"from llbase import llsd\n")
|
||||
{}
|
||||
~TestPythonCompatible() {}
|
||||
auto PYTHON(LLStringUtil::getenv("PYTHON"));
|
||||
ensure("Set $PYTHON to the Python interpreter", !PYTHON.empty());
|
||||
|
||||
std::string import_llsd;
|
||||
|
||||
template <typename CONTENT>
|
||||
void python(const std::string& desc, const CONTENT& script, int expect=0)
|
||||
{
|
||||
auto PYTHON(LLStringUtil::getenv("PYTHON"));
|
||||
ensure("Set $PYTHON to the Python interpreter", !PYTHON.empty());
|
||||
|
||||
NamedTempFile scriptfile("py", script);
|
||||
NamedTempFile scriptfile("py", script);
|
||||
|
||||
#if LL_WINDOWS
|
||||
std::string q("\"");
|
||||
std::string qPYTHON(q + PYTHON + q);
|
||||
std::string qscript(q + scriptfile.getName() + q);
|
||||
int rc = _spawnl(_P_WAIT, PYTHON.c_str(), qPYTHON.c_str(), qscript.c_str(), NULL);
|
||||
if (rc == -1)
|
||||
{
|
||||
char buffer[256];
|
||||
strerror_s(buffer, errno); // C++ can infer the buffer size! :-O
|
||||
ensure(STRINGIZE("Couldn't run Python " << desc << "script: " << buffer), false);
|
||||
}
|
||||
else
|
||||
{
|
||||
ensure_equals(STRINGIZE(desc << " script terminated with rc " << rc), rc, expect);
|
||||
}
|
||||
std::string q("\"");
|
||||
std::string qPYTHON(q + PYTHON + q);
|
||||
std::string qscript(q + scriptfile.getName() + q);
|
||||
int rc = _spawnl(_P_WAIT, PYTHON.c_str(), qPYTHON.c_str(), qscript.c_str(), NULL);
|
||||
if (rc == -1)
|
||||
{
|
||||
char buffer[256];
|
||||
strerror_s(buffer, errno); // C++ can infer the buffer size! :-O
|
||||
ensure(STRINGIZE("Couldn't run Python " << desc << "script: " << buffer), false);
|
||||
}
|
||||
else
|
||||
{
|
||||
ensure_equals(STRINGIZE(desc << " script terminated with rc " << rc), rc, expect);
|
||||
}
|
||||
|
||||
#else // LL_DARWIN, LL_LINUX
|
||||
LLProcess::Params params;
|
||||
params.executable = PYTHON;
|
||||
params.args.add(scriptfile.getName());
|
||||
LLProcessPtr py(LLProcess::create(params));
|
||||
ensure(STRINGIZE("Couldn't launch " << desc << " script"), bool(py));
|
||||
// Implementing timeout would mean messing with alarm() and
|
||||
// catching SIGALRM... later maybe...
|
||||
int status(0);
|
||||
if (waitpid(py->getProcessID(), &status, 0) == -1)
|
||||
LLProcess::Params params;
|
||||
params.executable = PYTHON;
|
||||
params.args.add(scriptfile.getName());
|
||||
LLProcessPtr py(LLProcess::create(params));
|
||||
ensure(STRINGIZE("Couldn't launch " << desc << " script"), bool(py));
|
||||
// Implementing timeout would mean messing with alarm() and
|
||||
// catching SIGALRM... later maybe...
|
||||
int status(0);
|
||||
if (waitpid(py->getProcessID(), &status, 0) == -1)
|
||||
{
|
||||
int waitpid_errno(errno);
|
||||
ensure_equals(STRINGIZE("Couldn't retrieve rc from " << desc << " script: "
|
||||
"waitpid() errno " << waitpid_errno),
|
||||
waitpid_errno, ECHILD);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (WIFEXITED(status))
|
||||
{
|
||||
int waitpid_errno(errno);
|
||||
ensure_equals(STRINGIZE("Couldn't retrieve rc from " << desc << " script: "
|
||||
"waitpid() errno " << waitpid_errno),
|
||||
waitpid_errno, ECHILD);
|
||||
int rc(WEXITSTATUS(status));
|
||||
ensure_equals(STRINGIZE(desc << " script terminated with rc " << rc),
|
||||
rc, expect);
|
||||
}
|
||||
else if (WIFSIGNALED(status))
|
||||
{
|
||||
ensure(STRINGIZE(desc << " script terminated by signal " << WTERMSIG(status)),
|
||||
false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (WIFEXITED(status))
|
||||
{
|
||||
int rc(WEXITSTATUS(status));
|
||||
ensure_equals(STRINGIZE(desc << " script terminated with rc " << rc),
|
||||
rc, expect);
|
||||
}
|
||||
else if (WIFSIGNALED(status))
|
||||
{
|
||||
ensure(STRINGIZE(desc << " script terminated by signal " << WTERMSIG(status)),
|
||||
false);
|
||||
}
|
||||
else
|
||||
{
|
||||
ensure(STRINGIZE(desc << " script produced impossible status " << status),
|
||||
false);
|
||||
}
|
||||
ensure(STRINGIZE(desc << " script produced impossible status " << status),
|
||||
false);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
struct TestPythonCompatible
|
||||
{
|
||||
TestPythonCompatible() {}
|
||||
~TestPythonCompatible() {}
|
||||
};
|
||||
|
||||
typedef tut::test_group<TestPythonCompatible> TestPythonCompatibleGroup;
|
||||
|
|
@ -1798,25 +1895,33 @@ namespace tut
|
|||
"print('Running on', sys.platform)\n");
|
||||
}
|
||||
|
||||
// helper for test<3>
|
||||
static void writeLLSDArray(std::ostream& out, const LLSD& array)
|
||||
// helper for test<3> - test<7>
|
||||
static void writeLLSDArray(const FormatterFunction& serialize,
|
||||
std::ostream& out, const LLSD& array)
|
||||
{
|
||||
BOOST_FOREACH(LLSD item, llsd::inArray(array))
|
||||
for (const LLSD& item : llsd::inArray(array))
|
||||
{
|
||||
LLSDSerialize::toNotation(item, out);
|
||||
// It's important to separate with newlines because Python's llsd
|
||||
// module doesn't support parsing from a file stream, only from a
|
||||
// string, so we have to know how much of the file to read into a
|
||||
// string.
|
||||
out << '\n';
|
||||
// It's important to delimit the entries in this file somehow
|
||||
// because, although Python's llsd.parse() can accept a file
|
||||
// stream, the XML parser expects EOF after a single outer element
|
||||
// -- it doesn't just stop. So we must extract a sequence of bytes
|
||||
// strings from the file. But since one of the serialization
|
||||
// formats we want to test is binary, we can't pick any single
|
||||
// byte value as a delimiter! Use a binary integer length prefix
|
||||
// instead.
|
||||
std::ostringstream buffer;
|
||||
serialize(item, buffer);
|
||||
auto buffstr{ buffer.str() };
|
||||
int bufflen{ static_cast<int>(buffstr.length()) };
|
||||
out.write(reinterpret_cast<const char*>(&bufflen), sizeof(bufflen));
|
||||
out.write(buffstr.c_str(), buffstr.length());
|
||||
}
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void TestPythonCompatibleObject::test<3>()
|
||||
// helper for test<3> - test<7>
|
||||
static void toPythonUsing(const std::string& desc,
|
||||
const FormatterFunction& serialize)
|
||||
{
|
||||
set_test_name("verify sequence to Python");
|
||||
|
||||
LLSD cdata(llsd::array(17, 3.14,
|
||||
"This string\n"
|
||||
"has several\n"
|
||||
|
|
@ -1836,7 +1941,7 @@ namespace tut
|
|||
" except StopIteration:\n"
|
||||
" pass\n"
|
||||
" else:\n"
|
||||
" assert False, 'Too many data items'\n";
|
||||
" raise AssertionError('Too many data items')\n";
|
||||
|
||||
// Create an llsdXXXXXX file containing 'data' serialized to
|
||||
// notation.
|
||||
|
|
@ -1845,32 +1950,128 @@ namespace tut
|
|||
// takes a callable. To this callable it passes the
|
||||
// std::ostream with which it's writing the
|
||||
// NamedTempFile.
|
||||
boost::bind(writeLLSDArray, _1, cdata));
|
||||
[serialize, cdata]
|
||||
(std::ostream& out)
|
||||
{ writeLLSDArray(serialize, out, cdata); });
|
||||
|
||||
python("read C++ notation",
|
||||
python("read C++ " + desc,
|
||||
placeholders::arg1 <<
|
||||
import_llsd <<
|
||||
"def parse_each(iterable):\n"
|
||||
" for item in iterable:\n"
|
||||
" yield llsd.parse(item)\n" <<
|
||||
pydata <<
|
||||
"from functools import partial\n"
|
||||
"import io\n"
|
||||
"import struct\n"
|
||||
"lenformat = struct.Struct('i')\n"
|
||||
"def parse_each(inf):\n"
|
||||
" for rawlen in iter(partial(inf.read, lenformat.size), b''):\n"
|
||||
" len = lenformat.unpack(rawlen)[0]\n"
|
||||
// Since llsd.parse() has no max_bytes argument, instead of
|
||||
// passing the input stream directly to parse(), read the item
|
||||
// into a distinct bytes object and parse that.
|
||||
" data = inf.read(len)\n"
|
||||
" try:\n"
|
||||
" frombytes = llsd.parse(data)\n"
|
||||
" except llsd.LLSDParseError as err:\n"
|
||||
" print(f'*** {err}')\n"
|
||||
" print(f'Bad content:\\n{data!r}')\n"
|
||||
" raise\n"
|
||||
// Also try parsing from a distinct stream.
|
||||
" stream = io.BytesIO(data)\n"
|
||||
" fromstream = llsd.parse(stream)\n"
|
||||
" assert frombytes == fromstream\n"
|
||||
" yield frombytes\n"
|
||||
<< pydata <<
|
||||
// Don't forget raw-string syntax for Windows pathnames.
|
||||
"verify(parse_each(open(r'" << file.getName() << "', 'rb')))\n");
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void TestPythonCompatibleObject::test<3>()
|
||||
{
|
||||
set_test_name("to Python using LLSDSerialize::serialize(LLSD_XML)");
|
||||
toPythonUsing("LLSD_XML",
|
||||
[](const LLSD& sd, std::ostream& out)
|
||||
{ LLSDSerialize::serialize(sd, out, LLSDSerialize::LLSD_XML); });
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void TestPythonCompatibleObject::test<4>()
|
||||
{
|
||||
set_test_name("verify sequence from Python");
|
||||
set_test_name("to Python using LLSDSerialize::serialize(LLSD_NOTATION)");
|
||||
toPythonUsing("LLSD_NOTATION",
|
||||
[](const LLSD& sd, std::ostream& out)
|
||||
{ LLSDSerialize::serialize(sd, out, LLSDSerialize::LLSD_NOTATION); });
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void TestPythonCompatibleObject::test<5>()
|
||||
{
|
||||
set_test_name("to Python using LLSDSerialize::serialize(LLSD_BINARY)");
|
||||
toPythonUsing("LLSD_BINARY",
|
||||
[](const LLSD& sd, std::ostream& out)
|
||||
{ LLSDSerialize::serialize(sd, out, LLSDSerialize::LLSD_BINARY); });
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void TestPythonCompatibleObject::test<6>()
|
||||
{
|
||||
set_test_name("to Python using LLSDSerialize::toXML()");
|
||||
toPythonUsing("toXML()", LLSDSerialize::toXML);
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void TestPythonCompatibleObject::test<7>()
|
||||
{
|
||||
set_test_name("to Python using LLSDSerialize::toNotation()");
|
||||
toPythonUsing("toNotation()", LLSDSerialize::toNotation);
|
||||
}
|
||||
|
||||
/*==========================================================================*|
|
||||
template<> template<>
|
||||
void TestPythonCompatibleObject::test<8>()
|
||||
{
|
||||
set_test_name("to Python using LLSDSerialize::toBinary()");
|
||||
// We don't expect this to work because, without a header,
|
||||
// llsd.parse() will assume notation rather than binary.
|
||||
toPythonUsing("toBinary()", LLSDSerialize::toBinary);
|
||||
}
|
||||
|*==========================================================================*/
|
||||
|
||||
// helper for test<8> - test<12>
|
||||
bool itemFromStream(std::istream& istr, LLSD& item, const ParserFunction& parse)
|
||||
{
|
||||
// reset the output value for debugging clarity
|
||||
item.clear();
|
||||
// We use an int length prefix as a foolproof delimiter even for
|
||||
// binary serialized streams.
|
||||
int length{ 0 };
|
||||
istr.read(reinterpret_cast<char*>(&length), sizeof(length));
|
||||
// return parse(istr, item, length);
|
||||
// Sadly, as of 2022-12-01 it seems we can't really trust our LLSD
|
||||
// parsers to honor max_bytes: this test works better when we read
|
||||
// each item into its own distinct LLMemoryStream, instead of passing
|
||||
// the original istr with a max_bytes constraint.
|
||||
std::vector<U8> buffer(length);
|
||||
istr.read(reinterpret_cast<char*>(buffer.data()), length);
|
||||
LLMemoryStream stream(buffer.data(), length);
|
||||
return parse(stream, item, length);
|
||||
}
|
||||
|
||||
// helper for test<8> - test<12>
|
||||
void fromPythonUsing(const std::string& pyformatter,
|
||||
const ParserFunction& parse=
|
||||
[](std::istream& istr, LLSD& data, llssize max_bytes)
|
||||
{ return LLSDSerialize::deserialize(data, istr, max_bytes); })
|
||||
{
|
||||
// Create an empty data file. This is just a placeholder for our
|
||||
// script to write into. Create it to establish a unique name that
|
||||
// we know.
|
||||
NamedTempFile file("llsd", "");
|
||||
|
||||
python("write Python notation",
|
||||
python("Python " + pyformatter,
|
||||
placeholders::arg1 <<
|
||||
import_llsd <<
|
||||
"import struct\n"
|
||||
"lenformat = struct.Struct('i')\n"
|
||||
"DATA = [\n"
|
||||
" 17,\n"
|
||||
" 3.14,\n"
|
||||
|
|
@ -1881,34 +2082,87 @@ namespace tut
|
|||
"]\n"
|
||||
// Don't forget raw-string syntax for Windows pathnames.
|
||||
// N.B. Using 'print' implicitly adds newlines.
|
||||
"with open(r'" << file.getName() << "', 'w') as f:\n"
|
||||
"with open(r'" << file.getName() << "', 'wb') as f:\n"
|
||||
" for item in DATA:\n"
|
||||
" print(llsd.format_notation(item).decode(), file=f)\n");
|
||||
" serialized = llsd." << pyformatter << "(item)\n"
|
||||
" f.write(lenformat.pack(len(serialized)))\n"
|
||||
" f.write(serialized)\n");
|
||||
|
||||
std::ifstream inf(file.getName().c_str());
|
||||
LLSD item;
|
||||
// Notice that we're not doing anything special to parse out the
|
||||
// newlines: LLSDSerialize::fromNotation ignores them. While it would
|
||||
// seem they're not strictly necessary, going in this direction, we
|
||||
// want to ensure that notation-separated-by-newlines works in both
|
||||
// directions -- since in practice, a given file might be read by
|
||||
// either language.
|
||||
ensure_equals("Failed to read LLSD::Integer from Python",
|
||||
LLSDSerialize::fromNotation(item, inf, LLSDSerialize::SIZE_UNLIMITED),
|
||||
1);
|
||||
ensure_equals(item.asInteger(), 17);
|
||||
ensure_equals("Failed to read LLSD::Real from Python",
|
||||
LLSDSerialize::fromNotation(item, inf, LLSDSerialize::SIZE_UNLIMITED),
|
||||
1);
|
||||
ensure_approximately_equals("Bad LLSD::Real value from Python",
|
||||
item.asReal(), 3.14, 7); // 7 bits ~= 0.01
|
||||
ensure_equals("Failed to read LLSD::String from Python",
|
||||
LLSDSerialize::fromNotation(item, inf, LLSDSerialize::SIZE_UNLIMITED),
|
||||
1);
|
||||
ensure_equals(item.asString(),
|
||||
"This string\n"
|
||||
"has several\n"
|
||||
"lines.");
|
||||
|
||||
try
|
||||
{
|
||||
ensure("Failed to read LLSD::Integer from Python",
|
||||
itemFromStream(inf, item, parse));
|
||||
ensure_equals(item.asInteger(), 17);
|
||||
ensure("Failed to read LLSD::Real from Python",
|
||||
itemFromStream(inf, item, parse));
|
||||
ensure_approximately_equals("Bad LLSD::Real value from Python",
|
||||
item.asReal(), 3.14, 7); // 7 bits ~= 0.01
|
||||
ensure("Failed to read LLSD::String from Python",
|
||||
itemFromStream(inf, item, parse));
|
||||
ensure_equals(item.asString(),
|
||||
"This string\n"
|
||||
"has several\n"
|
||||
"lines.");
|
||||
}
|
||||
catch (const tut::failure& err)
|
||||
{
|
||||
std::cout << "for " << err.what() << ", item = " << item << std::endl;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void TestPythonCompatibleObject::test<8>()
|
||||
{
|
||||
set_test_name("from Python XML using LLSDSerialize::deserialize()");
|
||||
fromPythonUsing("format_xml");
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void TestPythonCompatibleObject::test<9>()
|
||||
{
|
||||
set_test_name("from Python notation using LLSDSerialize::deserialize()");
|
||||
fromPythonUsing("format_notation");
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void TestPythonCompatibleObject::test<10>()
|
||||
{
|
||||
set_test_name("from Python binary using LLSDSerialize::deserialize()");
|
||||
fromPythonUsing("format_binary");
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void TestPythonCompatibleObject::test<11>()
|
||||
{
|
||||
set_test_name("from Python XML using fromXML()");
|
||||
// fromXML()'s optional 3rd param isn't max_bytes, it's emit_errors
|
||||
fromPythonUsing("format_xml",
|
||||
[](std::istream& istr, LLSD& data, llssize)
|
||||
{ return LLSDSerialize::fromXML(data, istr) > 0; });
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void TestPythonCompatibleObject::test<12>()
|
||||
{
|
||||
set_test_name("from Python notation using fromNotation()");
|
||||
fromPythonUsing("format_notation",
|
||||
[](std::istream& istr, LLSD& data, llssize max_bytes)
|
||||
{ return LLSDSerialize::fromNotation(data, istr, max_bytes) > 0; });
|
||||
}
|
||||
|
||||
/*==========================================================================*|
|
||||
template<> template<>
|
||||
void TestPythonCompatibleObject::test<13>()
|
||||
{
|
||||
set_test_name("from Python binary using fromBinary()");
|
||||
// We don't expect this to work because format_binary() emits a
|
||||
// header, but fromBinary() won't recognize a header.
|
||||
fromPythonUsing("format_binary",
|
||||
[](std::istream& istr, LLSD& data, llssize max_bytes)
|
||||
{ return LLSDSerialize::fromBinary(data, istr, max_bytes) > 0; });
|
||||
}
|
||||
|*==========================================================================*/
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ from io import StringIO
|
|||
from http.server import HTTPServer, BaseHTTPRequestHandler
|
||||
|
||||
|
||||
from llbase import llsd
|
||||
import llsd
|
||||
|
||||
# we're in llcorehttp/tests ; testrunner.py is found in llmessage/tests
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir,
|
||||
|
|
|
|||
|
|
@ -40,9 +40,12 @@
|
|||
///----------------------------------------------------------------------------
|
||||
/// Exported functions
|
||||
///----------------------------------------------------------------------------
|
||||
// FIXME D567 - what's the point of these, especially if we don't even use them consistently?
|
||||
static const std::string INV_ITEM_ID_LABEL("item_id");
|
||||
static const std::string INV_FOLDER_ID_LABEL("cat_id");
|
||||
static const std::string INV_PARENT_ID_LABEL("parent_id");
|
||||
static const std::string INV_THUMBNAIL_LABEL("thumbnail");
|
||||
static const std::string INV_THUMBNAIL_ID_LABEL("thumbnail_id");
|
||||
static const std::string INV_ASSET_TYPE_LABEL("type");
|
||||
static const std::string INV_PREFERRED_TYPE_LABEL("preferred_type");
|
||||
static const std::string INV_INVENTORY_TYPE_LABEL("inv_type");
|
||||
|
|
@ -99,6 +102,7 @@ void LLInventoryObject::copyObject(const LLInventoryObject* other)
|
|||
mParentUUID = other->mParentUUID;
|
||||
mType = other->mType;
|
||||
mName = other->mName;
|
||||
mThumbnailUUID = other->mThumbnailUUID;
|
||||
}
|
||||
|
||||
const LLUUID& LLInventoryObject::getUUID() const
|
||||
|
|
@ -111,6 +115,11 @@ const LLUUID& LLInventoryObject::getParentUUID() const
|
|||
return mParentUUID;
|
||||
}
|
||||
|
||||
const LLUUID& LLInventoryObject::getThumbnailUUID() const
|
||||
{
|
||||
return mThumbnailUUID;
|
||||
}
|
||||
|
||||
const std::string& LLInventoryObject::getName() const
|
||||
{
|
||||
return mName;
|
||||
|
|
@ -160,6 +169,11 @@ void LLInventoryObject::setParent(const LLUUID& new_parent)
|
|||
mParentUUID = new_parent;
|
||||
}
|
||||
|
||||
void LLInventoryObject::setThumbnailUUID(const LLUUID& thumbnail_uuid)
|
||||
{
|
||||
mThumbnailUUID = thumbnail_uuid;
|
||||
}
|
||||
|
||||
void LLInventoryObject::setType(LLAssetType::EType type)
|
||||
{
|
||||
mType = type;
|
||||
|
|
@ -201,6 +215,26 @@ BOOL LLInventoryObject::importLegacyStream(std::istream& input_stream)
|
|||
{
|
||||
mType = LLAssetType::lookup(valuestr);
|
||||
}
|
||||
else if (0 == strcmp("metadata", keyword))
|
||||
{
|
||||
LLSD metadata(valuestr);
|
||||
if (metadata.has("thumbnail"))
|
||||
{
|
||||
const LLSD& thumbnail = metadata["thumbnail"];
|
||||
if (thumbnail.has("asset_id"))
|
||||
{
|
||||
setThumbnailUUID(thumbnail["asset_id"].asUUID());
|
||||
}
|
||||
else
|
||||
{
|
||||
setThumbnailUUID(LLUUID::null);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
setThumbnailUUID(LLUUID::null);
|
||||
}
|
||||
}
|
||||
else if(0 == strcmp("name", keyword))
|
||||
{
|
||||
//strcpy(valuestr, buffer + strlen(keyword) + 3);
|
||||
|
|
@ -336,6 +370,7 @@ void LLInventoryItem::copyItem(const LLInventoryItem* other)
|
|||
copyObject(other);
|
||||
mPermissions = other->mPermissions;
|
||||
mAssetUUID = other->mAssetUUID;
|
||||
mThumbnailUUID = other->mThumbnailUUID;
|
||||
mDescription = other->mDescription;
|
||||
mSaleInfo = other->mSaleInfo;
|
||||
mInventoryType = other->mInventoryType;
|
||||
|
|
@ -400,6 +435,7 @@ U32 LLInventoryItem::getCRC32() const
|
|||
//LL_DEBUGS() << "8 crc: " << std::hex << crc << std::dec << LL_ENDL;
|
||||
crc += (U32)mCreationDate;
|
||||
//LL_DEBUGS() << "9 crc: " << std::hex << crc << std::dec << LL_ENDL;
|
||||
crc += mThumbnailUUID.getCRC32();
|
||||
return crc;
|
||||
}
|
||||
|
||||
|
|
@ -655,6 +691,26 @@ BOOL LLInventoryItem::importLegacyStream(std::istream& input_stream)
|
|||
{
|
||||
mType = LLAssetType::lookup(valuestr);
|
||||
}
|
||||
else if (0 == strcmp("metadata", keyword))
|
||||
{
|
||||
LLSD metadata(valuestr);
|
||||
if (metadata.has("thumbnail"))
|
||||
{
|
||||
const LLSD& thumbnail = metadata["thumbnail"];
|
||||
if (thumbnail.has("asset_id"))
|
||||
{
|
||||
setThumbnailUUID(thumbnail["asset_id"].asUUID());
|
||||
}
|
||||
else
|
||||
{
|
||||
setThumbnailUUID(LLUUID::null);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
setThumbnailUUID(LLUUID::null);
|
||||
}
|
||||
}
|
||||
else if(0 == strcmp("inv_type", keyword))
|
||||
{
|
||||
mInventoryType = LLInventoryType::lookup(std::string(valuestr));
|
||||
|
|
@ -744,6 +800,13 @@ BOOL LLInventoryItem::exportLegacyStream(std::ostream& output_stream, BOOL inclu
|
|||
output_stream << "\t\tparent_id\t" << uuid_str << "\n";
|
||||
mPermissions.exportLegacyStream(output_stream);
|
||||
|
||||
if (mThumbnailUUID.notNull())
|
||||
{
|
||||
LLSD metadata;
|
||||
metadata["thumbnail"] = LLSD().with("asset_id", mThumbnailUUID);
|
||||
output_stream << "\t\tmetadata\t" << metadata << "|\n";
|
||||
}
|
||||
|
||||
// Check for permissions to see the asset id, and if so write it
|
||||
// out as an asset id. Otherwise, apply our cheesy encryption.
|
||||
if(include_asset_key)
|
||||
|
|
@ -797,6 +860,11 @@ void LLInventoryItem::asLLSD( LLSD& sd ) const
|
|||
sd[INV_PARENT_ID_LABEL] = mParentUUID;
|
||||
sd[INV_PERMISSIONS_LABEL] = ll_create_sd_from_permissions(mPermissions);
|
||||
|
||||
if (mThumbnailUUID.notNull())
|
||||
{
|
||||
sd[INV_THUMBNAIL_LABEL] = LLSD().with(INV_ASSET_ID_LABEL, mThumbnailUUID);
|
||||
}
|
||||
|
||||
U32 mask = mPermissions.getMaskBase();
|
||||
if(((mask & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED)
|
||||
|| (mAssetUUID.isNull()))
|
||||
|
|
@ -848,6 +916,35 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new)
|
|||
{
|
||||
mParentUUID = sd[w];
|
||||
}
|
||||
mThumbnailUUID.setNull();
|
||||
w = INV_THUMBNAIL_LABEL;
|
||||
if (sd.has(w))
|
||||
{
|
||||
const LLSD &thumbnail_map = sd[w];
|
||||
w = INV_ASSET_ID_LABEL;
|
||||
if (thumbnail_map.has(w))
|
||||
{
|
||||
mThumbnailUUID = thumbnail_map[w];
|
||||
}
|
||||
/* Example:
|
||||
<key> asset_id </key>
|
||||
<uuid> acc0ec86 - 17f2 - 4b92 - ab41 - 6718b1f755f7 </uuid>
|
||||
<key> perms </key>
|
||||
<integer> 8 </integer>
|
||||
<key>service</key>
|
||||
<integer> 3 </integer>
|
||||
<key>version</key>
|
||||
<integer> 1 </key>
|
||||
*/
|
||||
}
|
||||
else
|
||||
{
|
||||
w = INV_THUMBNAIL_ID_LABEL;
|
||||
if (sd.has(w))
|
||||
{
|
||||
mThumbnailUUID = sd[w].asUUID();
|
||||
}
|
||||
}
|
||||
w = INV_PERMISSIONS_LABEL;
|
||||
if (sd.has(w))
|
||||
{
|
||||
|
|
@ -972,135 +1069,6 @@ fail:
|
|||
|
||||
}
|
||||
|
||||
// Deleted LLInventoryItem::exportFileXML() and LLInventoryItem::importXML()
|
||||
// because I can't find any non-test code references to it. 2009-05-04 JC
|
||||
|
||||
S32 LLInventoryItem::packBinaryBucket(U8* bin_bucket, LLPermissions* perm_override) const
|
||||
{
|
||||
// Figure out which permissions to use.
|
||||
LLPermissions perm;
|
||||
if (perm_override)
|
||||
{
|
||||
// Use the permissions override.
|
||||
perm = *perm_override;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use the current permissions.
|
||||
perm = getPermissions();
|
||||
}
|
||||
|
||||
// describe the inventory item
|
||||
char* buffer = (char*) bin_bucket;
|
||||
std::string creator_id_str;
|
||||
|
||||
perm.getCreator().toString(creator_id_str);
|
||||
std::string owner_id_str;
|
||||
perm.getOwner().toString(owner_id_str);
|
||||
std::string last_owner_id_str;
|
||||
perm.getLastOwner().toString(last_owner_id_str);
|
||||
std::string group_id_str;
|
||||
perm.getGroup().toString(group_id_str);
|
||||
std::string asset_id_str;
|
||||
getAssetUUID().toString(asset_id_str);
|
||||
S32 size = sprintf(buffer, /* Flawfinder: ignore */
|
||||
"%d|%d|%s|%s|%s|%s|%s|%x|%x|%x|%x|%x|%s|%s|%d|%d|%x",
|
||||
getType(),
|
||||
getInventoryType(),
|
||||
getName().c_str(),
|
||||
creator_id_str.c_str(),
|
||||
owner_id_str.c_str(),
|
||||
last_owner_id_str.c_str(),
|
||||
group_id_str.c_str(),
|
||||
perm.getMaskBase(),
|
||||
perm.getMaskOwner(),
|
||||
perm.getMaskGroup(),
|
||||
perm.getMaskEveryone(),
|
||||
perm.getMaskNextOwner(),
|
||||
asset_id_str.c_str(),
|
||||
getDescription().c_str(),
|
||||
getSaleInfo().getSaleType(),
|
||||
getSaleInfo().getSalePrice(),
|
||||
getFlags()) + 1;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void LLInventoryItem::unpackBinaryBucket(U8* bin_bucket, S32 bin_bucket_size)
|
||||
{
|
||||
// Early exit on an empty binary bucket.
|
||||
if (bin_bucket_size <= 1) return;
|
||||
|
||||
if (NULL == bin_bucket)
|
||||
{
|
||||
LL_ERRS() << "unpackBinaryBucket failed. bin_bucket is NULL." << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert the bin_bucket into a string.
|
||||
std::vector<char> item_buffer(bin_bucket_size+1);
|
||||
memcpy(&item_buffer[0], bin_bucket, bin_bucket_size); /* Flawfinder: ignore */
|
||||
item_buffer[bin_bucket_size] = '\0';
|
||||
std::string str(&item_buffer[0]);
|
||||
|
||||
LL_DEBUGS() << "item buffer: " << str << LL_ENDL;
|
||||
|
||||
// Tokenize the string.
|
||||
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
|
||||
boost::char_separator<char> sep("|", "", boost::keep_empty_tokens);
|
||||
tokenizer tokens(str, sep);
|
||||
tokenizer::iterator iter = tokens.begin();
|
||||
|
||||
// Extract all values.
|
||||
LLUUID item_id;
|
||||
item_id.generate();
|
||||
setUUID(item_id);
|
||||
|
||||
LLAssetType::EType type;
|
||||
type = (LLAssetType::EType)(atoi((*(iter++)).c_str()));
|
||||
setType( type );
|
||||
|
||||
LLInventoryType::EType inv_type;
|
||||
inv_type = (LLInventoryType::EType)(atoi((*(iter++)).c_str()));
|
||||
setInventoryType( inv_type );
|
||||
|
||||
std::string name((*(iter++)).c_str());
|
||||
rename( name );
|
||||
|
||||
LLUUID creator_id((*(iter++)).c_str());
|
||||
LLUUID owner_id((*(iter++)).c_str());
|
||||
LLUUID last_owner_id((*(iter++)).c_str());
|
||||
LLUUID group_id((*(iter++)).c_str());
|
||||
PermissionMask mask_base = strtoul((*(iter++)).c_str(), NULL, 16);
|
||||
PermissionMask mask_owner = strtoul((*(iter++)).c_str(), NULL, 16);
|
||||
PermissionMask mask_group = strtoul((*(iter++)).c_str(), NULL, 16);
|
||||
PermissionMask mask_every = strtoul((*(iter++)).c_str(), NULL, 16);
|
||||
PermissionMask mask_next = strtoul((*(iter++)).c_str(), NULL, 16);
|
||||
LLPermissions perm;
|
||||
perm.init(creator_id, owner_id, last_owner_id, group_id);
|
||||
perm.initMasks(mask_base, mask_owner, mask_group, mask_every, mask_next);
|
||||
setPermissions(perm);
|
||||
//LL_DEBUGS() << "perm: " << perm << LL_ENDL;
|
||||
|
||||
LLUUID asset_id((*(iter++)).c_str());
|
||||
setAssetUUID(asset_id);
|
||||
|
||||
std::string desc((*(iter++)).c_str());
|
||||
setDescription(desc);
|
||||
|
||||
LLSaleInfo::EForSale sale_type;
|
||||
sale_type = (LLSaleInfo::EForSale)(atoi((*(iter++)).c_str()));
|
||||
S32 price = atoi((*(iter++)).c_str());
|
||||
LLSaleInfo sale_info(sale_type, price);
|
||||
setSaleInfo(sale_info);
|
||||
|
||||
U32 flags = strtoul((*(iter++)).c_str(), NULL, 16);
|
||||
setFlags(flags);
|
||||
|
||||
time_t now = time(NULL);
|
||||
setCreationDate(now);
|
||||
}
|
||||
|
||||
///----------------------------------------------------------------------------
|
||||
/// Class LLInventoryCategory
|
||||
///----------------------------------------------------------------------------
|
||||
|
|
@ -1150,11 +1118,32 @@ void LLInventoryCategory::setPreferredType(LLFolderType::EType type)
|
|||
LLSD LLInventoryCategory::asLLSD() const
|
||||
{
|
||||
LLSD sd = LLSD();
|
||||
sd["item_id"] = mUUID;
|
||||
sd["parent_id"] = mParentUUID;
|
||||
sd[INV_ITEM_ID_LABEL] = mUUID;
|
||||
sd[INV_PARENT_ID_LABEL] = mParentUUID;
|
||||
S8 type = static_cast<S8>(mPreferredType);
|
||||
sd["type"] = type;
|
||||
sd["name"] = mName;
|
||||
sd[INV_ASSET_TYPE_LABEL] = type;
|
||||
sd[INV_NAME_LABEL] = mName;
|
||||
|
||||
if (mThumbnailUUID.notNull())
|
||||
{
|
||||
sd[INV_THUMBNAIL_LABEL] = LLSD().with(INV_ASSET_ID_LABEL, mThumbnailUUID);
|
||||
}
|
||||
|
||||
return sd;
|
||||
}
|
||||
|
||||
LLSD LLInventoryCategory::asAISCreateCatLLSD() const
|
||||
{
|
||||
LLSD sd = LLSD();
|
||||
sd[INV_FOLDER_ID_LABEL_WS] = mUUID;
|
||||
sd[INV_PARENT_ID_LABEL] = mParentUUID;
|
||||
S8 type = static_cast<S8>(mPreferredType);
|
||||
sd[INV_ASSET_TYPE_LABEL_WS] = type;
|
||||
sd[INV_NAME_LABEL] = mName;
|
||||
if (mThumbnailUUID.notNull())
|
||||
{
|
||||
sd[INV_THUMBNAIL_LABEL] = LLSD().with(INV_ASSET_ID_LABEL, mThumbnailUUID);
|
||||
}
|
||||
|
||||
return sd;
|
||||
}
|
||||
|
|
@ -1184,6 +1173,25 @@ bool LLInventoryCategory::fromLLSD(const LLSD& sd)
|
|||
{
|
||||
mParentUUID = sd[w];
|
||||
}
|
||||
mThumbnailUUID.setNull();
|
||||
w = INV_THUMBNAIL_LABEL;
|
||||
if (sd.has(w))
|
||||
{
|
||||
const LLSD &thumbnail_map = sd[w];
|
||||
w = INV_ASSET_ID_LABEL;
|
||||
if (thumbnail_map.has(w))
|
||||
{
|
||||
mThumbnailUUID = thumbnail_map[w];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
w = INV_THUMBNAIL_ID_LABEL;
|
||||
if (sd.has(w))
|
||||
{
|
||||
mThumbnailUUID = sd[w];
|
||||
}
|
||||
}
|
||||
w = INV_ASSET_TYPE_LABEL;
|
||||
if (sd.has(w))
|
||||
{
|
||||
|
|
@ -1275,6 +1283,26 @@ BOOL LLInventoryCategory::importLegacyStream(std::istream& input_stream)
|
|||
LLStringUtil::replaceNonstandardASCII(mName, ' ');
|
||||
LLStringUtil::replaceChar(mName, '|', ' ');
|
||||
}
|
||||
else if (0 == strcmp("metadata", keyword))
|
||||
{
|
||||
LLSD metadata(valuestr);
|
||||
if (metadata.has("thumbnail"))
|
||||
{
|
||||
const LLSD& thumbnail = metadata["thumbnail"];
|
||||
if (thumbnail.has("asset_id"))
|
||||
{
|
||||
setThumbnailUUID(thumbnail["asset_id"].asUUID());
|
||||
}
|
||||
else
|
||||
{
|
||||
setThumbnailUUID(LLUUID::null);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
setThumbnailUUID(LLUUID::null);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS() << "unknown keyword '" << keyword
|
||||
|
|
@ -1295,6 +1323,12 @@ BOOL LLInventoryCategory::exportLegacyStream(std::ostream& output_stream, BOOL)
|
|||
output_stream << "\t\ttype\t" << LLAssetType::lookup(mType) << "\n";
|
||||
output_stream << "\t\tpref_type\t" << LLFolderType::lookup(mPreferredType) << "\n";
|
||||
output_stream << "\t\tname\t" << mName.c_str() << "|\n";
|
||||
if (mThumbnailUUID.notNull())
|
||||
{
|
||||
LLSD metadata;
|
||||
metadata["thumbnail"] = LLSD().with("asset_id", mThumbnailUUID);
|
||||
output_stream << "\t\tmetadata\t" << metadata << "|\n";
|
||||
}
|
||||
output_stream << "\t}\n";
|
||||
return TRUE;
|
||||
}
|
||||
|
|
@ -1308,6 +1342,11 @@ LLSD LLInventoryCategory::exportLLSD() const
|
|||
cat_data[INV_PREFERRED_TYPE_LABEL] = LLFolderType::lookup(mPreferredType);
|
||||
cat_data[INV_NAME_LABEL] = mName;
|
||||
|
||||
if (mThumbnailUUID.notNull())
|
||||
{
|
||||
cat_data[INV_THUMBNAIL_LABEL] = LLSD().with(INV_ASSET_ID_LABEL, mThumbnailUUID);
|
||||
}
|
||||
|
||||
return cat_data;
|
||||
}
|
||||
|
||||
|
|
@ -1329,6 +1368,16 @@ bool LLInventoryCategory::importLLSD(const LLSD& cat_data)
|
|||
{
|
||||
setPreferredType(LLFolderType::lookup(cat_data[INV_PREFERRED_TYPE_LABEL].asString()));
|
||||
}
|
||||
if (cat_data.has(INV_THUMBNAIL_LABEL))
|
||||
{
|
||||
LLUUID thumbnail_uuid;
|
||||
const LLSD &thumbnail_data = cat_data[INV_THUMBNAIL_LABEL];
|
||||
if (thumbnail_data.has(INV_ASSET_ID_LABEL))
|
||||
{
|
||||
thumbnail_uuid = thumbnail_data[INV_ASSET_ID_LABEL].asUUID();
|
||||
}
|
||||
setThumbnailUUID(thumbnail_uuid);
|
||||
}
|
||||
if (cat_data.has(INV_NAME_LABEL))
|
||||
{
|
||||
mName = cat_data[INV_NAME_LABEL].asString();
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ public:
|
|||
virtual const LLUUID& getUUID() const; // inventoryID that this item points to
|
||||
virtual const LLUUID& getLinkedUUID() const; // inventoryID that this item points to, else this item's inventoryID
|
||||
const LLUUID& getParentUUID() const;
|
||||
virtual const LLUUID& getThumbnailUUID() const;
|
||||
virtual const std::string& getName() const;
|
||||
virtual LLAssetType::EType getType() const;
|
||||
LLAssetType::EType getActualType() const; // bypasses indirection for linked items
|
||||
|
|
@ -84,6 +85,7 @@ public:
|
|||
void setUUID(const LLUUID& new_uuid);
|
||||
virtual void rename(const std::string& new_name);
|
||||
void setParent(const LLUUID& new_parent);
|
||||
virtual void setThumbnailUUID(const LLUUID& thumbnail_uuid);
|
||||
void setType(LLAssetType::EType type);
|
||||
virtual void setCreationDate(time_t creation_date_utc); // only stored for items
|
||||
|
||||
|
|
@ -108,6 +110,7 @@ public:
|
|||
protected:
|
||||
LLUUID mUUID;
|
||||
LLUUID mParentUUID; // Parent category. Root categories have LLUUID::NULL.
|
||||
LLUUID mThumbnailUUID;
|
||||
LLAssetType::EType mType;
|
||||
std::string mName;
|
||||
time_t mCreationDate; // seconds from 1/1/1970, UTC
|
||||
|
|
@ -203,9 +206,6 @@ public:
|
|||
// Helper Functions
|
||||
//--------------------------------------------------------------------
|
||||
public:
|
||||
// Pack all information needed to reconstruct this item into the given binary bucket.
|
||||
S32 packBinaryBucket(U8* bin_bucket, LLPermissions* perm_override = NULL) const;
|
||||
void unpackBinaryBucket(U8* bin_bucket, S32 bin_bucket_size);
|
||||
LLSD asLLSD() const;
|
||||
void asLLSD( LLSD& sd ) const;
|
||||
bool fromLLSD(const LLSD& sd, bool is_new = true);
|
||||
|
|
@ -253,6 +253,7 @@ public:
|
|||
LLFolderType::EType getPreferredType() const;
|
||||
void setPreferredType(LLFolderType::EType type);
|
||||
LLSD asLLSD() const;
|
||||
LLSD asAISCreateCatLLSD() const;
|
||||
bool fromLLSD(const LLSD& sd);
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
#include "llfasttimer.h"
|
||||
#include "v3colorutil.h"
|
||||
|
||||
|
||||
//=========================================================================
|
||||
namespace
|
||||
{
|
||||
|
|
@ -133,7 +134,9 @@ const std::string LLSettingsSky::SETTING_SKY_ICE_LEVEL("ice_level");
|
|||
|
||||
const std::string LLSettingsSky::SETTING_REFLECTION_PROBE_AMBIANCE("reflection_probe_ambiance");
|
||||
|
||||
const LLUUID LLSettingsSky::DEFAULT_ASSET_ID("3ae23978-ac82-bcf3-a9cb-ba6e52dcb9ad");
|
||||
const LLUUID LLSettingsSky::DEFAULT_ASSET_ID("651510b8-5f4d-8991-1592-e7eeab2a5a06");
|
||||
|
||||
F32 LLSettingsSky::sAutoAdjustProbeAmbiance = 1.f;
|
||||
|
||||
static const LLUUID DEFAULT_SUN_ID("32bfbcea-24b1-fb9d-1ef9-48a28a63730f"); // dataserver
|
||||
static const LLUUID DEFAULT_MOON_ID("d07f6eed-b96a-47cd-b51d-400ad4a1c428"); // dataserver
|
||||
|
|
@ -1438,7 +1441,7 @@ F32 LLSettingsSky::getReflectionProbeAmbiance(bool auto_adjust) const
|
|||
{
|
||||
if (auto_adjust && canAutoAdjust())
|
||||
{
|
||||
return 1.f;
|
||||
return sAutoAdjustProbeAmbiance;
|
||||
}
|
||||
|
||||
return mSettings[SETTING_REFLECTION_PROBE_AMBIANCE].asReal();
|
||||
|
|
@ -1446,6 +1449,7 @@ F32 LLSettingsSky::getReflectionProbeAmbiance(bool auto_adjust) const
|
|||
|
||||
F32 LLSettingsSky::getTotalReflectionProbeAmbiance(F32 cloud_shadow_scale, bool auto_adjust) const
|
||||
{
|
||||
#if 0
|
||||
// feed cloud shadow back into reflection probe ambiance to mimic pre-reflection-probe behavior
|
||||
// without brightening dark/interior spaces
|
||||
F32 probe_ambiance = getReflectionProbeAmbiance(auto_adjust);
|
||||
|
|
@ -1456,6 +1460,9 @@ F32 LLSettingsSky::getTotalReflectionProbeAmbiance(F32 cloud_shadow_scale, bool
|
|||
}
|
||||
|
||||
return probe_ambiance;
|
||||
#else
|
||||
return getReflectionProbeAmbiance(auto_adjust);
|
||||
#endif
|
||||
}
|
||||
|
||||
F32 LLSettingsSky::getSkyBottomRadius() const
|
||||
|
|
|
|||
|
|
@ -103,6 +103,8 @@ public:
|
|||
|
||||
static const LLUUID DEFAULT_ASSET_ID;
|
||||
|
||||
static F32 sAutoAdjustProbeAmbiance;
|
||||
|
||||
typedef PTR_NAMESPACE::shared_ptr<LLSettingsSky> ptr_t;
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -400,27 +400,7 @@ namespace tut
|
|||
// Deleted LLInventoryItem::exportFileXML() and LLInventoryItem::importXML()
|
||||
// because I can't find any non-test code references to it. 2009-05-04 JC
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void inventory_object::test<10>()
|
||||
{
|
||||
LLPointer<LLInventoryItem> src1 = create_random_inventory_item();
|
||||
U8* bin_bucket = new U8[300];
|
||||
S32 bin_bucket_size = src1->packBinaryBucket(bin_bucket, NULL);
|
||||
|
||||
LLPointer<LLInventoryItem> src2 = new LLInventoryItem();
|
||||
src2->unpackBinaryBucket(bin_bucket, bin_bucket_size);
|
||||
|
||||
ensure_equals("1.sale price::getSalePrice() failed price", src1->getSaleInfo().getSalePrice(), src2->getSaleInfo().getSalePrice());
|
||||
ensure_equals("2.sale type::getSaleType() failed type", src1->getSaleInfo().getSaleType(), src2->getSaleInfo().getSaleType());
|
||||
ensure_equals("3.type::getType() failed", src1->getType(), src2->getType());
|
||||
ensure_equals("4.inventory type::getInventoryType() failed type", src1->getInventoryType(), src2->getInventoryType());
|
||||
ensure_equals("5.name::getName() failed", src1->getName(), src2->getName());
|
||||
ensure_equals("6.description::getDescription() failed", src1->getDescription(), src2->getDescription());
|
||||
ensure_equals("7.flags::getFlags() failed", src1->getFlags(), src2->getFlags());
|
||||
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void inventory_object::test<11>()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ const F32 DEFAULT_NEAR_PLANE = 0.25f;
|
|||
const F32 DEFAULT_FAR_PLANE = 64.f; // far reaches across two horizontal, not diagonal, regions
|
||||
|
||||
const F32 MAX_ASPECT_RATIO = 50.0f;
|
||||
const F32 MAX_NEAR_PLANE = 10.f;
|
||||
const F32 MAX_NEAR_PLANE = 1023.9f; // Clamp the near plane just before the skybox ends
|
||||
const F32 MAX_FAR_PLANE = 100000.0f; //1000000.0f; // Max allowed. Not good Z precision though.
|
||||
const F32 MAX_FAR_CLIP = 512.0f;
|
||||
|
||||
|
|
|
|||
|
|
@ -5626,29 +5626,29 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents)
|
|||
mWeights[dst_idx].loadua(data.w[src_idx].mV);
|
||||
}
|
||||
}
|
||||
|
||||
// put back in normalized coordinate frame
|
||||
LLVector4a inv_scale(1.f/mNormalizedScale.mV[0], 1.f / mNormalizedScale.mV[1], 1.f / mNormalizedScale.mV[2]);
|
||||
LLVector4a scale;
|
||||
scale.load3(mNormalizedScale.mV);
|
||||
scale.getF32ptr()[3] = 1.f;
|
||||
|
||||
for (int i = 0; i < mNumVertices; ++i)
|
||||
{
|
||||
mPositions[i].mul(inv_scale);
|
||||
mNormals[i].mul(scale);
|
||||
mNormals[i].normalize3();
|
||||
F32 w = mTangents[i].getF32ptr()[3];
|
||||
mTangents[i].mul(scale);
|
||||
mTangents[i].normalize3();
|
||||
mTangents[i].getF32ptr()[3] = w;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// blew past the max vertex size limit, use legacy tangent generation which never adds verts
|
||||
createTangents();
|
||||
}
|
||||
|
||||
// put back in normalized coordinate frame
|
||||
LLVector4a inv_scale(1.f/mNormalizedScale.mV[0], 1.f / mNormalizedScale.mV[1], 1.f / mNormalizedScale.mV[2]);
|
||||
LLVector4a scale;
|
||||
scale.load3(mNormalizedScale.mV);
|
||||
scale.getF32ptr()[3] = 1.f;
|
||||
|
||||
for (int i = 0; i < mNumVertices; ++i)
|
||||
{
|
||||
mPositions[i].mul(inv_scale);
|
||||
mNormals[i].mul(scale);
|
||||
mNormals[i].normalize3();
|
||||
F32 w = mTangents[i].getF32ptr()[3];
|
||||
mTangents[i].mul(scale);
|
||||
mTangents[i].normalize3();
|
||||
mTangents[i].getF32ptr()[3] = w;
|
||||
}
|
||||
}
|
||||
|
||||
// cache optimize index buffer
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ BOOL LLVolumeMgr::cleanup()
|
|||
// Note however that LLVolumeLODGroup that contains the volume
|
||||
// also holds a LLPointer so the volume will only go away after
|
||||
// anything holding the volume and the LODGroup are destroyed
|
||||
LLVolume* LLVolumeMgr::refVolume(const LLVolumeParams &volume_params, const S32 detail)
|
||||
LLVolume* LLVolumeMgr::refVolume(const LLVolumeParams &volume_params, const S32 lod)
|
||||
{
|
||||
LLVolumeLODGroup* volgroupp;
|
||||
if (mDataMutex)
|
||||
|
|
@ -109,7 +109,7 @@ LLVolume* LLVolumeMgr::refVolume(const LLVolumeParams &volume_params, const S32
|
|||
{
|
||||
mDataMutex->unlock();
|
||||
}
|
||||
return volgroupp->refLOD(detail);
|
||||
return volgroupp->refLOD(lod);
|
||||
}
|
||||
|
||||
// virtual
|
||||
|
|
@ -287,18 +287,18 @@ bool LLVolumeLODGroup::cleanupRefs()
|
|||
return res;
|
||||
}
|
||||
|
||||
LLVolume* LLVolumeLODGroup::refLOD(const S32 detail)
|
||||
LLVolume* LLVolumeLODGroup::refLOD(const S32 lod)
|
||||
{
|
||||
llassert(detail >=0 && detail < NUM_LODS);
|
||||
mAccessCount[detail]++;
|
||||
llassert(lod >=0 && lod < NUM_LODS);
|
||||
mAccessCount[lod]++;
|
||||
|
||||
mRefs++;
|
||||
if (mVolumeLODs[detail].isNull())
|
||||
if (mVolumeLODs[lod].isNull())
|
||||
{
|
||||
mVolumeLODs[detail] = new LLVolume(mVolumeParams, mDetailScales[detail]);
|
||||
mVolumeLODs[lod] = new LLVolume(mVolumeParams, mDetailScales[lod]);
|
||||
}
|
||||
mLODRefs[detail]++;
|
||||
return mVolumeLODs[detail];
|
||||
mLODRefs[lod]++;
|
||||
return mVolumeLODs[lod];
|
||||
}
|
||||
|
||||
BOOL LLVolumeLODGroup::derefLOD(LLVolume *volumep)
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ set(llmessage_SOURCE_FILES
|
|||
lldispatcher.cpp
|
||||
llexperiencecache.cpp
|
||||
llfiltersd2xmlrpc.cpp
|
||||
llgenericstreamingmessage.cpp
|
||||
llhost.cpp
|
||||
llhttpnode.cpp
|
||||
llhttpsdhandler.cpp
|
||||
|
|
@ -114,6 +115,7 @@ set(llmessage_HEADER_FILES
|
|||
llextendedstatus.h
|
||||
llfiltersd2xmlrpc.h
|
||||
llfollowcamparams.h
|
||||
llgenericstreamingmessage.h
|
||||
llhost.h
|
||||
llhttpnode.h
|
||||
llhttpnodeadapter.h
|
||||
|
|
|
|||
|
|
@ -552,7 +552,9 @@ std::string LLCacheName::buildUsername(const std::string& full_name)
|
|||
|
||||
// if the input wasn't a correctly formatted legacy name, just return it
|
||||
// cleaned up from a potential terminal "Resident"
|
||||
return cleanFullName(full_name);
|
||||
std::string clean_name = cleanFullName(full_name);
|
||||
LLStringUtil::toLower(clean_name);
|
||||
return clean_name;
|
||||
}
|
||||
|
||||
//static
|
||||
|
|
|
|||
|
|
@ -271,7 +271,6 @@ void LLCircuitData::ackReliablePacket(TPACKETID packet_num)
|
|||
|
||||
S32 LLCircuitData::resendUnackedPackets(const F64Seconds now)
|
||||
{
|
||||
S32 resent_packets = 0;
|
||||
LLReliablePacket *packetp;
|
||||
|
||||
|
||||
|
|
@ -375,7 +374,6 @@ S32 LLCircuitData::resendUnackedPackets(const F64Seconds now)
|
|||
// Don't remove it yet, it still gets to try to resend at least once.
|
||||
++iter;
|
||||
}
|
||||
resent_packets++;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -364,7 +364,26 @@ LLUUID LLCoprocedurePool::enqueueCoprocedure(const std::string &name, LLCoproced
|
|||
{
|
||||
LLUUID id(LLUUID::generateNewID());
|
||||
|
||||
LL_INFOS("CoProcMgr") << "Coprocedure(" << name << ") enqueuing with id=" << id.asString() << " in pool \"" << mPoolName << "\" at " << mPending << LL_ENDL;
|
||||
if (mPoolName == "AIS")
|
||||
{
|
||||
// Fetch is going to be spammy.
|
||||
LL_DEBUGS("CoProcMgr", "Inventory") << "Coprocedure(" << name << ") enqueuing with id=" << id.asString() << " in pool \"" << mPoolName
|
||||
<< "\" at "
|
||||
<< mPending << LL_ENDL;
|
||||
|
||||
if (mPending >= (LLCoprocedureManager::DEFAULT_QUEUE_SIZE - 1))
|
||||
{
|
||||
// If it's all used up (not supposed to happen,
|
||||
// fetched should cap it), we are going to crash
|
||||
LL_WARNS("CoProcMgr", "Inventory") << "About to run out of queue space for Coprocedure(" << name
|
||||
<< ") enqueuing with id=" << id.asString() << " Already pending:" << mPending << LL_ENDL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_INFOS("CoProcMgr") << "Coprocedure(" << name << ") enqueuing with id=" << id.asString() << " in pool \"" << mPoolName << "\" at "
|
||||
<< mPending << LL_ENDL;
|
||||
}
|
||||
auto pushed = mPendingCoprocs->try_push(boost::make_shared<QueuedCoproc>(name, id, proc));
|
||||
if (pushed == boost::fibers::channel_op_status::success)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1329,6 +1329,48 @@ void HttpCoroutineAdapter::trivialPostCoro(std::string url, LLCore::HttpRequest:
|
|||
}
|
||||
|
||||
|
||||
/*static*/
|
||||
void HttpCoroutineAdapter::callbackHttpDel(const std::string &url, LLCore::HttpRequest::policy_t policyId, completionCallback_t success,
|
||||
completionCallback_t failure)
|
||||
{
|
||||
LLCoros::instance().launch("HttpCoroutineAdapter::genericDelCoro",
|
||||
boost::bind(&HttpCoroutineAdapter::trivialDelCoro, url, policyId, success, failure));
|
||||
}
|
||||
|
||||
/*static*/
|
||||
void HttpCoroutineAdapter::trivialDelCoro(std::string url, LLCore::HttpRequest::policy_t policyId, completionCallback_t success,
|
||||
completionCallback_t failure)
|
||||
{
|
||||
LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("genericDelCoro", policyId));
|
||||
LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
|
||||
LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
|
||||
|
||||
httpOpts->setWantHeaders(true);
|
||||
|
||||
LL_INFOS("HttpCoroutineAdapter", "genericDelCoro") << "Generic DEL for " << url << LL_ENDL;
|
||||
|
||||
LLSD result = httpAdapter->deleteAndSuspend(httpRequest, url, httpOpts);
|
||||
|
||||
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
|
||||
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
|
||||
|
||||
if (!status)
|
||||
{
|
||||
if (failure)
|
||||
{
|
||||
failure(httpResults);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (success)
|
||||
{
|
||||
success(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // end namespace LLCoreHttpUtil
|
||||
|
||||
|
|
|
|||
|
|
@ -598,6 +598,9 @@ public:
|
|||
callbackHttpPost(url, LLCore::HttpRequest::DEFAULT_POLICY_ID, postData, success, failure);
|
||||
}
|
||||
|
||||
static void callbackHttpDel(const std::string &url, LLCore::HttpRequest::policy_t policyId, completionCallback_t success = NULL,
|
||||
completionCallback_t failure = NULL);
|
||||
|
||||
/// Generic Get and post routines for HTTP via coroutines.
|
||||
/// These static methods do all required setup for the GET or POST operation.
|
||||
/// When the operation completes successfully they will put the success message in the log at INFO level,
|
||||
|
|
@ -659,6 +662,7 @@ private:
|
|||
|
||||
static void trivialGetCoro(std::string url, LLCore::HttpRequest::policy_t policyId, completionCallback_t success, completionCallback_t failure);
|
||||
static void trivialPostCoro(std::string url, LLCore::HttpRequest::policy_t policyId, LLSD postData, completionCallback_t success, completionCallback_t failure);
|
||||
static void trivialDelCoro(std::string url, LLCore::HttpRequest::policy_t policyId, completionCallback_t success, completionCallback_t failure);
|
||||
|
||||
void checkDefaultHeaders(LLCore::HttpHeaders::ptr_t &headers);
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,72 @@
|
|||
/**
|
||||
* @file llgenericstreamingmessage.cpp
|
||||
* @brief Generic Streaming Message helpers. Shared between viewer and simulator.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2023&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2023, 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$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llgenericstreamingmessage.h"
|
||||
|
||||
#include "message.h"
|
||||
|
||||
void LLGenericStreamingMessage::send(LLMessageSystem* msg)
|
||||
{
|
||||
#if 0 // viewer cannot send GenericStreamingMessage
|
||||
msg->newMessageFast(_PREHASH_GenericStreamingMessage);
|
||||
|
||||
if (mData.size() < 1024 * 7)
|
||||
{ // disable warning about big messages unless we're sending a REALLY big message
|
||||
msg->tempDisableWarnAboutBigMessage();
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("Messaging") << "Attempted to send too large GenericStreamingMessage, dropping." << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
msg->nextBlockFast(_PREHASH_MethodData);
|
||||
msg->addU16Fast(_PREHASH_Method, mMethod);
|
||||
msg->nextBlockFast(_PREHASH_DataBlock);
|
||||
msg->addStringFast(_PREHASH_Data, mData.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
void LLGenericStreamingMessage::unpack(LLMessageSystem* msg)
|
||||
{
|
||||
U16* m = (U16*)&mMethod; // squirrely pass enum as U16 by reference
|
||||
msg->getU16Fast(_PREHASH_MethodData, _PREHASH_Method, *m);
|
||||
|
||||
constexpr int MAX_SIZE = 7 * 1024;
|
||||
|
||||
char buffer[MAX_SIZE];
|
||||
|
||||
// NOTE: don't use getStringFast to avoid 1200 byte truncation
|
||||
U32 size = msg->getSizeFast(_PREHASH_DataBlock, _PREHASH_Data);
|
||||
msg->getBinaryDataFast(_PREHASH_DataBlock, _PREHASH_Data, buffer, size, 0, MAX_SIZE);
|
||||
|
||||
mData.assign(buffer, size);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
/**
|
||||
* @file llgenericstreamingmessage.h
|
||||
* @brief Generic Streaming Message helpers. Shared between viewer and simulator.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2023&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2023, 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$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include "stdtypes.h"
|
||||
|
||||
class LLMessageSystem;
|
||||
|
||||
class LLGenericStreamingMessage
|
||||
{
|
||||
public:
|
||||
enum Method : U16
|
||||
{
|
||||
METHOD_GLTF_MATERIAL_OVERRIDE = 0x4175,
|
||||
METHOD_UNKNOWN = 0xFFFF,
|
||||
};
|
||||
|
||||
void send(LLMessageSystem* msg);
|
||||
void unpack(LLMessageSystem* msg);
|
||||
|
||||
Method mMethod = METHOD_UNKNOWN;
|
||||
std::string mData;
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -171,8 +171,9 @@ const U32 ESTATE_ACCESS_MANAGER_REMOVE = 1U << 9;
|
|||
const U32 ESTATE_ACCESS_NO_REPLY = 1U << 10;
|
||||
const U32 ESTATE_ACCESS_FAILED_BAN_ESTATE_MANAGER = 1U << 11;
|
||||
|
||||
const S32 ESTATE_MAX_MANAGERS = 15;
|
||||
const S32 ESTATE_MAX_ACCESS_IDS = 500; // max for access, banned
|
||||
const S32 ESTATE_MAX_MANAGERS = 20;
|
||||
const S32 ESTATE_MAX_ACCESS_IDS = 500; // max for access
|
||||
const S32 ESTATE_MAX_BANNED_IDS = 750; // max for banned
|
||||
const S32 ESTATE_MAX_GROUP_IDS = (S32) ESTATE_ACCESS_MAX_ENTRIES_PER_PACKET;
|
||||
|
||||
// 'Sim Wide Delete' flags
|
||||
|
|
|
|||
|
|
@ -3402,6 +3402,7 @@ typedef std::map<const char*, LLMessageBuilder*> BuilderMap;
|
|||
|
||||
void LLMessageSystem::newMessageFast(const char *name)
|
||||
{
|
||||
//LL_DEBUGS("Messaging") << "creating new message: " << name << LL_ENDL;
|
||||
LLMessageConfig::Flavor message_flavor =
|
||||
LLMessageConfig::getMessageFlavor(name);
|
||||
LLMessageConfig::Flavor server_flavor =
|
||||
|
|
|
|||
|
|
@ -1367,6 +1367,7 @@ char const* const _PREHASH_MuteType = LLMessageStringTable::getInstance()->getSt
|
|||
char const* const _PREHASH_IMViaEMail = LLMessageStringTable::getInstance()->getString("IMViaEMail");
|
||||
char const* const _PREHASH_RentPrice = LLMessageStringTable::getInstance()->getString("RentPrice");
|
||||
char const* const _PREHASH_GenericMessage = LLMessageStringTable::getInstance()->getString("GenericMessage");
|
||||
char const* const _PREHASH_GenericStreamingMessage = LLMessageStringTable::getInstance()->getString("GenericStreamingMessage");
|
||||
char const* const _PREHASH_ChildAgentAlive = LLMessageStringTable::getInstance()->getString("ChildAgentAlive");
|
||||
char const* const _PREHASH_AssetType = LLMessageStringTable::getInstance()->getString("AssetType");
|
||||
char const* const _PREHASH_SpawnPointBlock = LLMessageStringTable::getInstance()->getString("SpawnPointBlock");
|
||||
|
|
|
|||
|
|
@ -1368,6 +1368,7 @@ extern char const* const _PREHASH_MuteType;
|
|||
extern char const* const _PREHASH_IMViaEMail;
|
||||
extern char const* const _PREHASH_RentPrice;
|
||||
extern char const* const _PREHASH_GenericMessage;
|
||||
extern char const* const _PREHASH_GenericStreamingMessage;
|
||||
extern char const* const _PREHASH_ChildAgentAlive;
|
||||
extern char const* const _PREHASH_AssetType;
|
||||
extern char const* const _PREHASH_SpawnPointBlock;
|
||||
|
|
|
|||
|
|
@ -33,8 +33,8 @@ import os
|
|||
import sys
|
||||
from http.server import HTTPServer, BaseHTTPRequestHandler
|
||||
|
||||
from llbase.fastest_elementtree import parse as xml_parse
|
||||
from llbase import llsd
|
||||
from llsd.fastest_elementtree import parse as xml_parse
|
||||
import llsd
|
||||
from testrunner import freeport, run, debug, VERBOSE
|
||||
import time
|
||||
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ set(llprimitive_HEADER_FILES
|
|||
lldaeloader.h
|
||||
llgltfloader.h
|
||||
llgltfmaterial.h
|
||||
llgltfmaterial_templates.h
|
||||
legacy_object_types.h
|
||||
llmaterial.h
|
||||
llmaterialid.h
|
||||
|
|
|
|||
|
|
@ -24,24 +24,28 @@
|
|||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llgltfmaterial.h"
|
||||
|
||||
#include "llsdserialize.h"
|
||||
|
||||
// NOTE -- this should be the one and only place tiny_gltf.h is included
|
||||
#include "tinygltf/tiny_gltf.h"
|
||||
#include "llgltfmaterial_templates.h"
|
||||
|
||||
const char* const LLGLTFMaterial::ASSET_VERSION = "1.1";
|
||||
const char* const LLGLTFMaterial::ASSET_TYPE = "GLTF 2.0";
|
||||
const std::array<std::string, 2> LLGLTFMaterial::ACCEPTED_ASSET_VERSIONS = { "1.0", "1.1" };
|
||||
|
||||
const char* const GLTF_FILE_EXTENSION_TRANSFORM = "KHR_texture_transform";
|
||||
const char* const GLTF_FILE_EXTENSION_TRANSFORM_SCALE = "scale";
|
||||
const char* const GLTF_FILE_EXTENSION_TRANSFORM_OFFSET = "offset";
|
||||
const char* const GLTF_FILE_EXTENSION_TRANSFORM_ROTATION = "rotation";
|
||||
const char* const LLGLTFMaterial::GLTF_FILE_EXTENSION_TRANSFORM = "KHR_texture_transform";
|
||||
const char* const LLGLTFMaterial::GLTF_FILE_EXTENSION_TRANSFORM_SCALE = "scale";
|
||||
const char* const LLGLTFMaterial::GLTF_FILE_EXTENSION_TRANSFORM_OFFSET = "offset";
|
||||
const char* const LLGLTFMaterial::GLTF_FILE_EXTENSION_TRANSFORM_ROTATION = "rotation";
|
||||
|
||||
// special UUID that indicates a null UUID in override data
|
||||
static const LLUUID GLTF_OVERRIDE_NULL_UUID = LLUUID("ffffffff-ffff-ffff-ffff-ffffffffffff");
|
||||
const LLUUID LLGLTFMaterial::GLTF_OVERRIDE_NULL_UUID = LLUUID("ffffffff-ffff-ffff-ffff-ffffffffffff");
|
||||
|
||||
void LLGLTFMaterial::TextureTransform::getPacked(F32 (&packed)[8]) const
|
||||
{
|
||||
|
|
@ -67,14 +71,14 @@ LLGLTFMaterial::LLGLTFMaterial(const LLGLTFMaterial& rhs)
|
|||
|
||||
LLGLTFMaterial& LLGLTFMaterial::operator=(const LLGLTFMaterial& rhs)
|
||||
{
|
||||
//have to do a manual operator= because of LLRefCount
|
||||
//have to do a manual operator= because of LLRefCount
|
||||
mTextureId = rhs.mTextureId;
|
||||
|
||||
mTextureTransform = rhs.mTextureTransform;
|
||||
|
||||
mBaseColor = rhs.mBaseColor;
|
||||
mEmissiveColor = rhs.mEmissiveColor;
|
||||
|
||||
|
||||
mMetallicFactor = rhs.mMetallicFactor;
|
||||
mRoughnessFactor = rhs.mRoughnessFactor;
|
||||
mAlphaCutoff = rhs.mAlphaCutoff;
|
||||
|
|
@ -96,7 +100,7 @@ bool LLGLTFMaterial::operator==(const LLGLTFMaterial& rhs) const
|
|||
|
||||
mBaseColor == rhs.mBaseColor &&
|
||||
mEmissiveColor == rhs.mEmissiveColor &&
|
||||
|
||||
|
||||
mMetallicFactor == rhs.mMetallicFactor &&
|
||||
mRoughnessFactor == rhs.mRoughnessFactor &&
|
||||
mAlphaCutoff == rhs.mAlphaCutoff &&
|
||||
|
|
@ -121,6 +125,7 @@ bool LLGLTFMaterial::fromJSON(const std::string& json, std::string& warn_msg, st
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -189,7 +194,8 @@ void LLGLTFMaterial::setFromModel(const tinygltf::Model& model, S32 mat_index)
|
|||
}
|
||||
}
|
||||
|
||||
LLVector2 vec2_from_json(const tinygltf::Value::Object& object, const char* key, const LLVector2& default_value)
|
||||
// static
|
||||
LLVector2 LLGLTFMaterial::vec2FromJson(const tinygltf::Value::Object& object, const char* key, const LLVector2& default_value)
|
||||
{
|
||||
const auto it = object.find(key);
|
||||
if (it == object.end())
|
||||
|
|
@ -214,7 +220,8 @@ LLVector2 vec2_from_json(const tinygltf::Value::Object& object, const char* key,
|
|||
return value;
|
||||
}
|
||||
|
||||
F32 float_from_json(const tinygltf::Value::Object& object, const char* key, const F32 default_value)
|
||||
// static
|
||||
F32 LLGLTFMaterial::floatFromJson(const tinygltf::Value::Object& object, const char* key, const F32 default_value)
|
||||
{
|
||||
const auto it = object.find(key);
|
||||
if (it == object.end())
|
||||
|
|
@ -229,52 +236,6 @@ F32 float_from_json(const tinygltf::Value::Object& object, const char* key, cons
|
|||
return (F32)real_json.GetNumberAsDouble();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::string gltf_get_texture_image(const tinygltf::Model& model, const T& texture_info)
|
||||
{
|
||||
const S32 texture_idx = texture_info.index;
|
||||
if (texture_idx < 0 || texture_idx >= model.textures.size())
|
||||
{
|
||||
return "";
|
||||
}
|
||||
const tinygltf::Texture& texture = model.textures[texture_idx];
|
||||
|
||||
// Ignore texture.sampler for now
|
||||
|
||||
const S32 image_idx = texture.source;
|
||||
if (image_idx < 0 || image_idx >= model.images.size())
|
||||
{
|
||||
return "";
|
||||
}
|
||||
const tinygltf::Image& image = model.images[image_idx];
|
||||
|
||||
return image.uri;
|
||||
}
|
||||
|
||||
// *NOTE: Use template here as workaround for the different similar texture info classes
|
||||
template<typename T>
|
||||
void LLGLTFMaterial::setFromTexture(const tinygltf::Model& model, const T& texture_info, TextureInfo texture_info_id)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
const std::string uri = gltf_get_texture_image(model, texture_info);
|
||||
mTextureId[texture_info_id].set(uri);
|
||||
|
||||
const tinygltf::Value::Object& extensions_object = texture_info.extensions;
|
||||
const auto transform_it = extensions_object.find(GLTF_FILE_EXTENSION_TRANSFORM);
|
||||
if (transform_it != extensions_object.end())
|
||||
{
|
||||
const tinygltf::Value& transform_json = std::get<1>(*transform_it);
|
||||
if (transform_json.IsObject())
|
||||
{
|
||||
const tinygltf::Value::Object& transform_object = transform_json.Get<tinygltf::Value::Object>();
|
||||
TextureTransform& transform = mTextureTransform[texture_info_id];
|
||||
transform.mOffset = vec2_from_json(transform_object, GLTF_FILE_EXTENSION_TRANSFORM_OFFSET, getDefaultTextureOffset());
|
||||
transform.mScale = vec2_from_json(transform_object, GLTF_FILE_EXTENSION_TRANSFORM_SCALE, getDefaultTextureScale());
|
||||
transform.mRotation = float_from_json(transform_object, GLTF_FILE_EXTENSION_TRANSFORM_ROTATION, getDefaultTextureRotation());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLGLTFMaterial::writeToModel(tinygltf::Model& model, S32 mat_index) const
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
|
|
@ -301,7 +262,7 @@ void LLGLTFMaterial::writeToModel(tinygltf::Model& model, S32 mat_index) const
|
|||
|
||||
material_out.alphaMode = getAlphaMode();
|
||||
material_out.alphaCutoff = mAlphaCutoff;
|
||||
|
||||
|
||||
mBaseColor.write(material_out.pbrMetallicRoughness.baseColorFactor);
|
||||
|
||||
if (mEmissiveColor != LLGLTFMaterial::getDefaultEmissiveColor())
|
||||
|
|
@ -319,7 +280,7 @@ void LLGLTFMaterial::writeToModel(tinygltf::Model& model, S32 mat_index) const
|
|||
tinygltf::Value::Object extras;
|
||||
bool write_extras = false;
|
||||
if (mOverrideAlphaMode && mAlphaMode == getDefaultAlphaMode())
|
||||
{
|
||||
{
|
||||
extras["override_alpha_mode"] = tinygltf::Value(mOverrideAlphaMode);
|
||||
write_extras = true;
|
||||
}
|
||||
|
|
@ -338,57 +299,6 @@ void LLGLTFMaterial::writeToModel(tinygltf::Model& model, S32 mat_index) const
|
|||
model.asset.version = "2.0";
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void gltf_allocate_texture_image(tinygltf::Model& model, T& texture_info, const std::string& uri)
|
||||
{
|
||||
const S32 image_idx = model.images.size();
|
||||
model.images.emplace_back();
|
||||
model.images[image_idx].uri = uri;
|
||||
|
||||
// The texture, not to be confused with the texture info
|
||||
const S32 texture_idx = model.textures.size();
|
||||
model.textures.emplace_back();
|
||||
tinygltf::Texture& texture = model.textures[texture_idx];
|
||||
texture.source = image_idx;
|
||||
|
||||
texture_info.index = texture_idx;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void LLGLTFMaterial::writeToTexture(tinygltf::Model& model, T& texture_info, TextureInfo texture_info_id, bool force_write) const
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
const LLUUID& texture_id = mTextureId[texture_info_id];
|
||||
const TextureTransform& transform = mTextureTransform[texture_info_id];
|
||||
const bool is_blank_transform = transform == sDefault.mTextureTransform[0];
|
||||
// Check if this material matches all the fallback values, and if so, then
|
||||
// skip including it to reduce material size
|
||||
if (!force_write && texture_id.isNull() && is_blank_transform)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// tinygltf will discard this texture info if there is no valid texture,
|
||||
// causing potential loss of information for overrides, so ensure one is
|
||||
// defined. -Cosmic,2023-01-30
|
||||
gltf_allocate_texture_image(model, texture_info, texture_id.asString());
|
||||
|
||||
if (!is_blank_transform)
|
||||
{
|
||||
tinygltf::Value::Object transform_map;
|
||||
transform_map[GLTF_FILE_EXTENSION_TRANSFORM_OFFSET] = tinygltf::Value(tinygltf::Value::Array({
|
||||
tinygltf::Value(transform.mOffset.mV[VX]),
|
||||
tinygltf::Value(transform.mOffset.mV[VY])
|
||||
}));
|
||||
transform_map[GLTF_FILE_EXTENSION_TRANSFORM_SCALE] = tinygltf::Value(tinygltf::Value::Array({
|
||||
tinygltf::Value(transform.mScale.mV[VX]),
|
||||
tinygltf::Value(transform.mScale.mV[VY])
|
||||
}));
|
||||
transform_map[GLTF_FILE_EXTENSION_TRANSFORM_ROTATION] = tinygltf::Value(transform.mRotation);
|
||||
texture_info.extensions[GLTF_FILE_EXTENSION_TRANSFORM] = tinygltf::Value(transform_map);
|
||||
}
|
||||
}
|
||||
|
||||
void LLGLTFMaterial::sanitizeAssetMaterial()
|
||||
{
|
||||
mTextureTransform = sDefault.mTextureTransform;
|
||||
|
|
@ -402,19 +312,19 @@ bool LLGLTFMaterial::setBaseMaterial()
|
|||
return *this != old_override;
|
||||
}
|
||||
|
||||
bool LLGLTFMaterial::isClearedForBaseMaterial()
|
||||
{
|
||||
LLGLTFMaterial cleared_override = sDefault;
|
||||
cleared_override.setBaseMaterial(*this);
|
||||
return *this == cleared_override;
|
||||
}
|
||||
|
||||
// For material overrides only. Copies transforms from the old override.
|
||||
void LLGLTFMaterial::setBaseMaterial(const LLGLTFMaterial& old_override_mat)
|
||||
{
|
||||
mTextureTransform = old_override_mat.mTextureTransform;
|
||||
}
|
||||
|
||||
bool LLGLTFMaterial::isClearedForBaseMaterial() const
|
||||
{
|
||||
LLGLTFMaterial cleared_override = sDefault;
|
||||
cleared_override.setBaseMaterial(*this);
|
||||
return *this == cleared_override;
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
void LLGLTFMaterial::hackOverrideUUID(LLUUID& id)
|
||||
|
|
@ -515,7 +425,7 @@ void LLGLTFMaterial::setAlphaMode(const std::string& mode, bool for_override)
|
|||
{
|
||||
m = ALPHA_MODE_BLEND;
|
||||
}
|
||||
|
||||
|
||||
setAlphaMode(m, for_override);
|
||||
}
|
||||
|
||||
|
|
@ -693,6 +603,159 @@ void LLGLTFMaterial::applyOverride(const LLGLTFMaterial& override_mat)
|
|||
}
|
||||
}
|
||||
|
||||
void LLGLTFMaterial::getOverrideLLSD(const LLGLTFMaterial& override_mat, LLSD& data)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
llassert(data.isUndefined());
|
||||
|
||||
// make every effort to shave bytes here
|
||||
|
||||
for (int i = 0; i < GLTF_TEXTURE_INFO_COUNT; ++i)
|
||||
{
|
||||
LLUUID& texture_id = mTextureId[i];
|
||||
const LLUUID& override_texture_id = override_mat.mTextureId[i];
|
||||
if (override_texture_id.notNull() && override_texture_id != texture_id)
|
||||
{
|
||||
data["tex"][i] = LLSD::UUID(override_texture_id);
|
||||
}
|
||||
}
|
||||
|
||||
if (override_mat.mBaseColor != getDefaultBaseColor())
|
||||
{
|
||||
data["bc"] = override_mat.mBaseColor.getValue();
|
||||
}
|
||||
|
||||
if (override_mat.mEmissiveColor != getDefaultEmissiveColor())
|
||||
{
|
||||
data["ec"] = override_mat.mEmissiveColor.getValue();
|
||||
}
|
||||
|
||||
if (override_mat.mMetallicFactor != getDefaultMetallicFactor())
|
||||
{
|
||||
data["mf"] = override_mat.mMetallicFactor;
|
||||
}
|
||||
|
||||
if (override_mat.mRoughnessFactor != getDefaultRoughnessFactor())
|
||||
{
|
||||
data["rf"] = override_mat.mRoughnessFactor;
|
||||
}
|
||||
|
||||
if (override_mat.mAlphaMode != getDefaultAlphaMode() || override_mat.mOverrideAlphaMode)
|
||||
{
|
||||
data["am"] = override_mat.mAlphaMode;
|
||||
}
|
||||
|
||||
if (override_mat.mAlphaCutoff != getDefaultAlphaCutoff())
|
||||
{
|
||||
data["ac"] = override_mat.mAlphaCutoff;
|
||||
}
|
||||
|
||||
if (override_mat.mDoubleSided != getDefaultDoubleSided() || override_mat.mOverrideDoubleSided)
|
||||
{
|
||||
data["ds"] = override_mat.mDoubleSided;
|
||||
}
|
||||
|
||||
for (int i = 0; i < GLTF_TEXTURE_INFO_COUNT; ++i)
|
||||
{
|
||||
if (override_mat.mTextureTransform[i].mOffset != getDefaultTextureOffset())
|
||||
{
|
||||
data["ti"][i]["o"] = override_mat.mTextureTransform[i].mOffset.getValue();
|
||||
}
|
||||
|
||||
if (override_mat.mTextureTransform[i].mScale != getDefaultTextureScale())
|
||||
{
|
||||
data["ti"][i]["s"] = override_mat.mTextureTransform[i].mScale.getValue();
|
||||
}
|
||||
|
||||
if (override_mat.mTextureTransform[i].mRotation != getDefaultTextureRotation())
|
||||
{
|
||||
data["ti"][i]["r"] = override_mat.mTextureTransform[i].mRotation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LLGLTFMaterial::applyOverrideLLSD(const LLSD& data)
|
||||
{
|
||||
const LLSD& tex = data["tex"];
|
||||
|
||||
if (tex.isArray())
|
||||
{
|
||||
for (int i = 0; i < tex.size(); ++i)
|
||||
{
|
||||
mTextureId[i] = tex[i].asUUID();
|
||||
}
|
||||
}
|
||||
|
||||
const LLSD& bc = data["bc"];
|
||||
if (bc.isDefined())
|
||||
{
|
||||
mBaseColor.setValue(bc);
|
||||
}
|
||||
|
||||
const LLSD& ec = data["ec"];
|
||||
if (ec.isDefined())
|
||||
{
|
||||
mEmissiveColor.setValue(ec);
|
||||
}
|
||||
|
||||
const LLSD& mf = data["mf"];
|
||||
if (mf.isReal())
|
||||
{
|
||||
mMetallicFactor = mf.asReal();
|
||||
}
|
||||
|
||||
const LLSD& rf = data["rf"];
|
||||
if (rf.isReal())
|
||||
{
|
||||
mRoughnessFactor = rf.asReal();
|
||||
}
|
||||
|
||||
const LLSD& am = data["am"];
|
||||
if (am.isInteger())
|
||||
{
|
||||
mAlphaMode = (AlphaMode) am.asInteger();
|
||||
}
|
||||
|
||||
const LLSD& ac = data["ac"];
|
||||
if (ac.isReal())
|
||||
{
|
||||
mAlphaCutoff = ac.asReal();
|
||||
}
|
||||
|
||||
const LLSD& ds = data["ds"];
|
||||
if (ds.isBoolean())
|
||||
{
|
||||
mDoubleSided = ds.asBoolean();
|
||||
mOverrideDoubleSided = true;
|
||||
}
|
||||
|
||||
const LLSD& ti = data["ti"];
|
||||
if (ti.isArray())
|
||||
{
|
||||
for (int i = 0; i < GLTF_TEXTURE_INFO_COUNT; ++i)
|
||||
{
|
||||
const LLSD& o = ti[i]["o"];
|
||||
if (o.isDefined())
|
||||
{
|
||||
mTextureTransform[i].mOffset.setValue(o);
|
||||
}
|
||||
|
||||
const LLSD& s = ti[i]["s"];
|
||||
if (s.isDefined())
|
||||
{
|
||||
mTextureTransform[i].mScale.setValue(s);
|
||||
}
|
||||
|
||||
const LLSD& r = ti[i]["r"];
|
||||
if (r.isReal())
|
||||
{
|
||||
mTextureTransform[i].mRotation = r.asReal();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LLUUID LLGLTFMaterial::getHash() const
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
|
||||
|
|
|
|||
|
|
@ -35,10 +35,13 @@
|
|||
#include "hbxxh.h"
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
namespace tinygltf
|
||||
{
|
||||
class Model;
|
||||
struct TextureInfo;
|
||||
class Value;
|
||||
}
|
||||
|
||||
class LLTextureEntry;
|
||||
|
|
@ -52,6 +55,9 @@ public:
|
|||
|
||||
static const char* const ASSET_VERSION;
|
||||
static const char* const ASSET_TYPE;
|
||||
// Max allowed size of a GLTF material asset or override, when serialized
|
||||
// as a minified JSON string
|
||||
static constexpr size_t MAX_ASSET_LENGTH = 2048;
|
||||
static const std::array<std::string, 2> ACCEPTED_ASSET_VERSIONS;
|
||||
static bool isAcceptedVersion(const std::string& version) { return std::find(ACCEPTED_ASSET_VERSIONS.cbegin(), ACCEPTED_ASSET_VERSIONS.cend(), version) != ACCEPTED_ASSET_VERSIONS.cend(); }
|
||||
|
||||
|
|
@ -64,6 +70,7 @@ public:
|
|||
void getPacked(F32 (&packed)[8]) const;
|
||||
|
||||
bool operator==(const TextureTransform& other) const;
|
||||
bool operator!=(const TextureTransform& other) const { return !(*this == other); }
|
||||
};
|
||||
|
||||
enum AlphaMode
|
||||
|
|
@ -96,8 +103,13 @@ public:
|
|||
GLTF_TEXTURE_INFO_COUNT
|
||||
};
|
||||
|
||||
std::array<LLUUID, GLTF_TEXTURE_INFO_COUNT> mTextureId;
|
||||
static const char* const GLTF_FILE_EXTENSION_TRANSFORM;
|
||||
static const char* const GLTF_FILE_EXTENSION_TRANSFORM_SCALE;
|
||||
static const char* const GLTF_FILE_EXTENSION_TRANSFORM_OFFSET;
|
||||
static const char* const GLTF_FILE_EXTENSION_TRANSFORM_ROTATION;
|
||||
static const LLUUID GLTF_OVERRIDE_NULL_UUID;
|
||||
|
||||
std::array<LLUUID, GLTF_TEXTURE_INFO_COUNT> mTextureId;
|
||||
std::array<TextureTransform, GLTF_TEXTURE_INFO_COUNT> mTextureTransform;
|
||||
|
||||
// NOTE: initialize values to defaults according to the GLTF spec
|
||||
|
|
@ -137,7 +149,7 @@ public:
|
|||
void setAlphaMode(S32 mode, bool for_override = false);
|
||||
void setDoubleSided(bool double_sided, bool for_override = false);
|
||||
|
||||
//NOTE: texture offsets only exist in overrides, so "for_override" is not needed
|
||||
// *NOTE: texture offsets only exist in overrides, so "for_override" is not needed
|
||||
|
||||
void setTextureOffset(TextureInfo texture_info, const LLVector2& offset);
|
||||
void setTextureScale(TextureInfo texture_info, const LLVector2& scale);
|
||||
|
|
@ -155,7 +167,6 @@ public:
|
|||
static LLVector2 getDefaultTextureScale();
|
||||
static F32 getDefaultTextureRotation();
|
||||
|
||||
|
||||
static void hackOverrideUUID(LLUUID& id);
|
||||
static void applyOverrideUUID(LLUUID& dst_id, const LLUUID& override_id);
|
||||
|
||||
|
|
@ -164,7 +175,7 @@ public:
|
|||
void setAlphaMode(const std::string& mode, bool for_override = false);
|
||||
|
||||
const char* getAlphaMode() const;
|
||||
|
||||
|
||||
// set the contents of this LLGLTFMaterial from the given json
|
||||
// returns true if successful
|
||||
// if unsuccessful, the contents of this LLGLTFMaterial should be left unchanged and false is returned
|
||||
|
|
@ -185,6 +196,14 @@ public:
|
|||
void writeToModel(tinygltf::Model& model, S32 mat_index) const;
|
||||
|
||||
void applyOverride(const LLGLTFMaterial& override_mat);
|
||||
|
||||
// apply the given LLSD override data
|
||||
void applyOverrideLLSD(const LLSD& data);
|
||||
|
||||
// Get the given override on this LLGLTFMaterial as LLSD
|
||||
// override_mat -- the override source data
|
||||
// data -- output LLSD object (should be passed in empty)
|
||||
void getOverrideLLSD(const LLGLTFMaterial& override_mat, LLSD& data);
|
||||
|
||||
// For base materials only (i.e. assets). Clears transforms to
|
||||
// default since they're not supported in assets yet.
|
||||
|
|
@ -193,21 +212,29 @@ public:
|
|||
// For material overrides only. Clears most properties to
|
||||
// default/fallthrough, but preserves the transforms.
|
||||
bool setBaseMaterial();
|
||||
void setBaseMaterial(const LLGLTFMaterial& old_override_mat);
|
||||
// True if setBaseMaterial() was just called
|
||||
bool isClearedForBaseMaterial();
|
||||
bool isClearedForBaseMaterial() const;
|
||||
|
||||
// For local materials, they have to keep track of where
|
||||
// they are assigned to for full updates
|
||||
virtual void addTextureEntry(LLTextureEntry* te) {};
|
||||
virtual void removeTextureEntry(LLTextureEntry* te) {};
|
||||
|
||||
private:
|
||||
protected:
|
||||
static LLVector2 vec2FromJson(const std::map<std::string, tinygltf::Value>& object, const char* key, const LLVector2& default_value);
|
||||
static F32 floatFromJson(const std::map<std::string, tinygltf::Value>& object, const char* key, const F32 default_value);
|
||||
|
||||
template<typename T>
|
||||
static void allocateTextureImage(tinygltf::Model& model, T& texture_info, const std::string& uri);
|
||||
|
||||
template<typename T>
|
||||
void setFromTexture(const tinygltf::Model& model, const T& texture_info, TextureInfo texture_info_id);
|
||||
template<typename T>
|
||||
static void setFromTexture(const tinygltf::Model& model, const T& texture_info, LLUUID& texture_id, TextureTransform& transform);
|
||||
|
||||
template<typename T>
|
||||
void writeToTexture(tinygltf::Model& model, T& texture_info, TextureInfo texture_info_id, bool force_write = false) const;
|
||||
|
||||
void setBaseMaterial(const LLGLTFMaterial& old_override_mat);
|
||||
template<typename T>
|
||||
static void writeToTexture(tinygltf::Model& model, T& texture_info, const LLUUID& texture_id, const TextureTransform& transform, bool force_write = false);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,142 @@
|
|||
/**
|
||||
* @file llgltfmaterial_templates.h
|
||||
* @brief Material template definition
|
||||
*
|
||||
* $LicenseInfo:firstyear=2023&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2023, 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$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "llgltfmaterial.h"
|
||||
|
||||
// Use templates here as workaround for the different similar texture info classes in tinygltf
|
||||
// Includer must first include tiny_gltf.h with the desired flags
|
||||
|
||||
template<typename T>
|
||||
std::string gltf_get_texture_image(const tinygltf::Model& model, const T& texture_info)
|
||||
{
|
||||
const S32 texture_idx = texture_info.index;
|
||||
if (texture_idx < 0 || texture_idx >= model.textures.size())
|
||||
{
|
||||
return "";
|
||||
}
|
||||
const tinygltf::Texture& texture = model.textures[texture_idx];
|
||||
|
||||
// Ignore texture.sampler for now
|
||||
|
||||
const S32 image_idx = texture.source;
|
||||
if (image_idx < 0 || image_idx >= model.images.size())
|
||||
{
|
||||
return "";
|
||||
}
|
||||
const tinygltf::Image& image = model.images[image_idx];
|
||||
|
||||
return image.uri;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void LLGLTFMaterial::setFromTexture(const tinygltf::Model& model, const T& texture_info, TextureInfo texture_info_id)
|
||||
{
|
||||
setFromTexture(model, texture_info, mTextureId[texture_info_id], mTextureTransform[texture_info_id]);
|
||||
const std::string uri = gltf_get_texture_image(model, texture_info);
|
||||
}
|
||||
|
||||
// static
|
||||
template<typename T>
|
||||
void LLGLTFMaterial::setFromTexture(const tinygltf::Model& model, const T& texture_info, LLUUID& texture_id, TextureTransform& transform)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
const std::string uri = gltf_get_texture_image(model, texture_info);
|
||||
texture_id.set(uri);
|
||||
|
||||
const tinygltf::Value::Object& extensions_object = texture_info.extensions;
|
||||
const auto transform_it = extensions_object.find(GLTF_FILE_EXTENSION_TRANSFORM);
|
||||
if (transform_it != extensions_object.end())
|
||||
{
|
||||
const tinygltf::Value& transform_json = std::get<1>(*transform_it);
|
||||
if (transform_json.IsObject())
|
||||
{
|
||||
const tinygltf::Value::Object& transform_object = transform_json.Get<tinygltf::Value::Object>();
|
||||
transform.mOffset = vec2FromJson(transform_object, GLTF_FILE_EXTENSION_TRANSFORM_OFFSET, getDefaultTextureOffset());
|
||||
transform.mScale = vec2FromJson(transform_object, GLTF_FILE_EXTENSION_TRANSFORM_SCALE, getDefaultTextureScale());
|
||||
transform.mRotation = floatFromJson(transform_object, GLTF_FILE_EXTENSION_TRANSFORM_ROTATION, getDefaultTextureRotation());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
template<typename T>
|
||||
void LLGLTFMaterial::allocateTextureImage(tinygltf::Model& model, T& texture_info, const std::string& uri)
|
||||
{
|
||||
const S32 image_idx = model.images.size();
|
||||
model.images.emplace_back();
|
||||
model.images[image_idx].uri = uri;
|
||||
|
||||
// The texture, not to be confused with the texture info
|
||||
const S32 texture_idx = model.textures.size();
|
||||
model.textures.emplace_back();
|
||||
tinygltf::Texture& texture = model.textures[texture_idx];
|
||||
texture.source = image_idx;
|
||||
|
||||
texture_info.index = texture_idx;
|
||||
}
|
||||
|
||||
// static
|
||||
template<typename T>
|
||||
void LLGLTFMaterial::writeToTexture(tinygltf::Model& model, T& texture_info, TextureInfo texture_info_id, bool force_write) const
|
||||
{
|
||||
writeToTexture(model, texture_info, mTextureId[texture_info_id], mTextureTransform[texture_info_id], force_write);
|
||||
}
|
||||
|
||||
// static
|
||||
template<typename T>
|
||||
void LLGLTFMaterial::writeToTexture(tinygltf::Model& model, T& texture_info, const LLUUID& texture_id, const TextureTransform& transform, bool force_write)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
const bool is_blank_transform = transform == sDefault.mTextureTransform[0];
|
||||
// Check if this material matches all the fallback values, and if so, then
|
||||
// skip including it to reduce material size
|
||||
if (!force_write && texture_id.isNull() && is_blank_transform)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// tinygltf will discard this texture info if there is no valid texture,
|
||||
// causing potential loss of information for overrides, so ensure one is
|
||||
// defined. -Cosmic,2023-01-30
|
||||
allocateTextureImage(model, texture_info, texture_id.asString());
|
||||
|
||||
if (!is_blank_transform)
|
||||
{
|
||||
tinygltf::Value::Object transform_map;
|
||||
transform_map[GLTF_FILE_EXTENSION_TRANSFORM_OFFSET] = tinygltf::Value(tinygltf::Value::Array({
|
||||
tinygltf::Value(transform.mOffset.mV[VX]),
|
||||
tinygltf::Value(transform.mOffset.mV[VY])
|
||||
}));
|
||||
transform_map[GLTF_FILE_EXTENSION_TRANSFORM_SCALE] = tinygltf::Value(tinygltf::Value::Array({
|
||||
tinygltf::Value(transform.mScale.mV[VX]),
|
||||
tinygltf::Value(transform.mScale.mV[VY])
|
||||
}));
|
||||
transform_map[GLTF_FILE_EXTENSION_TRANSFORM_ROTATION] = tinygltf::Value(transform.mRotation);
|
||||
texture_info.extensions[GLTF_FILE_EXTENSION_TRANSFORM] = tinygltf::Value(transform_map);
|
||||
}
|
||||
}
|
||||
|
|
@ -332,17 +332,6 @@ void LLMaterial::setAlphaMaskCutoff(U8 cutoff)
|
|||
mAlphaMaskCutoff = cutoff;
|
||||
}
|
||||
|
||||
LLUUID LLMaterial::getMaterialID() const
|
||||
{
|
||||
// TODO - not null
|
||||
return LLUUID::null;
|
||||
}
|
||||
|
||||
void LLMaterial::setMaterialID(const LLUUID &material_id)
|
||||
{
|
||||
// TODO - set
|
||||
}
|
||||
|
||||
LLSD LLMaterial::asLLSD() const
|
||||
{
|
||||
LLSD material_data;
|
||||
|
|
@ -438,18 +427,18 @@ bool LLMaterial::operator != (const LLMaterial& rhs) const
|
|||
}
|
||||
|
||||
|
||||
U32 LLMaterial::getShaderMask(U32 alpha_mode)
|
||||
U32 LLMaterial::getShaderMask(U32 alpha_mode, BOOL is_alpha)
|
||||
{ //NEVER incorporate this value into the message system -- this function will vary depending on viewer implementation
|
||||
U32 ret = 0;
|
||||
|
||||
//two least significant bits are "diffuse alpha mode"
|
||||
if (alpha_mode != DIFFUSE_ALPHA_MODE_DEFAULT)
|
||||
//two least significant bits are "diffuse alpha mode"
|
||||
U32 ret = alpha_mode;
|
||||
if (ret == DIFFUSE_ALPHA_MODE_DEFAULT)
|
||||
{
|
||||
ret = alpha_mode;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = getDiffuseAlphaMode();
|
||||
ret = getDiffuseAlphaMode();
|
||||
if (ret == DIFFUSE_ALPHA_MODE_BLEND && !is_alpha)
|
||||
{
|
||||
ret = DIFFUSE_ALPHA_MODE_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
llassert(ret < SHADER_COUNT);
|
||||
|
|
|
|||
|
|
@ -115,8 +115,6 @@ public:
|
|||
void setDiffuseAlphaMode(U8 alpha_mode);
|
||||
U8 getAlphaMaskCutoff() const;
|
||||
void setAlphaMaskCutoff(U8 cutoff);
|
||||
LLUUID getMaterialID() const;
|
||||
void setMaterialID(LLUUID const & material_id);
|
||||
|
||||
bool isNull() const;
|
||||
static const LLMaterial null;
|
||||
|
|
@ -124,7 +122,7 @@ public:
|
|||
bool operator == (const LLMaterial& rhs) const;
|
||||
bool operator != (const LLMaterial& rhs) const;
|
||||
|
||||
U32 getShaderMask(U32 alpha_mode = DIFFUSE_ALPHA_MODE_DEFAULT);
|
||||
U32 getShaderMask(U32 alpha_mode, BOOL is_alpha);
|
||||
LLUUID getHash() const;
|
||||
|
||||
protected:
|
||||
|
|
|
|||
|
|
@ -67,6 +67,14 @@ public:
|
|||
|
||||
static const LLMaterialID null;
|
||||
|
||||
// Returns a 64 bits digest of the material Id, by XORing its two 64 bits
|
||||
// long words. HB
|
||||
inline U64 getDigest64() const
|
||||
{
|
||||
U64* tmp = (U64*)mID;
|
||||
return tmp[0] ^ tmp[1];
|
||||
}
|
||||
|
||||
private:
|
||||
void parseFromBinary(const LLSD::Binary& pMaterialID);
|
||||
void copyFromOtherMaterialID(const LLMaterialID& pOtherMaterialID);
|
||||
|
|
@ -75,5 +83,23 @@ private:
|
|||
U8 mID[MATERIAL_ID_SIZE];
|
||||
} ;
|
||||
|
||||
// std::hash implementation for LLMaterialID
|
||||
namespace std
|
||||
{
|
||||
template<> struct hash<LLMaterialID>
|
||||
{
|
||||
inline size_t operator()(const LLMaterialID& id) const noexcept
|
||||
{
|
||||
return (size_t)id.getDigest64();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// For use with boost containers.
|
||||
inline size_t hash_value(const LLMaterialID& id) noexcept
|
||||
{
|
||||
return (size_t)id.getDigest64();
|
||||
}
|
||||
|
||||
#endif // LL_LLMATERIALID_H
|
||||
|
||||
|
|
|
|||
|
|
@ -85,6 +85,8 @@ const F32 LIGHT_MAX_CUTOFF = 180.f;
|
|||
const F32 REFLECTION_PROBE_MIN_AMBIANCE = 0.f;
|
||||
const F32 REFLECTION_PROBE_MAX_AMBIANCE = 100.f;
|
||||
const F32 REFLECTION_PROBE_DEFAULT_AMBIANCE = 0.f;
|
||||
// *NOTE: Clip distances are clamped in LLCamera::setNear. The max clip
|
||||
// distance is currently limited by the skybox
|
||||
const F32 REFLECTION_PROBE_MIN_CLIP_DISTANCE = 0.f;
|
||||
const F32 REFLECTION_PROBE_MAX_CLIP_DISTANCE = 1024.f;
|
||||
const F32 REFLECTION_PROBE_DEFAULT_CLIP_DISTANCE = 0.f;
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ set(llrender_SOURCE_FILES
|
|||
llrendertarget.cpp
|
||||
llshadermgr.cpp
|
||||
lltexture.cpp
|
||||
lltexturemanagerbridge.cpp
|
||||
lluiimage.cpp
|
||||
llvertexbuffer.cpp
|
||||
llglcommonfunc.cpp
|
||||
|
|
@ -58,6 +59,7 @@ set(llrender_HEADER_FILES
|
|||
llrendersphere.h
|
||||
llshadermgr.h
|
||||
lltexture.h
|
||||
lltexturemanagerbridge.h
|
||||
lluiimage.h
|
||||
lluiimage.inl
|
||||
llvertexbuffer.h
|
||||
|
|
|
|||
|
|
@ -494,7 +494,7 @@ F32 LLFontGL::getWidthF32(const std::string& utf8text, S32 begin_offset, S32 max
|
|||
return getWidthF32(wtext.c_str(), begin_offset, max_chars);
|
||||
}
|
||||
|
||||
F32 LLFontGL::getWidthF32(const llwchar* wchars, S32 begin_offset, S32 max_chars) const
|
||||
F32 LLFontGL::getWidthF32(const llwchar* wchars, S32 begin_offset, S32 max_chars, bool no_padding) const
|
||||
{
|
||||
const S32 LAST_CHARACTER = LLFontFreetype::LAST_CHAR_FULL;
|
||||
|
||||
|
|
@ -517,12 +517,15 @@ F32 LLFontGL::getWidthF32(const llwchar* wchars, S32 begin_offset, S32 max_chars
|
|||
|
||||
F32 advance = mFontFreetype->getXAdvance(fgi);
|
||||
|
||||
// for the last character we want to measure the greater of its width and xadvance values
|
||||
// so keep track of the difference between these values for the each character we measure
|
||||
// so we can fix things up at the end
|
||||
width_padding = llmax( 0.f, // always use positive padding amount
|
||||
width_padding - advance, // previous padding left over after advance of current character
|
||||
(F32)(fgi->mWidth + fgi->mXBearing) - advance); // difference between width of this character and advance to next character
|
||||
if (!no_padding)
|
||||
{
|
||||
// for the last character we want to measure the greater of its width and xadvance values
|
||||
// so keep track of the difference between these values for the each character we measure
|
||||
// so we can fix things up at the end
|
||||
width_padding = llmax(0.f, // always use positive padding amount
|
||||
width_padding - advance, // previous padding left over after advance of current character
|
||||
(F32)(fgi->mWidth + fgi->mXBearing) - advance); // difference between width of this character and advance to next character
|
||||
}
|
||||
|
||||
cur_x += advance;
|
||||
llwchar next_char = wchars[i+1];
|
||||
|
|
@ -539,8 +542,11 @@ F32 LLFontGL::getWidthF32(const llwchar* wchars, S32 begin_offset, S32 max_chars
|
|||
cur_x = (F32)ll_round(cur_x);
|
||||
}
|
||||
|
||||
// add in extra pixels for last character's width past its xadvance
|
||||
cur_x += width_padding;
|
||||
if (!no_padding)
|
||||
{
|
||||
// add in extra pixels for last character's width past its xadvance
|
||||
cur_x += width_padding;
|
||||
}
|
||||
|
||||
return cur_x / sScaleX;
|
||||
}
|
||||
|
|
@ -1017,6 +1023,20 @@ LLFontGL* LLFontGL::getFontSansSerifSmall()
|
|||
return fontp;
|
||||
}
|
||||
|
||||
//static
|
||||
LLFontGL* LLFontGL::getFontSansSerifSmallBold()
|
||||
{
|
||||
static LLFontGL* fontp = getFont(LLFontDescriptor("SansSerif","Small",BOLD));
|
||||
return fontp;
|
||||
}
|
||||
|
||||
//static
|
||||
LLFontGL* LLFontGL::getFontSansSerifSmallItalic()
|
||||
{
|
||||
static LLFontGL* fontp = getFont(LLFontDescriptor("SansSerif","Small",ITALIC));
|
||||
return fontp;
|
||||
}
|
||||
|
||||
//static
|
||||
LLFontGL* LLFontGL::getFontSansSerif()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ public:
|
|||
F32 getWidthF32(const std::string& utf8text) const;
|
||||
F32 getWidthF32(const llwchar* wchars) const;
|
||||
F32 getWidthF32(const std::string& text, S32 offset, S32 max_chars ) const;
|
||||
F32 getWidthF32(const llwchar* wchars, S32 offset, S32 max_chars) const;
|
||||
F32 getWidthF32(const llwchar* wchars, S32 offset, S32 max_chars, bool no_padding = false) const;
|
||||
|
||||
// The following are called often, frequently with large buffers, so do not use a string interface
|
||||
|
||||
|
|
@ -189,6 +189,8 @@ public:
|
|||
|
||||
static LLFontGL* getFontMonospace();
|
||||
static LLFontGL* getFontSansSerifSmall();
|
||||
static LLFontGL* getFontSansSerifSmallBold();
|
||||
static LLFontGL* getFontSansSerifSmallItalic();
|
||||
static LLFontGL* getFontSansSerif();
|
||||
static LLFontGL* getFontSansSerifBig();
|
||||
static LLFontGL* getFontSansSerifHuge();
|
||||
|
|
|
|||
|
|
@ -2890,9 +2890,7 @@ void LLGLSyncFence::wait()
|
|||
if (mSync)
|
||||
{
|
||||
while (glClientWaitSync(mSync, 0, FENCE_WAIT_TIME_NANOSECONDS) == GL_TIMEOUT_EXPIRED)
|
||||
{ //track the number of times we've waited here
|
||||
static S32 waits = 0;
|
||||
waits++;
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ U32 wpo2(U32 i);
|
|||
|
||||
// texture memory accounting (for OS X)
|
||||
static LLMutex sTexMemMutex;
|
||||
static std::unordered_map<U32, U32> sTextureAllocs;
|
||||
static std::unordered_map<U32, U64> sTextureAllocs;
|
||||
static U64 sTextureBytes = 0;
|
||||
|
||||
// track a texture alloc on the currently bound texture.
|
||||
|
|
@ -67,7 +67,7 @@ static void alloc_tex_image(U32 width, U32 height, U32 pixformat)
|
|||
{
|
||||
U32 texUnit = gGL.getCurrentTexUnitIndex();
|
||||
U32 texName = gGL.getTexUnit(texUnit)->getCurrTexture();
|
||||
S32 size = LLImageGL::dataFormatBytes(pixformat, width, height);
|
||||
U64 size = LLImageGL::dataFormatBytes(pixformat, width, height);
|
||||
|
||||
llassert(size >= 0);
|
||||
|
||||
|
|
@ -296,7 +296,7 @@ S32 LLImageGL::dataFormatBits(S32 dataformat)
|
|||
}
|
||||
|
||||
//static
|
||||
S32 LLImageGL::dataFormatBytes(S32 dataformat, S32 width, S32 height)
|
||||
S64 LLImageGL::dataFormatBytes(S32 dataformat, S32 width, S32 height)
|
||||
{
|
||||
switch (dataformat)
|
||||
{
|
||||
|
|
@ -312,8 +312,8 @@ S32 LLImageGL::dataFormatBytes(S32 dataformat, S32 width, S32 height)
|
|||
default:
|
||||
break;
|
||||
}
|
||||
S32 bytes ((width*height*dataFormatBits(dataformat)+7)>>3);
|
||||
S32 aligned = (bytes+3)&~3;
|
||||
S64 bytes (((S64)width * (S64)height * (S64)dataFormatBits(dataformat)+7)>>3);
|
||||
S64 aligned = (bytes+3)&~3;
|
||||
return aligned;
|
||||
}
|
||||
|
||||
|
|
@ -518,7 +518,7 @@ void LLImageGL::init(BOOL usemipmaps)
|
|||
// so that it is obvious by visual inspection if we forgot to
|
||||
// init a field.
|
||||
|
||||
mTextureMemory = (S32Bytes)0;
|
||||
mTextureMemory = S64Bytes(0);
|
||||
mLastBindTime = 0.f;
|
||||
|
||||
mPickMask = NULL;
|
||||
|
|
@ -905,9 +905,16 @@ BOOL LLImageGL::setImage(const U8* data_in, BOOL data_hasmips /* = FALSE */, S32
|
|||
stop_glerror();
|
||||
|
||||
if (prev_mip_data)
|
||||
delete[] prev_mip_data;
|
||||
{
|
||||
if (prev_mip_data != cur_mip_data)
|
||||
delete[] prev_mip_data;
|
||||
prev_mip_data = nullptr;
|
||||
}
|
||||
if (cur_mip_data)
|
||||
{
|
||||
delete[] cur_mip_data;
|
||||
cur_mip_data = nullptr;
|
||||
}
|
||||
|
||||
mGLTextureCreated = false;
|
||||
return FALSE;
|
||||
|
|
@ -1737,7 +1744,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_
|
|||
}
|
||||
|
||||
|
||||
mTextureMemory = (S32Bytes)getMipBytes(mCurrentDiscardLevel);
|
||||
mTextureMemory = (S64Bytes)getMipBytes(mCurrentDiscardLevel);
|
||||
mTexelsInGLTexture = getWidth() * getHeight();
|
||||
|
||||
// mark this as bound at this point, so we don't throw it out immediately
|
||||
|
|
@ -1931,9 +1938,9 @@ void LLImageGL::destroyGLTexture()
|
|||
|
||||
if (mTexName != 0)
|
||||
{
|
||||
if(mTextureMemory != S32Bytes(0))
|
||||
if(mTextureMemory != S64Bytes(0))
|
||||
{
|
||||
mTextureMemory = (S32Bytes)0;
|
||||
mTextureMemory = (S64Bytes)0;
|
||||
}
|
||||
|
||||
LLImageGL::deleteTextures(1, &mTexName);
|
||||
|
|
@ -2029,7 +2036,7 @@ S32 LLImageGL::getWidth(S32 discard_level) const
|
|||
return width;
|
||||
}
|
||||
|
||||
S32 LLImageGL::getBytes(S32 discard_level) const
|
||||
S64 LLImageGL::getBytes(S32 discard_level) const
|
||||
{
|
||||
if (discard_level < 0)
|
||||
{
|
||||
|
|
@ -2042,7 +2049,7 @@ S32 LLImageGL::getBytes(S32 discard_level) const
|
|||
return dataFormatBytes(mFormatPrimary, w, h);
|
||||
}
|
||||
|
||||
S32 LLImageGL::getMipBytes(S32 discard_level) const
|
||||
S64 LLImageGL::getMipBytes(S32 discard_level) const
|
||||
{
|
||||
if (discard_level < 0)
|
||||
{
|
||||
|
|
@ -2050,7 +2057,7 @@ S32 LLImageGL::getMipBytes(S32 discard_level) const
|
|||
}
|
||||
S32 w = mWidth>>discard_level;
|
||||
S32 h = mHeight>>discard_level;
|
||||
S32 res = dataFormatBytes(mFormatPrimary, w, h);
|
||||
S64 res = dataFormatBytes(mFormatPrimary, w, h);
|
||||
if (mUseMipMaps)
|
||||
{
|
||||
while (w > 1 && h > 1)
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ public:
|
|||
|
||||
// Size calculation
|
||||
static S32 dataFormatBits(S32 dataformat);
|
||||
static S32 dataFormatBytes(S32 dataformat, S32 width, S32 height);
|
||||
static S64 dataFormatBytes(S32 dataformat, S32 width, S32 height);
|
||||
static S32 dataFormatComponents(S32 dataformat);
|
||||
|
||||
BOOL updateBindStats() const ;
|
||||
|
|
@ -145,8 +145,8 @@ public:
|
|||
S32 getWidth(S32 discard_level = -1) const;
|
||||
S32 getHeight(S32 discard_level = -1) const;
|
||||
U8 getComponents() const { return mComponents; }
|
||||
S32 getBytes(S32 discard_level = -1) const;
|
||||
S32 getMipBytes(S32 discard_level = -1) const;
|
||||
S64 getBytes(S32 discard_level = -1) const;
|
||||
S64 getMipBytes(S32 discard_level = -1) const;
|
||||
BOOL getBoundRecently() const;
|
||||
BOOL isJustBound() const;
|
||||
BOOL getHasExplicitFormat() const { return mHasExplicitFormat; }
|
||||
|
|
@ -208,7 +208,7 @@ public:
|
|||
|
||||
public:
|
||||
// Various GL/Rendering options
|
||||
S32Bytes mTextureMemory;
|
||||
S64Bytes mTextureMemory;
|
||||
mutable F32 mLastBindTime; // last time this was bound, by discard level
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -975,8 +975,8 @@ void LLRender::syncLightState()
|
|||
shader->uniform3fv(LLShaderMgr::LIGHT_AMBIENT, 1, mAmbientLightColor.mV);
|
||||
shader->uniform1i(LLShaderMgr::SUN_UP_FACTOR, sun_primary[0] ? 1 : 0);
|
||||
//shader->uniform3fv(LLShaderMgr::AMBIENT, 1, mAmbientLightColor.mV);
|
||||
shader->uniform3fv(LLShaderMgr::SUNLIGHT_COLOR, 1, diffuse[0].mV);
|
||||
shader->uniform3fv(LLShaderMgr::MOONLIGHT_COLOR, 1, diffuse_b[0].mV);
|
||||
//shader->uniform3fv(LLShaderMgr::SUNLIGHT_COLOR, 1, diffuse[0].mV);
|
||||
//shader->uniform3fv(LLShaderMgr::MOONLIGHT_COLOR, 1, diffuse_b[0].mV);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1275,6 +1275,8 @@ void LLShaderMgr::initAttribsAndUniforms()
|
|||
mReservedUniforms.push_back("sunlight_color");
|
||||
mReservedUniforms.push_back("ambient_color");
|
||||
mReservedUniforms.push_back("sky_hdr_scale");
|
||||
mReservedUniforms.push_back("sky_sunlight_scale");
|
||||
mReservedUniforms.push_back("sky_ambient_scale");
|
||||
mReservedUniforms.push_back("blue_horizon");
|
||||
mReservedUniforms.push_back("blue_density");
|
||||
mReservedUniforms.push_back("haze_horizon");
|
||||
|
|
@ -1308,8 +1310,9 @@ void LLShaderMgr::initAttribsAndUniforms()
|
|||
mReservedUniforms.push_back("warmthAmount");
|
||||
mReservedUniforms.push_back("glowStrength");
|
||||
mReservedUniforms.push_back("glowDelta");
|
||||
mReservedUniforms.push_back("glowNoiseMap");
|
||||
|
||||
llassert(mReservedUniforms.size() == LLShaderMgr::GLOW_DELTA+1);
|
||||
llassert(mReservedUniforms.size() == LLShaderMgr::GLOW_NOISE_MAP+1);
|
||||
|
||||
|
||||
mReservedUniforms.push_back("minimum_alpha");
|
||||
|
|
|
|||
|
|
@ -103,6 +103,8 @@ public:
|
|||
SUNLIGHT_COLOR, // "sunlight_color"
|
||||
AMBIENT, // "ambient_color"
|
||||
SKY_HDR_SCALE, // "sky_hdr_scale"
|
||||
SKY_SUNLIGHT_SCALE, // "sky_sunlight_scale"
|
||||
SKY_AMBIENT_SCALE, // "sky_ambient_scale"
|
||||
BLUE_HORIZON, // "blue_horizon"
|
||||
BLUE_DENSITY, // "blue_density"
|
||||
HAZE_HORIZON, // "haze_horizon"
|
||||
|
|
@ -131,6 +133,7 @@ public:
|
|||
GLOW_WARMTH_AMOUNT, // "warmthAmount"
|
||||
GLOW_STRENGTH, // "glowStrength"
|
||||
GLOW_DELTA, // "glowDelta"
|
||||
GLOW_NOISE_MAP, // "glowNoiseMap"
|
||||
|
||||
MINIMUM_ALPHA, // "minimum_alpha"
|
||||
EMISSIVE_BRIGHTNESS, // "emissive_brightness"
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@
|
|||
#ifndef LL_TEXTUREMANAGERBRIDGE_H
|
||||
#define LL_TEXTUREMANAGERBRIDGE_H
|
||||
|
||||
#include "llavatarappearancedefines.h"
|
||||
#include "llpointer.h"
|
||||
#include "llgltexture.h"
|
||||
|
||||
|
|
@ -703,7 +703,7 @@ bool LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_of
|
|||
|
||||
for (U32 i = start; i <= end; ++i)
|
||||
{
|
||||
if (!v->isFinite3())
|
||||
if (!v[i].isFinite3())
|
||||
{
|
||||
LL_ERRS() << "Non-finite vertex position data detected." << LL_ENDL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ LLAccordionCtrl::LLAccordionCtrl(const Params& params):LLPanel(params)
|
|||
initNoTabsWidget(params.no_matched_tabs_text);
|
||||
|
||||
mSingleExpansion = params.single_expansion;
|
||||
if(mFitParent && !mSingleExpansion)
|
||||
if (mFitParent && !mSingleExpansion)
|
||||
{
|
||||
LL_INFOS() << "fit_parent works best when combined with single_expansion" << LL_ENDL;
|
||||
}
|
||||
|
|
@ -102,14 +102,13 @@ void LLAccordionCtrl::draw()
|
|||
LLPanel::draw();
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
BOOL LLAccordionCtrl::postBuild()
|
||||
{
|
||||
static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
|
||||
static LLUICachedControl<S32> scrollbar_size("UIScrollbarSize", 0);
|
||||
|
||||
LLRect scroll_rect;
|
||||
scroll_rect.setOriginAndSize(
|
||||
scroll_rect.setOriginAndSize(
|
||||
getRect().getWidth() - scrollbar_size,
|
||||
1,
|
||||
scrollbar_size,
|
||||
|
|
@ -126,39 +125,42 @@ BOOL LLAccordionCtrl::postBuild()
|
|||
sbparams.follows.flags(FOLLOWS_RIGHT | FOLLOWS_TOP | FOLLOWS_BOTTOM);
|
||||
sbparams.change_callback(boost::bind(&LLAccordionCtrl::onScrollPosChangeCallback, this, _1, _2));
|
||||
|
||||
mScrollbar = LLUICtrlFactory::create<LLScrollbar> (sbparams);
|
||||
LLView::addChild( mScrollbar );
|
||||
mScrollbar->setVisible( false );
|
||||
mScrollbar = LLUICtrlFactory::create<LLScrollbar>(sbparams);
|
||||
LLView::addChild(mScrollbar);
|
||||
mScrollbar->setVisible(FALSE);
|
||||
mScrollbar->setFollowsRight();
|
||||
mScrollbar->setFollowsTop();
|
||||
mScrollbar->setFollowsBottom();
|
||||
|
||||
//if it was created from xml...
|
||||
std::vector<LLUICtrl*> accordion_tabs;
|
||||
for(child_list_const_iter_t it = getChildList()->begin();
|
||||
for (child_list_const_iter_t it = getChildList()->begin();
|
||||
getChildList()->end() != it; ++it)
|
||||
{
|
||||
LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(*it);
|
||||
if(accordion_tab == NULL)
|
||||
if (accordion_tab == NULL)
|
||||
continue;
|
||||
if(std::find(mAccordionTabs.begin(),mAccordionTabs.end(),accordion_tab) == mAccordionTabs.end())
|
||||
if (std::find(mAccordionTabs.begin(), mAccordionTabs.end(), accordion_tab) == mAccordionTabs.end())
|
||||
{
|
||||
accordion_tabs.push_back(accordion_tab);
|
||||
}
|
||||
}
|
||||
|
||||
for(std::vector<LLUICtrl*>::reverse_iterator it = accordion_tabs.rbegin();it!=accordion_tabs.rend();++it)
|
||||
addCollapsibleCtrl(*it);
|
||||
|
||||
arrange ();
|
||||
|
||||
if(mSingleExpansion)
|
||||
for (std::vector<LLUICtrl*>::reverse_iterator it = accordion_tabs.rbegin();
|
||||
it < accordion_tabs.rend(); ++it)
|
||||
{
|
||||
if(!mAccordionTabs[0]->getDisplayChildren())
|
||||
addCollapsibleCtrl(*it);
|
||||
}
|
||||
|
||||
arrange();
|
||||
|
||||
if (mSingleExpansion)
|
||||
{
|
||||
if (!mAccordionTabs[0]->getDisplayChildren())
|
||||
mAccordionTabs[0]->setDisplayChildren(true);
|
||||
for(size_t i=1;i<mAccordionTabs.size();++i)
|
||||
for (size_t i = 1; i < mAccordionTabs.size(); ++i)
|
||||
{
|
||||
if(mAccordionTabs[i]->getDisplayChildren())
|
||||
if (mAccordionTabs[i]->getDisplayChildren())
|
||||
mAccordionTabs[i]->setDisplayChildren(false);
|
||||
}
|
||||
}
|
||||
|
|
@ -205,23 +207,22 @@ BOOL LLAccordionCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask)
|
|||
//---------------------------------------------------------------------------------
|
||||
void LLAccordionCtrl::shiftAccordionTabs(S16 panel_num, S32 delta)
|
||||
{
|
||||
for(size_t i = panel_num; i < mAccordionTabs.size(); i++ )
|
||||
for (size_t i = panel_num; i < mAccordionTabs.size(); ++i)
|
||||
{
|
||||
ctrlShiftVertical(mAccordionTabs[i],delta);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
void LLAccordionCtrl::onCollapseCtrlCloseOpen(S16 panel_num)
|
||||
{
|
||||
if(mSingleExpansion)
|
||||
if (mSingleExpansion)
|
||||
{
|
||||
for(size_t i=0;i<mAccordionTabs.size();++i)
|
||||
for (size_t i = 0; i < mAccordionTabs.size(); ++i)
|
||||
{
|
||||
if(i==panel_num)
|
||||
if (i == panel_num)
|
||||
continue;
|
||||
if(mAccordionTabs[i]->getDisplayChildren())
|
||||
if (mAccordionTabs[i]->getDisplayChildren())
|
||||
mAccordionTabs[i]->setDisplayChildren(false);
|
||||
}
|
||||
|
||||
|
|
@ -232,64 +233,63 @@ void LLAccordionCtrl::onCollapseCtrlCloseOpen(S16 panel_num)
|
|||
void LLAccordionCtrl::show_hide_scrollbar(S32 width, S32 height)
|
||||
{
|
||||
calcRecuiredHeight();
|
||||
if(getRecuiredHeight() > height )
|
||||
showScrollbar(width,height);
|
||||
if (getRecuiredHeight() > height)
|
||||
showScrollbar(width, height);
|
||||
else
|
||||
hideScrollbar(width,height);
|
||||
hideScrollbar(width, height);
|
||||
}
|
||||
|
||||
void LLAccordionCtrl::showScrollbar(S32 width, S32 height)
|
||||
void LLAccordionCtrl::showScrollbar(S32 width, S32 height)
|
||||
{
|
||||
bool was_visible = mScrollbar->getVisible();
|
||||
|
||||
mScrollbar->setVisible(true);
|
||||
mScrollbar->setVisible(TRUE);
|
||||
|
||||
static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
|
||||
|
||||
ctrlSetLeftTopAndSize(mScrollbar
|
||||
,width-scrollbar_size - PARENT_BORDER_MARGIN/2
|
||||
,height-PARENT_BORDER_MARGIN
|
||||
,scrollbar_size
|
||||
,height-2*PARENT_BORDER_MARGIN);
|
||||
, width - scrollbar_size - PARENT_BORDER_MARGIN / 2
|
||||
, height - PARENT_BORDER_MARGIN
|
||||
, scrollbar_size
|
||||
, height - PARENT_BORDER_MARGIN * 2);
|
||||
|
||||
mScrollbar->setPageSize(height);
|
||||
mScrollbar->setDocParams(mInnerRect.getHeight(),mScrollbar->getDocPos());
|
||||
mScrollbar->setDocParams(mInnerRect.getHeight(), mScrollbar->getDocPos());
|
||||
|
||||
if(was_visible)
|
||||
if (was_visible)
|
||||
{
|
||||
S32 scroll_pos = llmin(mScrollbar->getDocPos(), getRecuiredHeight() - height - 1);
|
||||
mScrollbar->setDocPos(scroll_pos);
|
||||
}
|
||||
}
|
||||
|
||||
void LLAccordionCtrl::hideScrollbar( S32 width, S32 height )
|
||||
void LLAccordionCtrl::hideScrollbar(S32 width, S32 height)
|
||||
{
|
||||
if(mScrollbar->getVisible() == false)
|
||||
if (mScrollbar->getVisible() == FALSE)
|
||||
return;
|
||||
mScrollbar->setVisible(false);
|
||||
mScrollbar->setVisible(FALSE);
|
||||
|
||||
static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
|
||||
|
||||
S32 panel_width = width - 2*BORDER_MARGIN;
|
||||
|
||||
//reshape all accordeons and shift all draggers
|
||||
for(size_t i=0;i<mAccordionTabs.size();++i)
|
||||
// Reshape all accordions and shift all draggers
|
||||
for (size_t i = 0; i < mAccordionTabs.size(); ++i)
|
||||
{
|
||||
LLRect panel_rect = mAccordionTabs[i]->getRect();
|
||||
ctrlSetLeftTopAndSize(mAccordionTabs[i],panel_rect.mLeft,panel_rect.mTop,panel_width,panel_rect.getHeight());
|
||||
ctrlSetLeftTopAndSize(mAccordionTabs[i], panel_rect.mLeft, panel_rect.mTop, panel_width, panel_rect.getHeight());
|
||||
}
|
||||
|
||||
mScrollbar->setDocPos(0);
|
||||
|
||||
if(mAccordionTabs.size()>0)
|
||||
if (!mAccordionTabs.empty())
|
||||
{
|
||||
S32 panel_top = height - BORDER_MARGIN; // Top coordinate of the first panel
|
||||
S32 panel_top = height - BORDER_MARGIN; // Top coordinate of the first panel
|
||||
S32 diff = panel_top - mAccordionTabs[0]->getRect().mTop;
|
||||
shiftAccordionTabs(0,diff);
|
||||
shiftAccordionTabs(0, diff);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
S32 LLAccordionCtrl::calcRecuiredHeight()
|
||||
{
|
||||
|
|
@ -305,7 +305,7 @@ S32 LLAccordionCtrl::calcRecuiredHeight()
|
|||
}
|
||||
}
|
||||
|
||||
mInnerRect.setLeftTopAndSize(0,rec_height + BORDER_MARGIN*2,getRect().getWidth(),rec_height + BORDER_MARGIN);
|
||||
mInnerRect.setLeftTopAndSize(0, rec_height + BORDER_MARGIN * 2, getRect().getWidth(), rec_height + BORDER_MARGIN);
|
||||
|
||||
return mInnerRect.getHeight();
|
||||
}
|
||||
|
|
@ -313,7 +313,7 @@ S32 LLAccordionCtrl::calcRecuiredHeight()
|
|||
//---------------------------------------------------------------------------------
|
||||
void LLAccordionCtrl::ctrlSetLeftTopAndSize(LLView* panel, S32 left, S32 top, S32 width, S32 height)
|
||||
{
|
||||
if(!panel)
|
||||
if (!panel)
|
||||
return;
|
||||
LLRect panel_rect = panel->getRect();
|
||||
panel_rect.setLeftTopAndSize( left, top, width, height);
|
||||
|
|
@ -321,9 +321,9 @@ void LLAccordionCtrl::ctrlSetLeftTopAndSize(LLView* panel, S32 left, S32 top, S3
|
|||
panel->setRect(panel_rect);
|
||||
}
|
||||
|
||||
void LLAccordionCtrl::ctrlShiftVertical(LLView* panel,S32 delta)
|
||||
void LLAccordionCtrl::ctrlShiftVertical(LLView* panel, S32 delta)
|
||||
{
|
||||
if(!panel)
|
||||
if (!panel)
|
||||
return;
|
||||
panel->translate(0,delta);
|
||||
}
|
||||
|
|
@ -333,9 +333,9 @@ void LLAccordionCtrl::ctrlShiftVertical(LLView* panel,S32 delta)
|
|||
void LLAccordionCtrl::addCollapsibleCtrl(LLView* view)
|
||||
{
|
||||
LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(view);
|
||||
if(!accordion_tab)
|
||||
if (!accordion_tab)
|
||||
return;
|
||||
if(std::find(beginChild(), endChild(), accordion_tab) == endChild())
|
||||
if (std::find(beginChild(), endChild(), accordion_tab) == endChild())
|
||||
addChild(accordion_tab);
|
||||
mAccordionTabs.push_back(accordion_tab);
|
||||
|
||||
|
|
@ -369,7 +369,7 @@ void LLAccordionCtrl::removeCollapsibleCtrl(LLView* view)
|
|||
}
|
||||
}
|
||||
|
||||
void LLAccordionCtrl::initNoTabsWidget(const LLTextBox::Params& tb_params)
|
||||
void LLAccordionCtrl::initNoTabsWidget(const LLTextBox::Params& tb_params)
|
||||
{
|
||||
LLTextBox::Params tp = tb_params;
|
||||
tp.rect(getLocalRect());
|
||||
|
|
@ -377,39 +377,39 @@ void LLAccordionCtrl::initNoTabsWidget(const LLTextBox::Params& tb_params)
|
|||
mNoVisibleTabsHelpText = LLUICtrlFactory::create<LLTextBox>(tp, this);
|
||||
}
|
||||
|
||||
void LLAccordionCtrl::updateNoTabsHelpTextVisibility()
|
||||
void LLAccordionCtrl::updateNoTabsHelpTextVisibility()
|
||||
{
|
||||
bool visible_exists = false;
|
||||
std::vector<LLAccordionCtrlTab*>::const_iterator it = mAccordionTabs.begin();
|
||||
const std::vector<LLAccordionCtrlTab*>::const_iterator it_end = mAccordionTabs.end();
|
||||
for (; it != it_end; ++it)
|
||||
while (it < it_end)
|
||||
{
|
||||
if ((*it)->getVisible())
|
||||
if ((*(it++))->getVisible())
|
||||
{
|
||||
visible_exists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mNoVisibleTabsHelpText->setVisible(!visible_exists);
|
||||
mNoVisibleTabsHelpText->setVisible(visible_exists ? FALSE : TRUE);
|
||||
}
|
||||
|
||||
void LLAccordionCtrl::arrangeSinge()
|
||||
void LLAccordionCtrl::arrangeSingle()
|
||||
{
|
||||
S32 panel_left = BORDER_MARGIN; // Margin from left side of Splitter
|
||||
S32 panel_top = getRect().getHeight() - BORDER_MARGIN; // Top coordinate of the first panel
|
||||
S32 panel_width = getRect().getWidth() - 4; // Top coordinate of the first panel
|
||||
S32 panel_left = BORDER_MARGIN; // Margin from left side of Splitter
|
||||
S32 panel_top = getRect().getHeight() - BORDER_MARGIN; // Top coordinate of the first panel
|
||||
S32 panel_width = getRect().getWidth() - 4;
|
||||
S32 panel_height;
|
||||
|
||||
S32 collapsed_height = 0;
|
||||
|
||||
for(size_t i=0;i<mAccordionTabs.size();++i)
|
||||
for (size_t i = 0; i < mAccordionTabs.size(); ++i)
|
||||
{
|
||||
LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]);
|
||||
|
||||
if(accordion_tab->getVisible() == false) //skip hidden accordion tabs
|
||||
if (accordion_tab->getVisible() == FALSE) // Skip hidden accordion tabs
|
||||
continue;
|
||||
if(!accordion_tab->isExpanded() )
|
||||
if (!accordion_tab->isExpanded() )
|
||||
{
|
||||
collapsed_height+=mAccordionTabs[i]->getRect().getHeight();
|
||||
}
|
||||
|
|
@ -417,28 +417,28 @@ void LLAccordionCtrl::arrangeSinge()
|
|||
|
||||
S32 expanded_height = getRect().getHeight() - BORDER_MARGIN - collapsed_height;
|
||||
|
||||
for(size_t i=0;i<mAccordionTabs.size();++i)
|
||||
for (size_t i = 0; i < mAccordionTabs.size(); ++i)
|
||||
{
|
||||
LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]);
|
||||
|
||||
if(accordion_tab->getVisible() == false) //skip hidden accordion tabs
|
||||
if (accordion_tab->getVisible() == FALSE) // Skip hidden accordion tabs
|
||||
continue;
|
||||
if(!accordion_tab->isExpanded() )
|
||||
if (!accordion_tab->isExpanded() )
|
||||
{
|
||||
panel_height = accordion_tab->getRect().getHeight();
|
||||
}
|
||||
else
|
||||
{
|
||||
if(mFitParent)
|
||||
if (mFitParent)
|
||||
{
|
||||
panel_height = expanded_height;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(accordion_tab->getAccordionView())
|
||||
if (accordion_tab->getAccordionView())
|
||||
{
|
||||
panel_height = accordion_tab->getAccordionView()->getRect().getHeight() +
|
||||
accordion_tab->getHeaderHeight() + 2*BORDER_MARGIN;
|
||||
accordion_tab->getHeaderHeight() + BORDER_MARGIN * 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -451,67 +451,67 @@ void LLAccordionCtrl::arrangeSinge()
|
|||
panel_height = llmax(panel_height, accordion_tab->getHeaderHeight());
|
||||
|
||||
ctrlSetLeftTopAndSize(mAccordionTabs[i], panel_left, panel_top, panel_width, panel_height);
|
||||
panel_top-=mAccordionTabs[i]->getRect().getHeight();
|
||||
panel_top -= mAccordionTabs[i]->getRect().getHeight();
|
||||
}
|
||||
|
||||
show_hide_scrollbar(getRect().getWidth(), getRect().getHeight());
|
||||
updateLayout(getRect().getWidth(), getRect().getHeight());
|
||||
}
|
||||
|
||||
void LLAccordionCtrl::arrangeMultiple()
|
||||
void LLAccordionCtrl::arrangeMultiple()
|
||||
{
|
||||
S32 panel_left = BORDER_MARGIN; // Margin from left side of Splitter
|
||||
S32 panel_top = getRect().getHeight() - BORDER_MARGIN; // Top coordinate of the first panel
|
||||
S32 panel_width = getRect().getWidth() - 4; // Top coordinate of the first panel
|
||||
S32 panel_left = BORDER_MARGIN; // Margin from left side of Splitter
|
||||
S32 panel_top = getRect().getHeight() - BORDER_MARGIN; // Top coordinate of the first panel
|
||||
S32 panel_width = getRect().getWidth() - 4;
|
||||
|
||||
//Calculate params
|
||||
for(size_t i = 0; i < mAccordionTabs.size(); i++ )
|
||||
for (size_t i = 0; i < mAccordionTabs.size(); i++ )
|
||||
{
|
||||
LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]);
|
||||
|
||||
if(accordion_tab->getVisible() == false) //skip hidden accordion tabs
|
||||
if (accordion_tab->getVisible() == FALSE) // Skip hidden accordion tabs
|
||||
continue;
|
||||
|
||||
if(!accordion_tab->isExpanded() )
|
||||
if (!accordion_tab->isExpanded() )
|
||||
{
|
||||
ctrlSetLeftTopAndSize(mAccordionTabs[i], panel_left, panel_top, panel_width, accordion_tab->getRect().getHeight());
|
||||
panel_top-=mAccordionTabs[i]->getRect().getHeight();
|
||||
panel_top -= mAccordionTabs[i]->getRect().getHeight();
|
||||
}
|
||||
else
|
||||
{
|
||||
S32 panel_height = accordion_tab->getRect().getHeight();
|
||||
|
||||
if(mFitParent)
|
||||
if (mFitParent)
|
||||
{
|
||||
// all expanded tabs will have equal height
|
||||
// All expanded tabs will have equal height
|
||||
panel_height = calcExpandedTabHeight(i, panel_top);
|
||||
ctrlSetLeftTopAndSize(accordion_tab, panel_left, panel_top, panel_width, panel_height);
|
||||
|
||||
// try to make accordion tab fit accordion view height.
|
||||
// Try to make accordion tab fit accordion view height.
|
||||
// Accordion View should implement getRequiredRect() and provide valid height
|
||||
S32 optimal_height = accordion_tab->getAccordionView()->getRequiredRect().getHeight();
|
||||
optimal_height += accordion_tab->getHeaderHeight() + 2 * BORDER_MARGIN;
|
||||
if(optimal_height < panel_height)
|
||||
if (optimal_height < panel_height)
|
||||
{
|
||||
panel_height = optimal_height;
|
||||
}
|
||||
|
||||
// minimum tab height is equal to header height
|
||||
if(mAccordionTabs[i]->getHeaderHeight() > panel_height)
|
||||
if (mAccordionTabs[i]->getHeaderHeight() > panel_height)
|
||||
{
|
||||
panel_height = mAccordionTabs[i]->getHeaderHeight();
|
||||
}
|
||||
}
|
||||
|
||||
ctrlSetLeftTopAndSize(mAccordionTabs[i], panel_left, panel_top, panel_width, panel_height);
|
||||
panel_top-=panel_height;
|
||||
panel_top -= panel_height;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
show_hide_scrollbar(getRect().getWidth(),getRect().getHeight());
|
||||
show_hide_scrollbar(getRect().getWidth(), getRect().getHeight());
|
||||
|
||||
updateLayout(getRect().getWidth(),getRect().getHeight());
|
||||
updateLayout(getRect().getWidth(), getRect().getHeight());
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -519,70 +519,67 @@ void LLAccordionCtrl::arrange()
|
|||
{
|
||||
updateNoTabsHelpTextVisibility();
|
||||
|
||||
if( mAccordionTabs.size() == 0)
|
||||
if (mAccordionTabs.empty())
|
||||
{
|
||||
//We do not arrange if we do not have what should be arranged
|
||||
// Nothing to arrange
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if(mAccordionTabs.size() == 1)
|
||||
if (mAccordionTabs.size() == 1)
|
||||
{
|
||||
S32 panel_top = getRect().getHeight() - BORDER_MARGIN; // Top coordinate of the first panel
|
||||
S32 panel_width = getRect().getWidth() - 4; // Top coordinate of the first panel
|
||||
S32 panel_top = getRect().getHeight() - BORDER_MARGIN; // Top coordinate of the first panel
|
||||
S32 panel_width = getRect().getWidth() - 4;
|
||||
|
||||
LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[0]);
|
||||
|
||||
LLRect panel_rect = accordion_tab->getRect();
|
||||
|
||||
S32 panel_height = getRect().getHeight() - 2*BORDER_MARGIN;
|
||||
|
||||
S32 panel_height = getRect().getHeight() - BORDER_MARGIN * 2;
|
||||
if (accordion_tab->getFitParent())
|
||||
panel_height = accordion_tab->getRect().getHeight();
|
||||
ctrlSetLeftTopAndSize(accordion_tab,panel_rect.mLeft,panel_top,panel_width,panel_height);
|
||||
|
||||
show_hide_scrollbar(getRect().getWidth(),getRect().getHeight());
|
||||
return;
|
||||
|
||||
ctrlSetLeftTopAndSize(accordion_tab, panel_rect.mLeft, panel_top, panel_width, panel_height);
|
||||
|
||||
show_hide_scrollbar(getRect().getWidth(), getRect().getHeight());
|
||||
return;
|
||||
}
|
||||
|
||||
if(mSingleExpansion)
|
||||
arrangeSinge ();
|
||||
if (mSingleExpansion)
|
||||
arrangeSingle();
|
||||
else
|
||||
arrangeMultiple ();
|
||||
arrangeMultiple();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
|
||||
BOOL LLAccordionCtrl::handleScrollWheel ( S32 x, S32 y, S32 clicks )
|
||||
BOOL LLAccordionCtrl::handleScrollWheel(S32 x, S32 y, S32 clicks)
|
||||
{
|
||||
if(LLPanel::handleScrollWheel(x,y,clicks))
|
||||
if (LLPanel::handleScrollWheel(x, y, clicks))
|
||||
return TRUE;
|
||||
if( mScrollbar->getVisible() && mScrollbar->handleScrollWheel( 0, 0, clicks ) )
|
||||
if (mScrollbar->getVisible() && mScrollbar->handleScrollWheel(0, 0, clicks))
|
||||
return TRUE;
|
||||
return false;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL LLAccordionCtrl::handleKeyHere (KEY key, MASK mask)
|
||||
BOOL LLAccordionCtrl::handleKeyHere(KEY key, MASK mask)
|
||||
{
|
||||
if( mScrollbar->getVisible() && mScrollbar->handleKeyHere( key,mask ) )
|
||||
if (mScrollbar->getVisible() && mScrollbar->handleKeyHere(key, mask))
|
||||
return TRUE;
|
||||
return LLPanel::handleKeyHere(key,mask);
|
||||
return LLPanel::handleKeyHere(key, mask);
|
||||
}
|
||||
|
||||
BOOL LLAccordionCtrl::handleDragAndDrop (S32 x, S32 y, MASK mask,
|
||||
BOOL drop,
|
||||
EDragAndDropType cargo_type,
|
||||
void* cargo_data,
|
||||
EAcceptance* accept,
|
||||
std::string& tooltip_msg)
|
||||
BOOL LLAccordionCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask,
|
||||
BOOL drop,
|
||||
EDragAndDropType cargo_type,
|
||||
void* cargo_data,
|
||||
EAcceptance* accept,
|
||||
std::string& tooltip_msg)
|
||||
{
|
||||
// Scroll folder view if needed. Never accepts a drag or drop.
|
||||
*accept = ACCEPT_NO;
|
||||
BOOL handled = autoScroll(x, y);
|
||||
|
||||
if( !handled )
|
||||
if (!handled)
|
||||
{
|
||||
handled = childrenHandleDragAndDrop(x, y, mask, drop, cargo_type,
|
||||
cargo_data, accept, tooltip_msg) != NULL;
|
||||
|
|
@ -590,14 +587,14 @@ BOOL LLAccordionCtrl::handleDragAndDrop (S32 x, S32 y, MASK mask,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL LLAccordionCtrl::autoScroll (S32 x, S32 y)
|
||||
BOOL LLAccordionCtrl::autoScroll(S32 x, S32 y)
|
||||
{
|
||||
static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
|
||||
|
||||
bool scrolling = false;
|
||||
if( mScrollbar->getVisible() )
|
||||
if (mScrollbar->getVisible())
|
||||
{
|
||||
LLRect rect_local( 0, getRect().getHeight(), getRect().getWidth() - scrollbar_size, 0 );
|
||||
LLRect rect_local(0, getRect().getHeight(), getRect().getWidth() - scrollbar_size, 0);
|
||||
LLRect screen_local_extents;
|
||||
|
||||
// clip rect against root view
|
||||
|
|
@ -610,51 +607,52 @@ BOOL LLAccordionCtrl::autoScroll (S32 x, S32 y)
|
|||
|
||||
LLRect bottom_scroll_rect = screen_local_extents;
|
||||
bottom_scroll_rect.mTop = rect_local.mBottom + auto_scroll_region_height;
|
||||
if( bottom_scroll_rect.pointInRect( x, y ) && (mScrollbar->getDocPos() < mScrollbar->getDocPosMax()) )
|
||||
if (bottom_scroll_rect.pointInRect( x, y ) && (mScrollbar->getDocPos() < mScrollbar->getDocPosMax()))
|
||||
{
|
||||
mScrollbar->setDocPos( mScrollbar->getDocPos() + auto_scroll_speed );
|
||||
mScrollbar->setDocPos(mScrollbar->getDocPos() + auto_scroll_speed);
|
||||
mAutoScrolling = true;
|
||||
scrolling = true;
|
||||
}
|
||||
|
||||
LLRect top_scroll_rect = screen_local_extents;
|
||||
top_scroll_rect.mBottom = rect_local.mTop - auto_scroll_region_height;
|
||||
if( top_scroll_rect.pointInRect( x, y ) && (mScrollbar->getDocPos() > 0) )
|
||||
if (top_scroll_rect.pointInRect(x, y) && (mScrollbar->getDocPos() > 0))
|
||||
{
|
||||
mScrollbar->setDocPos( mScrollbar->getDocPos() - auto_scroll_speed );
|
||||
mScrollbar->setDocPos(mScrollbar->getDocPos() - auto_scroll_speed);
|
||||
mAutoScrolling = true;
|
||||
scrolling = true;
|
||||
}
|
||||
}
|
||||
return scrolling;
|
||||
|
||||
return scrolling ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
void LLAccordionCtrl::updateLayout (S32 width, S32 height)
|
||||
void LLAccordionCtrl::updateLayout(S32 width, S32 height)
|
||||
{
|
||||
S32 panel_top = height - BORDER_MARGIN ;
|
||||
if(mScrollbar->getVisible())
|
||||
panel_top+=mScrollbar->getDocPos();
|
||||
if (mScrollbar->getVisible())
|
||||
panel_top += mScrollbar->getDocPos();
|
||||
|
||||
S32 panel_width = width - 2*BORDER_MARGIN;
|
||||
S32 panel_width = width - BORDER_MARGIN * 2;
|
||||
|
||||
static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
|
||||
if(mScrollbar->getVisible())
|
||||
panel_width-=scrollbar_size;
|
||||
if (mScrollbar->getVisible())
|
||||
panel_width -= scrollbar_size;
|
||||
|
||||
//set sizes for first panels and dragbars
|
||||
for(size_t i=0;i<mAccordionTabs.size();++i)
|
||||
// set sizes for first panels and dragbars
|
||||
for (size_t i = 0; i < mAccordionTabs.size(); ++i)
|
||||
{
|
||||
if(!mAccordionTabs[i]->getVisible())
|
||||
if (!mAccordionTabs[i]->getVisible())
|
||||
continue;
|
||||
LLRect panel_rect = mAccordionTabs[i]->getRect();
|
||||
ctrlSetLeftTopAndSize(mAccordionTabs[i],panel_rect.mLeft,panel_top,panel_width,panel_rect.getHeight());
|
||||
panel_top-=panel_rect.getHeight();
|
||||
ctrlSetLeftTopAndSize(mAccordionTabs[i], panel_rect.mLeft, panel_top, panel_width, panel_rect.getHeight());
|
||||
panel_top -= panel_rect.getHeight();
|
||||
}
|
||||
}
|
||||
|
||||
void LLAccordionCtrl::onScrollPosChangeCallback(S32, LLScrollbar*)
|
||||
void LLAccordionCtrl::onScrollPosChangeCallback(S32, LLScrollbar*)
|
||||
{
|
||||
updateLayout(getRect().getWidth(),getRect().getHeight());
|
||||
updateLayout(getRect().getWidth(), getRect().getHeight());
|
||||
}
|
||||
|
||||
// virtual
|
||||
|
|
@ -687,42 +685,43 @@ void LLAccordionCtrl::onUpdateScrollToChild(const LLUICtrl *cntrl)
|
|||
LLUICtrl::onUpdateScrollToChild(cntrl);
|
||||
}
|
||||
|
||||
void LLAccordionCtrl::onOpen (const LLSD& key)
|
||||
void LLAccordionCtrl::onOpen(const LLSD& key)
|
||||
{
|
||||
for(size_t i=0;i<mAccordionTabs.size();++i)
|
||||
for (size_t i = 0; i < mAccordionTabs.size(); ++i)
|
||||
{
|
||||
LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]);
|
||||
LLPanel* panel = dynamic_cast<LLPanel*>(accordion_tab->getAccordionView());
|
||||
if(panel!=NULL)
|
||||
if (panel != NULL)
|
||||
{
|
||||
panel->onOpen(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
S32 LLAccordionCtrl::notifyParent(const LLSD& info)
|
||||
{
|
||||
if(info.has("action"))
|
||||
if (info.has("action"))
|
||||
{
|
||||
std::string str_action = info["action"];
|
||||
if(str_action == "size_changes")
|
||||
if (str_action == "size_changes")
|
||||
{
|
||||
//
|
||||
arrange();
|
||||
return 1;
|
||||
}
|
||||
else if(str_action == "select_next")
|
||||
if (str_action == "select_next")
|
||||
{
|
||||
for(size_t i=0;i<mAccordionTabs.size();++i)
|
||||
for (size_t i = 0; i < mAccordionTabs.size(); ++i)
|
||||
{
|
||||
LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]);
|
||||
if(accordion_tab->hasFocus())
|
||||
if (accordion_tab->hasFocus())
|
||||
{
|
||||
while(++i<mAccordionTabs.size())
|
||||
while (++i < mAccordionTabs.size())
|
||||
{
|
||||
if(mAccordionTabs[i]->getVisible())
|
||||
if (mAccordionTabs[i]->getVisible())
|
||||
break;
|
||||
}
|
||||
if(i<mAccordionTabs.size())
|
||||
if (i < mAccordionTabs.size())
|
||||
{
|
||||
accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]);
|
||||
accordion_tab->notify(LLSD().with("action","select_first"));
|
||||
|
|
@ -733,17 +732,17 @@ S32 LLAccordionCtrl::notifyParent(const LLSD& info)
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
else if(str_action == "select_prev")
|
||||
if (str_action == "select_prev")
|
||||
{
|
||||
for(size_t i=0;i<mAccordionTabs.size();++i)
|
||||
for (size_t i = 0; i < mAccordionTabs.size(); ++i)
|
||||
{
|
||||
LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]);
|
||||
if(accordion_tab->hasFocus() && i>0)
|
||||
if (accordion_tab->hasFocus() && i > 0)
|
||||
{
|
||||
bool prev_visible_tab_found = false;
|
||||
while(i>0)
|
||||
while (i > 0)
|
||||
{
|
||||
if(mAccordionTabs[--i]->getVisible())
|
||||
if (mAccordionTabs[--i]->getVisible())
|
||||
{
|
||||
prev_visible_tab_found = true;
|
||||
break;
|
||||
|
|
@ -761,12 +760,12 @@ S32 LLAccordionCtrl::notifyParent(const LLSD& info)
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
else if(str_action == "select_current")
|
||||
if (str_action == "select_current")
|
||||
{
|
||||
for(size_t i=0;i<mAccordionTabs.size();++i)
|
||||
for (size_t i = 0; i < mAccordionTabs.size(); ++i)
|
||||
{
|
||||
// Set selection to the currently focused tab.
|
||||
if(mAccordionTabs[i]->hasFocus())
|
||||
if (mAccordionTabs[i]->hasFocus())
|
||||
{
|
||||
if (mAccordionTabs[i] != mSelectedTab)
|
||||
{
|
||||
|
|
@ -783,7 +782,7 @@ S32 LLAccordionCtrl::notifyParent(const LLSD& info)
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
else if(str_action == "deselect_current")
|
||||
if (str_action == "deselect_current")
|
||||
{
|
||||
// Reset selection to the currently selected tab.
|
||||
if (mSelectedTab)
|
||||
|
|
@ -802,9 +801,9 @@ S32 LLAccordionCtrl::notifyParent(const LLSD& info)
|
|||
screenRectToLocal(screen_rc, &local_rc);
|
||||
|
||||
// Translate to parent coordinatess to check if we are in visible rectangle
|
||||
local_rc.translate( getRect().mLeft, getRect().mBottom );
|
||||
local_rc.translate(getRect().mLeft, getRect().mBottom);
|
||||
|
||||
if ( !getRect().contains (local_rc) )
|
||||
if (!getRect().contains (local_rc))
|
||||
{
|
||||
// Back to local coords and calculate position for scroller
|
||||
S32 bottom = mScrollbar->getDocPos() - local_rc.mBottom + getRect().mBottom;
|
||||
|
|
@ -814,7 +813,7 @@ S32 LLAccordionCtrl::notifyParent(const LLSD& info)
|
|||
bottom, // min vertical scroll
|
||||
top); // max vertical scroll
|
||||
|
||||
mScrollbar->setDocPos( scroll_pos );
|
||||
mScrollbar->setDocPos(scroll_pos);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -834,15 +833,16 @@ S32 LLAccordionCtrl::notifyParent(const LLSD& info)
|
|||
}
|
||||
return LLPanel::notifyParent(info);
|
||||
}
|
||||
void LLAccordionCtrl::reset ()
|
||||
|
||||
void LLAccordionCtrl::reset()
|
||||
{
|
||||
if(mScrollbar)
|
||||
if (mScrollbar)
|
||||
mScrollbar->setDocPos(0);
|
||||
}
|
||||
|
||||
void LLAccordionCtrl::expandDefaultTab()
|
||||
{
|
||||
if (mAccordionTabs.size() > 0)
|
||||
if (!mAccordionTabs.empty())
|
||||
{
|
||||
LLAccordionCtrlTab* tab = mAccordionTabs.front();
|
||||
|
||||
|
|
@ -877,7 +877,7 @@ void LLAccordionCtrl::sort()
|
|||
arrange();
|
||||
}
|
||||
|
||||
void LLAccordionCtrl::setFilterSubString(const std::string& filter_string)
|
||||
void LLAccordionCtrl::setFilterSubString(const std::string& filter_string)
|
||||
{
|
||||
LLStringUtil::format_map_t args;
|
||||
args["[SEARCH_TERM]"] = LLURI::escape(filter_string);
|
||||
|
|
@ -907,7 +907,7 @@ const LLAccordionCtrlTab* LLAccordionCtrl::getExpandedTab() const
|
|||
|
||||
S32 LLAccordionCtrl::calcExpandedTabHeight(S32 tab_index /* = 0 */, S32 available_height /* = 0 */)
|
||||
{
|
||||
if(tab_index < 0)
|
||||
if (tab_index < 0)
|
||||
{
|
||||
return available_height;
|
||||
}
|
||||
|
|
@ -915,9 +915,9 @@ S32 LLAccordionCtrl::calcExpandedTabHeight(S32 tab_index /* = 0 */, S32 availabl
|
|||
S32 collapsed_tabs_height = 0;
|
||||
S32 num_expanded = 0;
|
||||
|
||||
for(size_t n = tab_index; n < mAccordionTabs.size(); ++n)
|
||||
for (size_t n = tab_index; n < mAccordionTabs.size(); ++n)
|
||||
{
|
||||
if(!mAccordionTabs[n]->isExpanded())
|
||||
if (!mAccordionTabs[n]->isExpanded())
|
||||
{
|
||||
collapsed_tabs_height += mAccordionTabs[n]->getHeaderHeight();
|
||||
}
|
||||
|
|
@ -927,7 +927,7 @@ S32 LLAccordionCtrl::calcExpandedTabHeight(S32 tab_index /* = 0 */, S32 availabl
|
|||
}
|
||||
}
|
||||
|
||||
if(0 == num_expanded)
|
||||
if (0 == num_expanded)
|
||||
{
|
||||
return available_height;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@ private:
|
|||
void initNoTabsWidget(const LLTextBox::Params& tb_params);
|
||||
void updateNoTabsHelpTextVisibility();
|
||||
|
||||
void arrangeSinge();
|
||||
void arrangeSingle();
|
||||
void arrangeMultiple();
|
||||
|
||||
// Calc Splitter's height that is necessary to display all child content
|
||||
|
|
|
|||
|
|
@ -69,13 +69,13 @@ public:
|
|||
virtual BOOL postBuild();
|
||||
|
||||
std::string getTitle();
|
||||
void setTitle(const std::string& title, const std::string& hl);
|
||||
void setTitle(const std::string& title, const std::string& hl);
|
||||
|
||||
void setTitleFontStyle(std::string style);
|
||||
void setTitleFontStyle(std::string style);
|
||||
|
||||
void setTitleColor(LLUIColor);
|
||||
void setTitleColor(LLUIColor);
|
||||
|
||||
void setSelected(bool is_selected) { mIsSelected = is_selected; }
|
||||
void setSelected(bool is_selected) { mIsSelected = is_selected; }
|
||||
|
||||
virtual void onMouseEnter(S32 x, S32 y, MASK mask);
|
||||
virtual void onMouseLeave(S32 x, S32 y, MASK mask);
|
||||
|
|
@ -85,8 +85,8 @@ public:
|
|||
void* cargo_data,
|
||||
EAcceptance* accept,
|
||||
std::string& tooltip_msg);
|
||||
private:
|
||||
|
||||
private:
|
||||
LLTextBox* mHeaderTextbox;
|
||||
|
||||
// Overlay images (arrows)
|
||||
|
|
@ -102,7 +102,7 @@ private:
|
|||
LLPointer<LLUIImage> mImageHeaderFocused;
|
||||
|
||||
// style saved when applying it in setTitleFontStyle
|
||||
LLStyle::Params mStyleParams;
|
||||
LLStyle::Params mStyleParams;
|
||||
|
||||
LLUIColor mHeaderBGColor;
|
||||
|
||||
|
|
@ -157,19 +157,17 @@ BOOL LLAccordionCtrlTab::LLAccordionCtrlTabHeader::postBuild()
|
|||
|
||||
std::string LLAccordionCtrlTab::LLAccordionCtrlTabHeader::getTitle()
|
||||
{
|
||||
if(mHeaderTextbox)
|
||||
if (mHeaderTextbox)
|
||||
{
|
||||
return mHeaderTextbox->getText();
|
||||
}
|
||||
else
|
||||
{
|
||||
return LLStringUtil::null;
|
||||
}
|
||||
|
||||
return LLStringUtil::null;
|
||||
}
|
||||
|
||||
void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::setTitle(const std::string& title, const std::string& hl)
|
||||
{
|
||||
if(mHeaderTextbox)
|
||||
if (mHeaderTextbox)
|
||||
{
|
||||
LLTextUtil::textboxSetHighlightedVal(
|
||||
mHeaderTextbox,
|
||||
|
|
@ -192,7 +190,7 @@ void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::setTitleFontStyle(std::string
|
|||
|
||||
void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::setTitleColor(LLUIColor color)
|
||||
{
|
||||
if(mHeaderTextbox)
|
||||
if (mHeaderTextbox)
|
||||
{
|
||||
mHeaderTextbox->setColor(color);
|
||||
}
|
||||
|
|
@ -204,11 +202,11 @@ void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::draw()
|
|||
S32 height = getRect().getHeight();
|
||||
|
||||
F32 alpha = getCurrentTransparency();
|
||||
gl_rect_2d(0,0,width - 1 ,height - 1,mHeaderBGColor.get() % alpha,true);
|
||||
gl_rect_2d(0, 0, width - 1, height - 1, mHeaderBGColor.get() % alpha, TRUE);
|
||||
|
||||
LLAccordionCtrlTab* parent = dynamic_cast<LLAccordionCtrlTab*>(getParent());
|
||||
bool collapsible = (parent && parent->getCollapsible());
|
||||
bool expanded = (parent && parent->getDisplayChildren());
|
||||
bool collapsible = parent && parent->getCollapsible();
|
||||
bool expanded = parent && parent->getDisplayChildren();
|
||||
|
||||
// Handle overlay images, if needed
|
||||
// Only show green "focus" background image if the accordion is open,
|
||||
|
|
@ -218,23 +216,22 @@ void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::draw()
|
|||
/*&& !(collapsible && !expanded)*/ // WHY??
|
||||
)
|
||||
{
|
||||
mImageHeaderFocused->draw(0,0,width,height);
|
||||
mImageHeaderFocused->draw(0, 0, width, height);
|
||||
}
|
||||
else
|
||||
{
|
||||
mImageHeader->draw(0,0,width,height);
|
||||
mImageHeader->draw(0, 0, width, height);
|
||||
}
|
||||
|
||||
if(mNeedsHighlight)
|
||||
if (mNeedsHighlight)
|
||||
{
|
||||
mImageHeaderOver->draw(0,0,width,height);
|
||||
mImageHeaderOver->draw(0, 0, width, height);
|
||||
}
|
||||
|
||||
|
||||
if(collapsible)
|
||||
if (collapsible)
|
||||
{
|
||||
LLPointer<LLUIImage> overlay_image;
|
||||
if(expanded)
|
||||
if (expanded)
|
||||
{
|
||||
overlay_image = mImageExpanded;
|
||||
}
|
||||
|
|
@ -242,8 +239,7 @@ void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::draw()
|
|||
{
|
||||
overlay_image = mImageCollapsed;
|
||||
}
|
||||
overlay_image->draw(HEADER_IMAGE_LEFT_OFFSET,
|
||||
(height - overlay_image->getHeight()) / 2);
|
||||
overlay_image->draw(HEADER_IMAGE_LEFT_OFFSET, (height - overlay_image->getHeight()) / 2);
|
||||
}
|
||||
|
||||
LLUICtrl::draw();
|
||||
|
|
@ -253,7 +249,7 @@ void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::reshape(S32 width, S32 height
|
|||
{
|
||||
S32 header_height = mHeaderTextbox->getTextPixelHeight();
|
||||
|
||||
LLRect textboxRect(HEADER_TEXT_LEFT_OFFSET,(height+header_height)/2 ,width,(height-header_height)/2);
|
||||
LLRect textboxRect(HEADER_TEXT_LEFT_OFFSET, (height + header_height) / 2, width, (height - header_height) / 2);
|
||||
mHeaderTextbox->reshape(textboxRect.getWidth(), textboxRect.getHeight());
|
||||
mHeaderTextbox->setRect(textboxRect);
|
||||
|
||||
|
|
@ -272,20 +268,24 @@ void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::onMouseEnter(S32 x, S32 y, MA
|
|||
LLUICtrl::onMouseEnter(x, y, mask);
|
||||
mNeedsHighlight = true;
|
||||
}
|
||||
|
||||
void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::onMouseLeave(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
LLUICtrl::onMouseLeave(x, y, mask);
|
||||
mNeedsHighlight = false;
|
||||
mAutoOpenTimer.stop();
|
||||
}
|
||||
|
||||
BOOL LLAccordionCtrlTab::LLAccordionCtrlTabHeader::handleKey(KEY key, MASK mask, BOOL called_from_parent)
|
||||
{
|
||||
if ( ( key == KEY_LEFT || key == KEY_RIGHT) && mask == MASK_NONE)
|
||||
if ((key == KEY_LEFT || key == KEY_RIGHT) && mask == MASK_NONE)
|
||||
{
|
||||
return getParent()->handleKey(key, mask, called_from_parent);
|
||||
}
|
||||
|
||||
return LLUICtrl::handleKey(key, mask, called_from_parent);
|
||||
}
|
||||
|
||||
BOOL LLAccordionCtrlTab::LLAccordionCtrlTabHeader::handleDragAndDrop(S32 x, S32 y, MASK mask,
|
||||
BOOL drop,
|
||||
EDragAndDropType cargo_type,
|
||||
|
|
@ -295,7 +295,7 @@ BOOL LLAccordionCtrlTab::LLAccordionCtrlTabHeader::handleDragAndDrop(S32 x, S32
|
|||
{
|
||||
LLAccordionCtrlTab* parent = dynamic_cast<LLAccordionCtrlTab*>(getParent());
|
||||
|
||||
if ( parent && !parent->getDisplayChildren() && parent->getCollapsible() && parent->canOpenClose() )
|
||||
if (parent && !parent->getDisplayChildren() && parent->getCollapsible() && parent->canOpenClose())
|
||||
{
|
||||
if (mAutoOpenTimer.getStarted())
|
||||
{
|
||||
|
|
@ -307,12 +307,15 @@ BOOL LLAccordionCtrlTab::LLAccordionCtrlTabHeader::handleDragAndDrop(S32 x, S32
|
|||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mAutoOpenTimer.start();
|
||||
}
|
||||
}
|
||||
|
||||
return LLUICtrl::handleDragAndDrop(x, y, mask, drop, cargo_type,
|
||||
cargo_data, accept, tooltip_msg);
|
||||
}
|
||||
|
||||
LLAccordionCtrlTab::Params::Params()
|
||||
: title("title")
|
||||
,display_children("expanded", true)
|
||||
|
|
@ -384,41 +387,39 @@ LLAccordionCtrlTab::~LLAccordionCtrlTab()
|
|||
{
|
||||
}
|
||||
|
||||
|
||||
void LLAccordionCtrlTab::setDisplayChildren(bool display)
|
||||
{
|
||||
mDisplayChildren = display;
|
||||
LLRect rect = getRect();
|
||||
|
||||
rect.mBottom = rect.mTop - (getDisplayChildren() ?
|
||||
mExpandedHeight : HEADER_HEIGHT);
|
||||
rect.mBottom = rect.mTop - (getDisplayChildren() ? mExpandedHeight : HEADER_HEIGHT);
|
||||
setRect(rect);
|
||||
|
||||
if(mContainerPanel)
|
||||
if (mContainerPanel)
|
||||
{
|
||||
mContainerPanel->setVisible(getDisplayChildren());
|
||||
}
|
||||
|
||||
if(mDisplayChildren)
|
||||
if (mDisplayChildren)
|
||||
{
|
||||
adjustContainerPanel();
|
||||
}
|
||||
else
|
||||
{
|
||||
if(mScrollbar)
|
||||
mScrollbar->setVisible(false);
|
||||
if (mScrollbar)
|
||||
mScrollbar->setVisible(FALSE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void LLAccordionCtrlTab::reshape(S32 width, S32 height, BOOL called_from_parent /* = TRUE */)
|
||||
{
|
||||
LLRect headerRect;
|
||||
|
||||
headerRect.setLeftTopAndSize(
|
||||
0,height,width,HEADER_HEIGHT);
|
||||
headerRect.setLeftTopAndSize(0, height, width, HEADER_HEIGHT);
|
||||
mHeader->setRect(headerRect);
|
||||
mHeader->reshape(headerRect.getWidth(), headerRect.getHeight());
|
||||
|
||||
if(!mDisplayChildren)
|
||||
if (!mDisplayChildren)
|
||||
return;
|
||||
|
||||
LLRect childRect;
|
||||
|
|
@ -426,7 +427,7 @@ void LLAccordionCtrlTab::reshape(S32 width, S32 height, BOOL called_from_parent
|
|||
childRect.setLeftTopAndSize(
|
||||
getPaddingLeft(),
|
||||
height - getHeaderHeight() - getPaddingTop(),
|
||||
width - getPaddingLeft() - getPaddingRight(),
|
||||
width - getPaddingLeft() - getPaddingRight(),
|
||||
height - getHeaderHeight() - getPaddingTop() - getPaddingBottom() );
|
||||
|
||||
adjustContainerPanel(childRect);
|
||||
|
|
@ -434,7 +435,7 @@ void LLAccordionCtrlTab::reshape(S32 width, S32 height, BOOL called_from_parent
|
|||
|
||||
void LLAccordionCtrlTab::changeOpenClose(bool is_open)
|
||||
{
|
||||
if(is_open)
|
||||
if (is_open)
|
||||
mExpandedHeight = getRect().getHeight();
|
||||
|
||||
setDisplayChildren(!is_open);
|
||||
|
|
@ -483,14 +484,14 @@ void LLAccordionCtrlTab::onUpdateScrollToChild(const LLUICtrl *cntrl)
|
|||
|
||||
BOOL LLAccordionCtrlTab::handleMouseDown(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
if(mCollapsible && mHeaderVisible && mCanOpenClose)
|
||||
if (mCollapsible && mHeaderVisible && mCanOpenClose)
|
||||
{
|
||||
if(y >= (getRect().getHeight() - HEADER_HEIGHT) )
|
||||
if (y >= (getRect().getHeight() - HEADER_HEIGHT))
|
||||
{
|
||||
mHeader->setFocus(true);
|
||||
changeOpenClose(getDisplayChildren());
|
||||
|
||||
//reset stored state
|
||||
// Reset stored state
|
||||
mWasStateStored = false;
|
||||
return TRUE;
|
||||
}
|
||||
|
|
@ -510,7 +511,7 @@ boost::signals2::connection LLAccordionCtrlTab::setDropDownStateChangedCallback(
|
|||
|
||||
bool LLAccordionCtrlTab::addChild(LLView* child, S32 tab_group)
|
||||
{
|
||||
if(DD_HEADER_NAME != child->getName())
|
||||
if (DD_HEADER_NAME != child->getName())
|
||||
{
|
||||
reshape(child->getRect().getWidth() , child->getRect().getHeight() + HEADER_HEIGHT );
|
||||
mExpandedHeight = getRect().getHeight();
|
||||
|
|
@ -518,12 +519,12 @@ bool LLAccordionCtrlTab::addChild(LLView* child, S32 tab_group)
|
|||
|
||||
bool res = LLUICtrl::addChild(child, tab_group);
|
||||
|
||||
if(DD_HEADER_NAME != child->getName())
|
||||
if (DD_HEADER_NAME != child->getName())
|
||||
{
|
||||
if(!mCollapsible)
|
||||
if (!mCollapsible)
|
||||
setDisplayChildren(true);
|
||||
else
|
||||
setDisplayChildren(getDisplayChildren());
|
||||
setDisplayChildren(getDisplayChildren());
|
||||
}
|
||||
|
||||
if (!mContainerPanel)
|
||||
|
|
@ -534,7 +535,7 @@ bool LLAccordionCtrlTab::addChild(LLView* child, S32 tab_group)
|
|||
|
||||
void LLAccordionCtrlTab::setAccordionView(LLView* panel)
|
||||
{
|
||||
addChild(panel,0);
|
||||
addChild(panel, 0);
|
||||
}
|
||||
|
||||
std::string LLAccordionCtrlTab::getTitle() const
|
||||
|
|
@ -543,10 +544,8 @@ std::string LLAccordionCtrlTab::getTitle() const
|
|||
{
|
||||
return mHeader->getTitle();
|
||||
}
|
||||
else
|
||||
{
|
||||
return LLStringUtil::null;
|
||||
}
|
||||
|
||||
return LLStringUtil::null;
|
||||
}
|
||||
|
||||
void LLAccordionCtrlTab::setTitle(const std::string& title, const std::string& hl)
|
||||
|
|
@ -579,6 +578,7 @@ boost::signals2::connection LLAccordionCtrlTab::setFocusReceivedCallback(const f
|
|||
{
|
||||
return mHeader->setFocusReceivedCallback(cb);
|
||||
}
|
||||
|
||||
return boost::signals2::connection();
|
||||
}
|
||||
|
||||
|
|
@ -588,6 +588,7 @@ boost::signals2::connection LLAccordionCtrlTab::setFocusLostCallback(const focus
|
|||
{
|
||||
return mHeader->setFocusLostCallback(cb);
|
||||
}
|
||||
|
||||
return boost::signals2::connection();
|
||||
}
|
||||
|
||||
|
|
@ -601,59 +602,65 @@ void LLAccordionCtrlTab::setSelected(bool is_selected)
|
|||
|
||||
LLView* LLAccordionCtrlTab::findContainerView()
|
||||
{
|
||||
for(child_list_const_iter_t it = getChildList()->begin();
|
||||
getChildList()->end() != it; ++it)
|
||||
child_list_const_iter_t it = getChildList()->begin(), it_end = getChildList()->end();
|
||||
while (it != it_end)
|
||||
{
|
||||
LLView* child = *it;
|
||||
if(DD_HEADER_NAME == child->getName())
|
||||
continue;
|
||||
if(!child->getVisible())
|
||||
continue;
|
||||
return child;
|
||||
LLView* child = *(it++);
|
||||
if (DD_HEADER_NAME != child->getName() && child->getVisible())
|
||||
return child;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void LLAccordionCtrlTab::selectOnFocusReceived()
|
||||
{
|
||||
if (getParent()) // A parent may not be set if tabs are added dynamically.
|
||||
{
|
||||
getParent()->notifyParent(LLSD().with("action", "select_current"));
|
||||
}
|
||||
}
|
||||
|
||||
void LLAccordionCtrlTab::deselectOnFocusLost()
|
||||
{
|
||||
if(getParent()) // A parent may not be set if tabs are added dynamically.
|
||||
if (getParent()) // A parent may not be set if tabs are added dynamically.
|
||||
{
|
||||
getParent()->notifyParent(LLSD().with("action", "deselect_current"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
S32 LLAccordionCtrlTab::getHeaderHeight()
|
||||
{
|
||||
return mHeaderVisible?HEADER_HEIGHT:0;
|
||||
return mHeaderVisible ? HEADER_HEIGHT : 0;
|
||||
}
|
||||
|
||||
void LLAccordionCtrlTab::setHeaderVisible(bool value)
|
||||
void LLAccordionCtrlTab::setHeaderVisible(bool value)
|
||||
{
|
||||
if(mHeaderVisible == value)
|
||||
if (mHeaderVisible == value)
|
||||
return;
|
||||
|
||||
mHeaderVisible = value;
|
||||
if(mHeader)
|
||||
mHeader->setVisible(value);
|
||||
|
||||
if (mHeader)
|
||||
{
|
||||
mHeader->setVisible(value ? TRUE : FALSE);
|
||||
}
|
||||
|
||||
reshape(getRect().getWidth(), getRect().getHeight(), FALSE);
|
||||
};
|
||||
|
||||
//virtual
|
||||
BOOL LLAccordionCtrlTab::postBuild()
|
||||
{
|
||||
if(mHeader)
|
||||
if (mHeader)
|
||||
{
|
||||
mHeader->setVisible(mHeaderVisible);
|
||||
|
||||
static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
|
||||
}
|
||||
|
||||
static LLUICachedControl<S32> scrollbar_size("UIScrollbarSize", 0);
|
||||
|
||||
LLRect scroll_rect;
|
||||
scroll_rect.setOriginAndSize(
|
||||
scroll_rect.setOriginAndSize(
|
||||
getRect().getWidth() - scrollbar_size,
|
||||
1,
|
||||
scrollbar_size,
|
||||
|
|
@ -661,7 +668,7 @@ BOOL LLAccordionCtrlTab::postBuild()
|
|||
|
||||
mContainerPanel = findContainerView();
|
||||
|
||||
if(!mFitPanel)
|
||||
if (!mFitPanel)
|
||||
{
|
||||
LLScrollbar::Params sbparams;
|
||||
sbparams.name("scrollable vertical");
|
||||
|
|
@ -674,9 +681,8 @@ BOOL LLAccordionCtrlTab::postBuild()
|
|||
sbparams.follows.flags(FOLLOWS_RIGHT | FOLLOWS_TOP | FOLLOWS_BOTTOM);
|
||||
sbparams.change_callback(boost::bind(&LLAccordionCtrlTab::onScrollPosChangeCallback, this, _1, _2));
|
||||
|
||||
|
||||
mScrollbar = LLUICtrlFactory::create<LLScrollbar> (sbparams);
|
||||
LLView::addChild( mScrollbar );
|
||||
mScrollbar = LLUICtrlFactory::create<LLScrollbar>(sbparams);
|
||||
LLView::addChild(mScrollbar);
|
||||
mScrollbar->setFollowsRight();
|
||||
mScrollbar->setFollowsTop();
|
||||
mScrollbar->setFollowsBottom();
|
||||
|
|
@ -684,44 +690,48 @@ BOOL LLAccordionCtrlTab::postBuild()
|
|||
mScrollbar->setVisible(false);
|
||||
}
|
||||
|
||||
if(mContainerPanel)
|
||||
if (mContainerPanel)
|
||||
{
|
||||
mContainerPanel->setVisible(mDisplayChildren);
|
||||
}
|
||||
|
||||
return LLUICtrl::postBuild();
|
||||
}
|
||||
bool LLAccordionCtrlTab::notifyChildren (const LLSD& info)
|
||||
|
||||
bool LLAccordionCtrlTab::notifyChildren (const LLSD& info)
|
||||
{
|
||||
if(info.has("action"))
|
||||
if (info.has("action"))
|
||||
{
|
||||
std::string str_action = info["action"];
|
||||
if(str_action == "store_state")
|
||||
if (str_action == "store_state")
|
||||
{
|
||||
storeOpenCloseState();
|
||||
return true;
|
||||
}
|
||||
if(str_action == "restore_state")
|
||||
|
||||
if (str_action == "restore_state")
|
||||
{
|
||||
restoreOpenCloseState();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return LLUICtrl::notifyChildren(info);
|
||||
}
|
||||
|
||||
S32 LLAccordionCtrlTab::notifyParent(const LLSD& info)
|
||||
{
|
||||
if(info.has("action"))
|
||||
if (info.has("action"))
|
||||
{
|
||||
std::string str_action = info["action"];
|
||||
if(str_action == "size_changes")
|
||||
if (str_action == "size_changes")
|
||||
{
|
||||
//
|
||||
S32 height = info["height"];
|
||||
height = llmax(height,10) + HEADER_HEIGHT + getPaddingTop() + getPaddingBottom();
|
||||
height = llmax(height, 10) + HEADER_HEIGHT + getPaddingTop() + getPaddingBottom();
|
||||
|
||||
mExpandedHeight = height;
|
||||
|
||||
if(isExpanded() && !mSkipChangesOnNotifyParent)
|
||||
if (isExpanded() && !mSkipChangesOnNotifyParent)
|
||||
{
|
||||
LLRect panel_rect = getRect();
|
||||
panel_rect.setLeftTopAndSize( panel_rect.mLeft, panel_rect.mTop, panel_rect.getWidth(), height);
|
||||
|
|
@ -729,12 +739,13 @@ S32 LLAccordionCtrlTab::notifyParent(const LLSD& info)
|
|||
setRect(panel_rect);
|
||||
}
|
||||
|
||||
//LLAccordionCtrl should rearrange accordion tab if one of accordion change its size
|
||||
// LLAccordionCtrl should rearrange accordion tab if one of accordions changed its size
|
||||
if (getParent()) // A parent may not be set if tabs are added dynamically.
|
||||
getParent()->notifyParent(info);
|
||||
return 1;
|
||||
}
|
||||
else if(str_action == "select_prev")
|
||||
|
||||
if (str_action == "select_prev")
|
||||
{
|
||||
showAndFocusHeader();
|
||||
return 1;
|
||||
|
|
@ -772,78 +783,85 @@ S32 LLAccordionCtrlTab::notifyParent(const LLSD& info)
|
|||
|
||||
S32 LLAccordionCtrlTab::notify(const LLSD& info)
|
||||
{
|
||||
if(info.has("action"))
|
||||
if (info.has("action"))
|
||||
{
|
||||
std::string str_action = info["action"];
|
||||
if(str_action == "select_first")
|
||||
if (str_action == "select_first")
|
||||
{
|
||||
showAndFocusHeader();
|
||||
return 1;
|
||||
}
|
||||
else if( str_action == "select_last" )
|
||||
|
||||
if (str_action == "select_last")
|
||||
{
|
||||
if(getDisplayChildren() == false)
|
||||
if (!getDisplayChildren())
|
||||
{
|
||||
showAndFocusHeader();
|
||||
}
|
||||
else
|
||||
{
|
||||
LLView* view = getAccordionView();
|
||||
if(view)
|
||||
view->notify(LLSD().with("action","select_last"));
|
||||
if (view)
|
||||
{
|
||||
view->notify(LLSD().with("action", "select_last"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
BOOL LLAccordionCtrlTab::handleKey(KEY key, MASK mask, BOOL called_from_parent)
|
||||
{
|
||||
if( !mHeader->hasFocus() )
|
||||
if (!mHeader->hasFocus())
|
||||
return LLUICtrl::handleKey(key, mask, called_from_parent);
|
||||
|
||||
if ( (key == KEY_RETURN )&& mask == MASK_NONE)
|
||||
if ((key == KEY_RETURN) && mask == MASK_NONE)
|
||||
{
|
||||
changeOpenClose(getDisplayChildren());
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if ( (key == KEY_ADD || key == KEY_RIGHT)&& mask == MASK_NONE)
|
||||
if ((key == KEY_ADD || key == KEY_RIGHT) && mask == MASK_NONE)
|
||||
{
|
||||
if(getDisplayChildren() == false)
|
||||
{
|
||||
changeOpenClose(getDisplayChildren());
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
if ( (key == KEY_SUBTRACT || key == KEY_LEFT)&& mask == MASK_NONE)
|
||||
{
|
||||
if(getDisplayChildren() == true)
|
||||
if (!getDisplayChildren())
|
||||
{
|
||||
changeOpenClose(getDisplayChildren());
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if ( key == KEY_DOWN && mask == MASK_NONE)
|
||||
if ((key == KEY_SUBTRACT || key == KEY_LEFT) && mask == MASK_NONE)
|
||||
{
|
||||
//if collapsed go to the next accordion
|
||||
if(getDisplayChildren() == false)
|
||||
//we processing notifyParent so let call parent directly
|
||||
getParent()->notifyParent(LLSD().with("action","select_next"));
|
||||
if (getDisplayChildren())
|
||||
{
|
||||
changeOpenClose(getDisplayChildren());
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (key == KEY_DOWN && mask == MASK_NONE)
|
||||
{
|
||||
// if collapsed go to the next accordion
|
||||
if (!getDisplayChildren())
|
||||
{
|
||||
// we're processing notifyParent so let call parent directly
|
||||
getParent()->notifyParent(LLSD().with("action", "select_next"));
|
||||
}
|
||||
else
|
||||
{
|
||||
getAccordionView()->notify(LLSD().with("action","select_first"));
|
||||
getAccordionView()->notify(LLSD().with("action", "select_first"));
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if ( key == KEY_UP && mask == MASK_NONE)
|
||||
if (key == KEY_UP && mask == MASK_NONE)
|
||||
{
|
||||
//go to the previous accordion
|
||||
// go to the previous accordion
|
||||
|
||||
//we processing notifyParent so let call parent directly
|
||||
getParent()->notifyParent(LLSD().with("action","select_prev"));
|
||||
// we're processing notifyParent so let call parent directly
|
||||
getParent()->notifyParent(LLSD().with("action", "select_prev"));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -869,28 +887,29 @@ void LLAccordionCtrlTab::showAndFocusHeader()
|
|||
// accordion tab (assuming that the parent is an LLAccordionCtrl) the calls chain
|
||||
// is shortened and messages from inside the collapsed tabs are avoided.
|
||||
// See STORM-536.
|
||||
getParent()->notifyParent(LLSD().with("scrollToShowRect",screen_rc.getValue()));
|
||||
getParent()->notifyParent(LLSD().with("scrollToShowRect", screen_rc.getValue()));
|
||||
}
|
||||
void LLAccordionCtrlTab::storeOpenCloseState()
|
||||
|
||||
void LLAccordionCtrlTab::storeOpenCloseState()
|
||||
{
|
||||
if(mWasStateStored)
|
||||
if (mWasStateStored)
|
||||
return;
|
||||
mStoredOpenCloseState = getDisplayChildren();
|
||||
mWasStateStored = true;
|
||||
}
|
||||
|
||||
void LLAccordionCtrlTab::restoreOpenCloseState()
|
||||
void LLAccordionCtrlTab::restoreOpenCloseState()
|
||||
{
|
||||
if(!mWasStateStored)
|
||||
if (!mWasStateStored)
|
||||
return;
|
||||
if(getDisplayChildren() != mStoredOpenCloseState)
|
||||
if (getDisplayChildren() != mStoredOpenCloseState)
|
||||
{
|
||||
changeOpenClose(getDisplayChildren());
|
||||
}
|
||||
mWasStateStored = false;
|
||||
}
|
||||
|
||||
void LLAccordionCtrlTab::adjustContainerPanel ()
|
||||
void LLAccordionCtrlTab::adjustContainerPanel()
|
||||
{
|
||||
S32 width = getRect().getWidth();
|
||||
S32 height = getRect().getHeight();
|
||||
|
|
@ -907,83 +926,83 @@ void LLAccordionCtrlTab::adjustContainerPanel ()
|
|||
|
||||
void LLAccordionCtrlTab::adjustContainerPanel(const LLRect& child_rect)
|
||||
{
|
||||
if(!mContainerPanel)
|
||||
if (!mContainerPanel)
|
||||
return;
|
||||
|
||||
if(!mFitPanel)
|
||||
if (!mFitPanel)
|
||||
{
|
||||
show_hide_scrollbar(child_rect);
|
||||
updateLayout(child_rect);
|
||||
}
|
||||
else
|
||||
{
|
||||
mContainerPanel->reshape(child_rect.getWidth(),child_rect.getHeight());
|
||||
mContainerPanel->reshape(child_rect.getWidth(), child_rect.getHeight());
|
||||
mContainerPanel->setRect(child_rect);
|
||||
}
|
||||
}
|
||||
|
||||
S32 LLAccordionCtrlTab::getChildViewHeight()
|
||||
{
|
||||
if(!mContainerPanel)
|
||||
if (!mContainerPanel)
|
||||
return 0;
|
||||
return mContainerPanel->getRect().getHeight();
|
||||
}
|
||||
|
||||
void LLAccordionCtrlTab::show_hide_scrollbar(const LLRect& child_rect)
|
||||
{
|
||||
if(getChildViewHeight() > child_rect.getHeight() )
|
||||
if (getChildViewHeight() > child_rect.getHeight())
|
||||
showScrollbar(child_rect);
|
||||
else
|
||||
hideScrollbar(child_rect);
|
||||
}
|
||||
|
||||
void LLAccordionCtrlTab::showScrollbar(const LLRect& child_rect)
|
||||
{
|
||||
if(!mContainerPanel || !mScrollbar)
|
||||
if (!mContainerPanel || !mScrollbar)
|
||||
return;
|
||||
bool was_visible = mScrollbar->getVisible();
|
||||
mScrollbar->setVisible(true);
|
||||
|
||||
static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
|
||||
|
||||
{
|
||||
ctrlSetLeftTopAndSize(mScrollbar,child_rect.getWidth()-scrollbar_size,
|
||||
child_rect.getHeight()-PARENT_BORDER_MARGIN,
|
||||
scrollbar_size,
|
||||
child_rect.getHeight()-2*PARENT_BORDER_MARGIN);
|
||||
}
|
||||
ctrlSetLeftTopAndSize(mScrollbar,
|
||||
child_rect.getWidth() - scrollbar_size,
|
||||
child_rect.getHeight() - PARENT_BORDER_MARGIN,
|
||||
scrollbar_size,
|
||||
child_rect.getHeight() - PARENT_BORDER_MARGIN * 2);
|
||||
|
||||
LLRect orig_rect = mContainerPanel->getRect();
|
||||
|
||||
mScrollbar->setPageSize(child_rect.getHeight());
|
||||
mScrollbar->setDocParams(orig_rect.getHeight(),mScrollbar->getDocPos());
|
||||
mScrollbar->setDocParams(orig_rect.getHeight(), mScrollbar->getDocPos());
|
||||
|
||||
if(was_visible)
|
||||
if (was_visible)
|
||||
{
|
||||
S32 scroll_pos = llmin(mScrollbar->getDocPos(), orig_rect.getHeight() - child_rect.getHeight() - 1);
|
||||
mScrollbar->setDocPos(scroll_pos);
|
||||
}
|
||||
else//shrink child panel
|
||||
else // Shrink child panel
|
||||
{
|
||||
updateLayout(child_rect);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void LLAccordionCtrlTab::hideScrollbar( const LLRect& child_rect )
|
||||
void LLAccordionCtrlTab::hideScrollbar(const LLRect& child_rect)
|
||||
{
|
||||
if(!mContainerPanel || !mScrollbar)
|
||||
if (!mContainerPanel || !mScrollbar)
|
||||
return;
|
||||
|
||||
if(mScrollbar->getVisible() == false)
|
||||
if (mScrollbar->getVisible() == FALSE)
|
||||
return;
|
||||
mScrollbar->setVisible(false);
|
||||
|
||||
mScrollbar->setVisible(FALSE);
|
||||
mScrollbar->setDocPos(0);
|
||||
|
||||
//shrink child panel
|
||||
updateLayout(child_rect);
|
||||
}
|
||||
|
||||
void LLAccordionCtrlTab::onScrollPosChangeCallback(S32, LLScrollbar*)
|
||||
void LLAccordionCtrlTab::onScrollPosChangeCallback(S32, LLScrollbar*)
|
||||
{
|
||||
LLRect child_rect;
|
||||
|
||||
|
|
@ -999,21 +1018,20 @@ void LLAccordionCtrlTab::onScrollPosChangeCallback(S32, LLScrollbar*)
|
|||
updateLayout(child_rect);
|
||||
}
|
||||
|
||||
void LLAccordionCtrlTab::drawChild(const LLRect& root_rect,LLView* child)
|
||||
void LLAccordionCtrlTab::drawChild(const LLRect& root_rect, LLView* child)
|
||||
{
|
||||
if (child && child->getVisible() && child->getRect().isValid())
|
||||
{
|
||||
LLRect screen_rect;
|
||||
localRectToScreen(child->getRect(),&screen_rect);
|
||||
|
||||
if ( root_rect.overlaps(screen_rect) && sDirtyRect.overlaps(screen_rect))
|
||||
localRectToScreen(child->getRect(), &screen_rect);
|
||||
|
||||
if (root_rect.overlaps(screen_rect) && sDirtyRect.overlaps(screen_rect))
|
||||
{
|
||||
gGL.matrixMode(LLRender::MM_MODELVIEW);
|
||||
LLUI::pushMatrix();
|
||||
{
|
||||
LLUI::translate((F32)child->getRect().mLeft, (F32)child->getRect().mBottom);
|
||||
child->draw();
|
||||
|
||||
}
|
||||
LLUI::popMatrix();
|
||||
}
|
||||
|
|
@ -1022,64 +1040,67 @@ void LLAccordionCtrlTab::drawChild(const LLRect& root_rect,LLView* child)
|
|||
|
||||
void LLAccordionCtrlTab::draw()
|
||||
{
|
||||
if(mFitPanel)
|
||||
if (mFitPanel)
|
||||
{
|
||||
LLUICtrl::draw();
|
||||
}
|
||||
else
|
||||
{
|
||||
LLRect root_rect = getRootView()->getRect();
|
||||
drawChild(root_rect,mHeader);
|
||||
drawChild(root_rect,mScrollbar );
|
||||
{
|
||||
LLRect child_rect;
|
||||
LLRect root_rect(getRootView()->getRect());
|
||||
drawChild(root_rect, mHeader);
|
||||
drawChild(root_rect, mScrollbar);
|
||||
|
||||
S32 width = getRect().getWidth();
|
||||
S32 height = getRect().getHeight();
|
||||
LLRect child_rect;
|
||||
|
||||
child_rect.setLeftTopAndSize(
|
||||
getPaddingLeft(),
|
||||
height - getHeaderHeight() - getPaddingTop(),
|
||||
width - getPaddingLeft() - getPaddingRight(),
|
||||
height - getHeaderHeight() - getPaddingTop() - getPaddingBottom() );
|
||||
S32 width = getRect().getWidth();
|
||||
S32 height = getRect().getHeight();
|
||||
|
||||
LLLocalClipRect clip(child_rect);
|
||||
drawChild(root_rect,mContainerPanel);
|
||||
}
|
||||
child_rect.setLeftTopAndSize(
|
||||
getPaddingLeft(),
|
||||
height - getHeaderHeight() - getPaddingTop(),
|
||||
width - getPaddingLeft() - getPaddingRight(),
|
||||
height - getHeaderHeight() - getPaddingTop() - getPaddingBottom());
|
||||
|
||||
LLLocalClipRect clip(child_rect);
|
||||
drawChild(root_rect,mContainerPanel);
|
||||
}
|
||||
}
|
||||
|
||||
void LLAccordionCtrlTab::updateLayout ( const LLRect& child_rect )
|
||||
void LLAccordionCtrlTab::updateLayout(const LLRect& child_rect)
|
||||
{
|
||||
LLView* child = getAccordionView();
|
||||
if(!mContainerPanel)
|
||||
if (!mContainerPanel)
|
||||
return;
|
||||
|
||||
S32 panel_top = child_rect.getHeight();
|
||||
S32 panel_width = child_rect.getWidth();
|
||||
|
||||
static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
|
||||
if(mScrollbar && mScrollbar->getVisible() != false)
|
||||
static LLUICachedControl<S32> scrollbar_size("UIScrollbarSize", 0);
|
||||
if (mScrollbar && mScrollbar->getVisible())
|
||||
{
|
||||
panel_top+=mScrollbar->getDocPos();
|
||||
panel_width-=scrollbar_size;
|
||||
panel_top += mScrollbar->getDocPos();
|
||||
panel_width -= scrollbar_size;
|
||||
}
|
||||
|
||||
//set sizes for first panels and dragbars
|
||||
// Set sizes for first panels and dragbars
|
||||
LLRect panel_rect = child->getRect();
|
||||
ctrlSetLeftTopAndSize(mContainerPanel,child_rect.mLeft,panel_top,panel_width,panel_rect.getHeight());
|
||||
ctrlSetLeftTopAndSize(mContainerPanel, child_rect.mLeft, panel_top, panel_width, panel_rect.getHeight());
|
||||
}
|
||||
|
||||
void LLAccordionCtrlTab::ctrlSetLeftTopAndSize(LLView* panel, S32 left, S32 top, S32 width, S32 height)
|
||||
{
|
||||
if(!panel)
|
||||
if (!panel)
|
||||
return;
|
||||
LLRect panel_rect = panel->getRect();
|
||||
panel_rect.setLeftTopAndSize( left, top, width, height);
|
||||
panel_rect.setLeftTopAndSize(left, top, width, height);
|
||||
panel->reshape( width, height, 1);
|
||||
panel->setRect(panel_rect);
|
||||
}
|
||||
|
||||
BOOL LLAccordionCtrlTab::handleToolTip(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
//header may be not the first child but we need to process it first
|
||||
if(y >= (getRect().getHeight() - HEADER_HEIGHT - HEADER_HEIGHT/2) )
|
||||
if (y >= (getRect().getHeight() - HEADER_HEIGHT - HEADER_HEIGHT / 2))
|
||||
{
|
||||
//inside tab header
|
||||
//fix for EXT-6619
|
||||
|
|
@ -1088,16 +1109,18 @@ BOOL LLAccordionCtrlTab::handleToolTip(S32 x, S32 y, MASK mask)
|
|||
}
|
||||
return LLUICtrl::handleToolTip(x, y, mask);
|
||||
}
|
||||
BOOL LLAccordionCtrlTab::handleScrollWheel ( S32 x, S32 y, S32 clicks )
|
||||
|
||||
BOOL LLAccordionCtrlTab::handleScrollWheel(S32 x, S32 y, S32 clicks)
|
||||
{
|
||||
if( LLUICtrl::handleScrollWheel(x,y,clicks))
|
||||
if (LLUICtrl::handleScrollWheel(x, y, clicks))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
if( mScrollbar && mScrollbar->getVisible() && mScrollbar->handleScrollWheel( 0, 0, clicks ) )
|
||||
|
||||
if (mScrollbar && mScrollbar->getVisible() && mScrollbar->handleScrollWheel(0, 0, clicks))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ public:
|
|||
virtual void setDisplayChildren(bool display);
|
||||
|
||||
// Returns expand/collapse state
|
||||
virtual bool getDisplayChildren() const {return mDisplayChildren;};
|
||||
virtual bool getDisplayChildren() const { return mDisplayChildren; };
|
||||
|
||||
//set LLAccordionCtrlTab panel
|
||||
void setAccordionView(LLView* panel);
|
||||
|
|
|
|||
|
|
@ -203,7 +203,8 @@ LLButton::LLButton(const LLButton::Params& p)
|
|||
}
|
||||
|
||||
// Hack to make sure there is space for at least one character
|
||||
if (getRect().getWidth() - (mRightHPad + mLeftHPad) < mGLFont->getWidth(std::string(" ")))
|
||||
if (getRect().mRight >= 0 && getRect().getWidth() > 0 &&
|
||||
getRect().getWidth() - (mRightHPad + mLeftHPad) < mGLFont->getWidth(std::string(" ")))
|
||||
{
|
||||
// Use old defaults
|
||||
mLeftHPad = llbutton_orig_h_pad;
|
||||
|
|
@ -942,11 +943,8 @@ void LLButton::draw()
|
|||
break;
|
||||
}
|
||||
|
||||
S32 y_offset = 2 + (getRect().getHeight() - 20)/2;
|
||||
|
||||
if (pressed && mDisplayPressedState)
|
||||
{
|
||||
y_offset--;
|
||||
x++;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ LLDragHandle::LLDragHandle(const LLDragHandle::Params& p)
|
|||
|
||||
LLDragHandle::~LLDragHandle()
|
||||
{
|
||||
gFocusMgr.removeKeyboardFocusWithoutCallback(this);
|
||||
removeChild(mTitleBox);
|
||||
delete mTitleBox;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1198,7 +1198,7 @@ void LLFlatListView::onFocusReceived()
|
|||
{
|
||||
if (size())
|
||||
{
|
||||
mSelectedItemsBorder->setVisible(TRUE);
|
||||
mSelectedItemsBorder->setVisible(TRUE);
|
||||
}
|
||||
gEditMenuHandler = this;
|
||||
}
|
||||
|
|
@ -1207,7 +1207,7 @@ void LLFlatListView::onFocusLost()
|
|||
{
|
||||
mSelectedItemsBorder->setVisible(FALSE);
|
||||
// Route menu back to the default
|
||||
if( gEditMenuHandler == this )
|
||||
if (gEditMenuHandler == this)
|
||||
{
|
||||
gEditMenuHandler = NULL;
|
||||
}
|
||||
|
|
@ -1216,16 +1216,16 @@ void LLFlatListView::onFocusLost()
|
|||
//virtual
|
||||
S32 LLFlatListView::notify(const LLSD& info)
|
||||
{
|
||||
if(info.has("action"))
|
||||
if (info.has("action"))
|
||||
{
|
||||
std::string str_action = info["action"];
|
||||
if(str_action == "select_first")
|
||||
if (str_action == "select_first")
|
||||
{
|
||||
setFocus(true);
|
||||
selectFirstItem();
|
||||
return 1;
|
||||
}
|
||||
else if(str_action == "select_last")
|
||||
else if (str_action == "select_last")
|
||||
{
|
||||
setFocus(true);
|
||||
selectLastItem();
|
||||
|
|
@ -1238,6 +1238,7 @@ S32 LLFlatListView::notify(const LLSD& info)
|
|||
notifyParentItemsRectChanged();
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1249,10 +1250,8 @@ void LLFlatListView::detachItems(std::vector<LLPanel*>& detached_items)
|
|||
detached_items.clear();
|
||||
// Go through items and detach valid items, remove them from items panel
|
||||
// and add to detached_items.
|
||||
for (pairs_iterator_t
|
||||
iter = mItemPairs.begin(),
|
||||
iter_end = mItemPairs.end();
|
||||
iter != iter_end; ++iter)
|
||||
pairs_iterator_t iter = mItemPairs.begin(), iter_end = mItemPairs.end();
|
||||
while (iter != iter_end)
|
||||
{
|
||||
LLPanel* pItem = (*iter)->first;
|
||||
if (1 == pItem->notify(action))
|
||||
|
|
@ -1261,6 +1260,7 @@ void LLFlatListView::detachItems(std::vector<LLPanel*>& detached_items)
|
|||
mItemsPanel->removeChild(pItem);
|
||||
detached_items.push_back(pItem);
|
||||
}
|
||||
iter++;
|
||||
}
|
||||
if (!detached_items.empty())
|
||||
{
|
||||
|
|
@ -1268,13 +1268,12 @@ void LLFlatListView::detachItems(std::vector<LLPanel*>& detached_items)
|
|||
if (detached_items.size() == mItemPairs.size())
|
||||
{
|
||||
// This way will be faster if all items were disconnected
|
||||
for (pairs_iterator_t
|
||||
iter = mItemPairs.begin(),
|
||||
iter_end = mItemPairs.end();
|
||||
iter != iter_end; ++iter)
|
||||
pairs_iterator_t iter = mItemPairs.begin(), iter_end = mItemPairs.end();
|
||||
while (iter != iter_end)
|
||||
{
|
||||
(*iter)->first = NULL;
|
||||
delete *iter;
|
||||
iter++;
|
||||
}
|
||||
mItemPairs.clear();
|
||||
// Also set items panel height to zero.
|
||||
|
|
@ -1287,16 +1286,14 @@ void LLFlatListView::detachItems(std::vector<LLPanel*>& detached_items)
|
|||
}
|
||||
else
|
||||
{
|
||||
for (std::vector<LLPanel*>::const_iterator
|
||||
detached_iter = detached_items.begin(),
|
||||
detached_iter_end = detached_items.end();
|
||||
detached_iter != detached_iter_end; ++detached_iter)
|
||||
std::vector<LLPanel*>::const_iterator
|
||||
detached_iter = detached_items.begin(),
|
||||
detached_iter_end = detached_items.end();
|
||||
while (detached_iter < detached_iter_end)
|
||||
{
|
||||
LLPanel* pDetachedItem = *detached_iter;
|
||||
for (pairs_iterator_t
|
||||
iter = mItemPairs.begin(),
|
||||
iter_end = mItemPairs.end();
|
||||
iter != iter_end; ++iter)
|
||||
pairs_iterator_t iter = mItemPairs.begin(), iter_end = mItemPairs.end();
|
||||
while (iter != iter_end)
|
||||
{
|
||||
item_pair_t* item_pair = *iter;
|
||||
if (item_pair->first == pDetachedItem)
|
||||
|
|
@ -1306,7 +1303,9 @@ void LLFlatListView::detachItems(std::vector<LLPanel*>& detached_items)
|
|||
delete item_pair;
|
||||
break;
|
||||
}
|
||||
iter++;
|
||||
}
|
||||
detached_iter++;
|
||||
}
|
||||
rearrangeItems();
|
||||
}
|
||||
|
|
@ -1322,7 +1321,6 @@ LLFlatListViewEx::Params::Params()
|
|||
: no_items_msg("no_items_msg")
|
||||
, no_filtered_items_msg("no_filtered_items_msg")
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
LLFlatListViewEx::LLFlatListViewEx(const Params& p)
|
||||
|
|
@ -1332,7 +1330,6 @@ LLFlatListViewEx::LLFlatListViewEx(const Params& p)
|
|||
, mForceShowingUnmatchedItems(false)
|
||||
, mHasMatchedItems(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void LLFlatListViewEx::updateNoItemsMessage(const std::string& filter_string)
|
||||
|
|
@ -1352,7 +1349,6 @@ void LLFlatListViewEx::updateNoItemsMessage(const std::string& filter_string)
|
|||
// list does not contain any items at all
|
||||
setNoItemsCommentText(mNoItemsMsg);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool LLFlatListViewEx::getForceShowingUnmatchedItems()
|
||||
|
|
@ -1411,12 +1407,10 @@ void LLFlatListViewEx::filterItems()
|
|||
getItems(items);
|
||||
|
||||
mHasMatchedItems = false;
|
||||
for (item_panel_list_t::iterator
|
||||
iter = items.begin(),
|
||||
iter_end = items.end();
|
||||
iter != iter_end; ++iter)
|
||||
item_panel_list_t::iterator iter = items.begin(), iter_end = items.end();
|
||||
while (iter < iter_end)
|
||||
{
|
||||
LLPanel* pItem = (*iter);
|
||||
LLPanel* pItem = *(iter++);
|
||||
updateItemVisibility(pItem, action);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -189,7 +189,9 @@ LLFolderView::LLFolderView(const Params& p)
|
|||
mStatusTextBox(NULL),
|
||||
mShowItemLinkOverlays(p.show_item_link_overlays),
|
||||
mViewModel(p.view_model),
|
||||
mGroupedItemModel(p.grouped_item_model)
|
||||
mGroupedItemModel(p.grouped_item_model),
|
||||
mForceArrange(false),
|
||||
mSingleFolderMode(false)
|
||||
{
|
||||
LLPanel* panel = p.parent_panel;
|
||||
mParentPanel = panel->getHandle();
|
||||
|
|
@ -609,6 +611,7 @@ void LLFolderView::clearSelection()
|
|||
}
|
||||
|
||||
mSelectedItems.clear();
|
||||
mNeedsScroll = false;
|
||||
}
|
||||
|
||||
std::set<LLFolderViewItem*> LLFolderView::getSelectionList() const
|
||||
|
|
@ -665,7 +668,7 @@ void LLFolderView::draw()
|
|||
}
|
||||
else if (mShowEmptyMessage)
|
||||
{
|
||||
mStatusTextBox->setValue(getFolderViewModel()->getStatusText());
|
||||
mStatusTextBox->setValue(getFolderViewModel()->getStatusText(mItems.empty() && mFolders.empty()));
|
||||
mStatusTextBox->setVisible( TRUE );
|
||||
|
||||
// firstly reshape message textbox with current size. This is necessary to
|
||||
|
|
@ -693,12 +696,16 @@ void LLFolderView::draw()
|
|||
}
|
||||
}
|
||||
|
||||
if (mRenameItem && mRenamer && mRenamer->getVisible() && !getVisibleRect().overlaps(mRenamer->getRect()))
|
||||
{
|
||||
// renamer is not connected to the item we are renaming in any form so manage it manually
|
||||
// TODO: consider stopping on any scroll action instead of when out of visible area
|
||||
finishRenamingItem();
|
||||
}
|
||||
if (mRenameItem
|
||||
&& mRenamer
|
||||
&& mRenamer->getVisible()
|
||||
&& !getVisibleRect().overlaps(mRenamer->getRect()))
|
||||
{
|
||||
// renamer is not connected to the item we are renaming in any form so manage it manually
|
||||
// TODO: consider stopping on any scroll action instead of when out of visible area
|
||||
LL_DEBUGS("Inventory") << "Renamer out of bounds, hiding" << LL_ENDL;
|
||||
finishRenamingItem();
|
||||
}
|
||||
|
||||
// skip over LLFolderViewFolder::draw since we don't want the folder icon, label,
|
||||
// and arrow for the root folder
|
||||
|
|
@ -832,9 +839,12 @@ void LLFolderView::autoOpenItem( LLFolderViewFolder* item )
|
|||
mAutoOpenItems.push(item);
|
||||
|
||||
item->setOpen(TRUE);
|
||||
if(!item->isSingleFolderMode())
|
||||
{
|
||||
LLRect content_rect = (mScrollContainer ? mScrollContainer->getContentWindowRect() : LLRect());
|
||||
LLRect constraint_rect(0,content_rect.getHeight(), content_rect.getWidth(), 0);
|
||||
scrollToShowItem(item, constraint_rect);
|
||||
}
|
||||
}
|
||||
|
||||
void LLFolderView::closeAutoOpenedFolders()
|
||||
|
|
@ -1038,6 +1048,8 @@ void LLFolderView::paste()
|
|||
// public rename functionality - can only start the process
|
||||
void LLFolderView::startRenamingSelectedItem( void )
|
||||
{
|
||||
LL_DEBUGS("Inventory") << "Starting inventory renamer" << LL_ENDL;
|
||||
|
||||
// make sure selection is visible
|
||||
scrollToShowSelection();
|
||||
|
||||
|
|
@ -1273,6 +1285,11 @@ BOOL LLFolderView::handleKeyHere( KEY key, MASK mask )
|
|||
if(mSelectedItems.size())
|
||||
{
|
||||
LLFolderViewItem* last_selected = getCurSelectedItem();
|
||||
if(last_selected && last_selected->isSingleFolderMode())
|
||||
{
|
||||
handled = FALSE;
|
||||
break;
|
||||
}
|
||||
LLFolderViewItem* parent_folder = last_selected->getParentFolder();
|
||||
if (!last_selected->isOpen() && parent_folder && parent_folder->getParentFolder())
|
||||
{
|
||||
|
|
@ -1458,9 +1475,19 @@ BOOL LLFolderView::handleRightMouseDown( S32 x, S32 y, MASK mask )
|
|||
mCallbackRegistrar->popScope();
|
||||
}
|
||||
}
|
||||
|
||||
BOOL item_clicked = FALSE;
|
||||
for (selected_items_t::iterator item_it = mSelectedItems.begin(); item_it != mSelectedItems.end(); ++item_it)
|
||||
{
|
||||
item_clicked |= (*item_it)->getRect().pointInRect(x, y);
|
||||
}
|
||||
if(!item_clicked && mSingleFolderMode)
|
||||
{
|
||||
clearSelection();
|
||||
}
|
||||
bool hide_folder_menu = mSuppressFolderMenu && isFolderSelected();
|
||||
if (menu && (handled
|
||||
&& ( count > 0 && (hasVisibleChildren()) )) && // show menu only if selected items are visible
|
||||
if (menu && (mSingleFolderMode || (handled
|
||||
&& ( count > 0 && (hasVisibleChildren()) ))) && // show menu only if selected items are visible
|
||||
!hide_folder_menu)
|
||||
{
|
||||
if (mCallbackRegistrar)
|
||||
|
|
@ -1532,6 +1559,22 @@ BOOL LLFolderView::handleHover( S32 x, S32 y, MASK mask )
|
|||
return LLView::handleHover( x, y, mask );
|
||||
}
|
||||
|
||||
LLFolderViewItem* LLFolderView::getHoveredItem() const
|
||||
{
|
||||
return dynamic_cast<LLFolderViewItem*>(mHoveredItem.get());
|
||||
}
|
||||
|
||||
void LLFolderView::setHoveredItem(LLFolderViewItem* itemp)
|
||||
{
|
||||
if (mHoveredItem.get() != itemp)
|
||||
{
|
||||
if (itemp)
|
||||
mHoveredItem = itemp->getHandle();
|
||||
else
|
||||
mHoveredItem.markDead();
|
||||
}
|
||||
}
|
||||
|
||||
BOOL LLFolderView::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
|
||||
EDragAndDropType cargo_type,
|
||||
void* cargo_data,
|
||||
|
|
@ -1716,7 +1759,7 @@ void LLFolderView::update()
|
|||
mNeedsAutoSelect = FALSE;
|
||||
}
|
||||
|
||||
BOOL is_visible = isInVisibleChain();
|
||||
BOOL is_visible = isInVisibleChain() || mForceArrange;
|
||||
|
||||
//Puts folders/items in proper positions
|
||||
// arrange() takes the model filter flag into account and call sort() if necessary (CHUI-849)
|
||||
|
|
@ -1817,13 +1860,28 @@ void LLFolderView::update()
|
|||
}
|
||||
}
|
||||
|
||||
if (mSignalSelectCallback)
|
||||
{
|
||||
//RN: we use keyboard focus as a proxy for user-explicit actions
|
||||
BOOL take_keyboard_focus = (mSignalSelectCallback == SIGNAL_KEYBOARD_FOCUS);
|
||||
mSelectSignal(mSelectedItems, take_keyboard_focus);
|
||||
}
|
||||
mSignalSelectCallback = FALSE;
|
||||
if (mSelectedItems.size())
|
||||
{
|
||||
LLFolderViewItem* item = mSelectedItems.back();
|
||||
// If the goal is to show renamer, don't callback untill
|
||||
// item is visible or is no longer being scrolled to.
|
||||
// Otherwise renamer will be instantly closed
|
||||
// Todo: consider moving renamer out of selection callback
|
||||
if (!mNeedsAutoRename || !mNeedsScroll || item->getVisible())
|
||||
{
|
||||
if (mSignalSelectCallback)
|
||||
{
|
||||
//RN: we use keyboard focus as a proxy for user-explicit actions
|
||||
BOOL take_keyboard_focus = (mSignalSelectCallback == SIGNAL_KEYBOARD_FOCUS);
|
||||
mSelectSignal(mSelectedItems, take_keyboard_focus);
|
||||
}
|
||||
mSignalSelectCallback = FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mSignalSelectCallback = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
void LLFolderView::dumpSelectionInformation()
|
||||
|
|
@ -1886,6 +1944,11 @@ void LLFolderView::updateMenuOptions(LLMenuGL* menu)
|
|||
flags = multi_select_flag;
|
||||
}
|
||||
|
||||
if(mSingleFolderMode && (mSelectedItems.size() == 0))
|
||||
{
|
||||
buildContextMenu(*menu, flags);
|
||||
}
|
||||
|
||||
// This adds a check for restrictions based on the entire
|
||||
// selection set - for example, any one wearable may not push you
|
||||
// over the limit, but all wearables together still might.
|
||||
|
|
@ -2042,7 +2105,7 @@ LLFolderViewItem* LLFolderView::getNextUnselectedItem()
|
|||
return new_selection;
|
||||
}
|
||||
|
||||
S32 LLFolderView::getItemHeight()
|
||||
S32 LLFolderView::getItemHeight() const
|
||||
{
|
||||
if(!hasVisibleChildren())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -127,6 +127,9 @@ public:
|
|||
bool getAllowMultiSelect() { return mAllowMultiSelect; }
|
||||
bool getAllowDrag() { return mAllowDrag; }
|
||||
|
||||
void setSingleFolderMode(bool is_single_mode) { mSingleFolderMode = is_single_mode; }
|
||||
bool isSingleFolderMode() { return mSingleFolderMode; }
|
||||
|
||||
// Close all folders in the view
|
||||
void closeAllFolders();
|
||||
void openTopLevelFolders();
|
||||
|
|
@ -136,7 +139,7 @@ public:
|
|||
// Find width and height of this object and its children. Also
|
||||
// makes sure that this view and its children are the right size.
|
||||
virtual S32 arrange( S32* width, S32* height );
|
||||
virtual S32 getItemHeight();
|
||||
virtual S32 getItemHeight() const;
|
||||
|
||||
void arrangeAll() { mArrangeGeneration++; }
|
||||
S32 getArrangeGeneration() { return mArrangeGeneration; }
|
||||
|
|
@ -144,6 +147,10 @@ public:
|
|||
// applies filters to control visibility of items
|
||||
virtual void filter( LLFolderViewFilter& filter);
|
||||
|
||||
void clearHoveredItem() { setHoveredItem(nullptr); }
|
||||
LLFolderViewItem* getHoveredItem() const;
|
||||
void setHoveredItem(LLFolderViewItem* itemp);
|
||||
|
||||
// Get the last selected item
|
||||
virtual LLFolderViewItem* getCurSelectedItem( void );
|
||||
selected_items_t& getSelectedItems( void );
|
||||
|
|
@ -210,6 +217,7 @@ public:
|
|||
virtual void draw();
|
||||
virtual void deleteAllChildren();
|
||||
|
||||
void stopAutoScollining() {mNeedsScroll = false;}
|
||||
void scrollToShowSelection();
|
||||
void scrollToShowItem(LLFolderViewItem* item, const LLRect& constraint_rect);
|
||||
void setScrollContainer( LLScrollContainer* parent ) { mScrollContainer = parent; }
|
||||
|
|
@ -237,11 +245,15 @@ public:
|
|||
void setCallbackRegistrar(LLUICtrl::CommitCallbackRegistry::ScopedRegistrar* registrar) { mCallbackRegistrar = registrar; }
|
||||
void setEnableRegistrar(LLUICtrl::EnableCallbackRegistry::ScopedRegistrar* registrar) { mEnableRegistrar = registrar; }
|
||||
|
||||
void setForceArrange(bool force) { mForceArrange = force; }
|
||||
|
||||
LLPanel* getParentPanel() { return mParentPanel.get(); }
|
||||
// DEBUG only
|
||||
void dumpSelectionInformation();
|
||||
|
||||
virtual S32 notify(const LLSD& info) ;
|
||||
|
||||
void setShowEmptyMessage(bool show_msg) { mShowEmptyMessage = show_msg; }
|
||||
|
||||
bool useLabelSuffix() { return mUseLabelSuffix; }
|
||||
virtual void updateMenu();
|
||||
|
|
@ -275,6 +287,7 @@ protected:
|
|||
LLHandle<LLView> mPopupMenuHandle;
|
||||
std::string mMenuFileName;
|
||||
|
||||
LLHandle<LLView> mHoveredItem;
|
||||
selected_items_t mSelectedItems;
|
||||
bool mKeyboardSelection,
|
||||
mAllowMultiSelect,
|
||||
|
|
@ -291,7 +304,8 @@ protected:
|
|||
mShowItemLinkOverlays,
|
||||
mShowSelectionContext,
|
||||
mShowSingleSelection,
|
||||
mSuppressFolderMenu;
|
||||
mSuppressFolderMenu,
|
||||
mSingleFolderMode;
|
||||
|
||||
// Renaming variables and methods
|
||||
LLFolderViewItem* mRenameItem; // The item currently being renamed
|
||||
|
|
@ -330,6 +344,8 @@ protected:
|
|||
|
||||
LLUICtrl::CommitCallbackRegistry::ScopedRegistrar* mCallbackRegistrar;
|
||||
LLUICtrl::EnableCallbackRegistry::ScopedRegistrar* mEnableRegistrar;
|
||||
|
||||
bool mForceArrange;
|
||||
|
||||
public:
|
||||
static F32 sAutoOpenTime;
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
#include "llfolderview.h"
|
||||
#include "llfolderviewmodel.h"
|
||||
#include "llpanel.h"
|
||||
#include "llcallbacklist.h"
|
||||
#include "llcriticaldamp.h"
|
||||
#include "llclipboard.h"
|
||||
#include "llfocusmgr.h" // gFocusMgr
|
||||
|
|
@ -113,6 +114,8 @@ LLFolderViewItem::Params::Params()
|
|||
icon_width("icon_width", 0),
|
||||
text_pad("text_pad", 0),
|
||||
text_pad_right("text_pad_right", 0),
|
||||
single_folder_mode("single_folder_mode", false),
|
||||
double_click_override("double_click_override", false),
|
||||
arrow_size("arrow_size", 0),
|
||||
max_folder_item_overlap("max_folder_item_overlap", 0)
|
||||
{ }
|
||||
|
|
@ -151,7 +154,9 @@ LLFolderViewItem::LLFolderViewItem(const LLFolderViewItem::Params& p)
|
|||
mTextPad(p.text_pad),
|
||||
mTextPadRight(p.text_pad_right),
|
||||
mArrowSize(p.arrow_size),
|
||||
mMaxFolderItemOverlap(p.max_folder_item_overlap)
|
||||
mSingleFolderMode(p.single_folder_mode),
|
||||
mMaxFolderItemOverlap(p.max_folder_item_overlap),
|
||||
mDoubleClickOverride(p.double_click_override)
|
||||
{
|
||||
if (!sColorSetInitialized)
|
||||
{
|
||||
|
|
@ -162,7 +167,7 @@ LLFolderViewItem::LLFolderViewItem(const LLFolderViewItem::Params& p)
|
|||
sMouseOverColor = LLUIColorTable::instance().getColor("InventoryMouseOverColor", DEFAULT_WHITE);
|
||||
sFilterBGColor = LLUIColorTable::instance().getColor("FilterBackgroundColor", DEFAULT_WHITE);
|
||||
sFilterTextColor = LLUIColorTable::instance().getColor("FilterTextColor", DEFAULT_WHITE);
|
||||
sSuffixColor = LLUIColorTable::instance().getColor("InventoryItemColor", DEFAULT_WHITE);
|
||||
sSuffixColor = LLUIColorTable::instance().getColor("InventoryItemLinkColor", DEFAULT_WHITE);
|
||||
sSearchStatusColor = LLUIColorTable::instance().getColor("InventorySearchStatusColor", DEFAULT_WHITE);
|
||||
sColorSetInitialized = true;
|
||||
}
|
||||
|
|
@ -177,6 +182,7 @@ LLFolderViewItem::LLFolderViewItem(const LLFolderViewItem::Params& p)
|
|||
LLFolderViewItem::~LLFolderViewItem()
|
||||
{
|
||||
mViewModelItem = NULL;
|
||||
gFocusMgr.removeKeyboardFocusWithoutCallback(this);
|
||||
}
|
||||
|
||||
BOOL LLFolderViewItem::postBuild()
|
||||
|
|
@ -395,7 +401,7 @@ S32 LLFolderViewItem::arrange( S32* width, S32* height )
|
|||
// it is purely visual, so it is fine to do at our laisure
|
||||
refreshSuffix();
|
||||
}
|
||||
mLabelWidth = getLabelXPos() + getLabelFontForStyle(mLabelStyle)->getWidth(mLabel) + getLabelFontForStyle(mLabelStyle)->getWidth(mLabelSuffix) + mLabelPaddingRight;
|
||||
mLabelWidth = getLabelXPos() + getLabelFontForStyle(mLabelStyle)->getWidth(mLabel) + getLabelFontForStyle(LLFontGL::NORMAL)->getWidth(mLabelSuffix) + mLabelPaddingRight;
|
||||
mLabelWidthDirty = false;
|
||||
}
|
||||
|
||||
|
|
@ -412,7 +418,7 @@ S32 LLFolderViewItem::arrange( S32* width, S32* height )
|
|||
return *height;
|
||||
}
|
||||
|
||||
S32 LLFolderViewItem::getItemHeight()
|
||||
S32 LLFolderViewItem::getItemHeight() const
|
||||
{
|
||||
return mItemHeight;
|
||||
}
|
||||
|
|
@ -624,11 +630,14 @@ BOOL LLFolderViewItem::handleHover( S32 x, S32 y, MASK mask )
|
|||
getWindow()->setCursor(UI_CURSOR_NOLOCKED);
|
||||
}
|
||||
|
||||
root->clearHoveredItem();
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
getRoot()->setShowSelectionContext(FALSE);
|
||||
LLFolderView* pRoot = getRoot();
|
||||
pRoot->setHoveredItem(this);
|
||||
pRoot->setShowSelectionContext(FALSE);
|
||||
getWindow()->setCursor(UI_CURSOR_ARROW);
|
||||
// let parent handle this then...
|
||||
return FALSE;
|
||||
|
|
@ -683,6 +692,13 @@ BOOL LLFolderViewItem::handleMouseUp( S32 x, S32 y, MASK mask )
|
|||
void LLFolderViewItem::onMouseLeave(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
mIsMouseOverTitle = false;
|
||||
|
||||
// NOTE: LLViewerWindow::updateUI() calls "enter" before "leave"; if the mouse moved to another item, we can't just outright clear it
|
||||
LLFolderView* pRoot = getRoot();
|
||||
if (this == pRoot->getHoveredItem())
|
||||
{
|
||||
pRoot->clearHoveredItem();
|
||||
}
|
||||
}
|
||||
|
||||
BOOL LLFolderViewItem::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
|
||||
|
|
@ -889,7 +905,10 @@ void LLFolderViewItem::draw()
|
|||
|
||||
getViewModelItem()->update();
|
||||
|
||||
drawOpenFolderArrow(default_params, sFgColor);
|
||||
if(!mSingleFolderMode)
|
||||
{
|
||||
drawOpenFolderArrow(default_params, sFgColor);
|
||||
}
|
||||
|
||||
drawHighlight(show_context, filled, sHighlightBgColor, sFlashBgColor, sFocusOutlineColor, sMouseOverColor);
|
||||
|
||||
|
|
@ -925,16 +944,43 @@ void LLFolderViewItem::draw()
|
|||
F32 text_left = (F32)getLabelXPos();
|
||||
std::string combined_string = mLabel + mLabelSuffix;
|
||||
|
||||
const LLFontGL* suffix_font = getLabelFontForStyle(LLFontGL::NORMAL);
|
||||
S32 filter_offset = mViewModelItem->getFilterStringOffset();
|
||||
if (filter_string_length > 0)
|
||||
{
|
||||
S32 left = ll_round(text_left) + font->getWidth(combined_string, 0, mViewModelItem->getFilterStringOffset()) - 2;
|
||||
S32 bottom = llfloor(getRect().getHeight() - font->getLineHeight() - 3 - TOP_PAD);
|
||||
S32 top = getRect().getHeight() - TOP_PAD;
|
||||
if(mLabelSuffix.empty() || (font == suffix_font))
|
||||
{
|
||||
S32 left = ll_round(text_left) + font->getWidth(combined_string, 0, mViewModelItem->getFilterStringOffset()) - 2;
|
||||
S32 right = left + font->getWidth(combined_string, mViewModelItem->getFilterStringOffset(), filter_string_length) + 2;
|
||||
S32 bottom = llfloor(getRect().getHeight() - font->getLineHeight() - 3 - TOP_PAD);
|
||||
S32 top = getRect().getHeight() - TOP_PAD;
|
||||
|
||||
LLUIImage* box_image = default_params.selection_image;
|
||||
LLRect box_rect(left, top, right, bottom);
|
||||
box_image->draw(box_rect, sFilterBGColor);
|
||||
}
|
||||
else
|
||||
{
|
||||
S32 label_filter_length = llmin((S32)mLabel.size() - filter_offset, (S32)filter_string_length);
|
||||
if(label_filter_length > 0)
|
||||
{
|
||||
S32 left = ll_round(text_left) + font->getWidthF32(mLabel, 0, llmin(filter_offset, (S32)mLabel.size())) - 2;
|
||||
S32 right = left + font->getWidthF32(mLabel, filter_offset, label_filter_length) + 2;
|
||||
LLUIImage* box_image = default_params.selection_image;
|
||||
LLRect box_rect(left, top, right, bottom);
|
||||
box_image->draw(box_rect, sFilterBGColor);
|
||||
}
|
||||
S32 suffix_filter_length = label_filter_length > 0 ? filter_string_length - label_filter_length : filter_string_length;
|
||||
if(suffix_filter_length > 0)
|
||||
{
|
||||
S32 suffix_offset = llmax(0, filter_offset - (S32)mLabel.size());
|
||||
S32 left = ll_round(text_left) + font->getWidthF32(mLabel, 0, mLabel.size()) + suffix_font->getWidthF32(mLabelSuffix, 0, suffix_offset) - 2;
|
||||
S32 right = left + suffix_font->getWidthF32(mLabelSuffix, suffix_offset, suffix_filter_length) + 2;
|
||||
LLUIImage* box_image = default_params.selection_image;
|
||||
LLRect box_rect(left, top, right, bottom);
|
||||
box_image->draw(box_rect, sFilterBGColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LLColor4 color = (mIsSelected && filled) ? mFontHighlightColor : mFontColor;
|
||||
|
|
@ -951,7 +997,7 @@ void LLFolderViewItem::draw()
|
|||
//
|
||||
if (!mLabelSuffix.empty())
|
||||
{
|
||||
font->renderUTF8( mLabelSuffix, 0, right_x, y, isFadeItem() ? color : (LLColor4)sSuffixColor,
|
||||
suffix_font->renderUTF8( mLabelSuffix, 0, right_x, y, isFadeItem() ? color : (LLColor4)sSuffixColor,
|
||||
LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW,
|
||||
S32_MAX, S32_MAX, &right_x, FALSE );
|
||||
}
|
||||
|
|
@ -961,12 +1007,35 @@ void LLFolderViewItem::draw()
|
|||
//
|
||||
if (filter_string_length > 0)
|
||||
{
|
||||
S32 filter_offset = mViewModelItem->getFilterStringOffset();
|
||||
F32 match_string_left = text_left + font->getWidthF32(combined_string, 0, filter_offset + filter_string_length) - font->getWidthF32(combined_string, filter_offset, filter_string_length);
|
||||
F32 yy = (F32)getRect().getHeight() - font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD;
|
||||
font->renderUTF8( combined_string, filter_offset, match_string_left, yy,
|
||||
if(mLabelSuffix.empty() || (font == suffix_font))
|
||||
{
|
||||
F32 match_string_left = text_left + font->getWidthF32(combined_string, 0, filter_offset + filter_string_length) - font->getWidthF32(combined_string, filter_offset, filter_string_length);
|
||||
F32 yy = (F32)getRect().getHeight() - font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD;
|
||||
font->renderUTF8( combined_string, filter_offset, match_string_left, yy,
|
||||
sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW,
|
||||
filter_string_length, S32_MAX, &right_x, FALSE );
|
||||
}
|
||||
else
|
||||
{
|
||||
S32 label_filter_length = llmin((S32)mLabel.size() - filter_offset, (S32)filter_string_length);
|
||||
if(label_filter_length > 0)
|
||||
{
|
||||
F32 match_string_left = text_left + font->getWidthF32(mLabel, 0, filter_offset + label_filter_length) - font->getWidthF32(mLabel, filter_offset, label_filter_length);
|
||||
F32 yy = (F32)getRect().getHeight() - font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD;
|
||||
font->renderUTF8( mLabel, filter_offset, match_string_left, yy,
|
||||
sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, label_filter_length, S32_MAX, &right_x, FALSE );
|
||||
}
|
||||
|
||||
S32 suffix_filter_length = label_filter_length > 0 ? filter_string_length - label_filter_length : filter_string_length;
|
||||
if(suffix_filter_length > 0)
|
||||
{
|
||||
S32 suffix_offset = llmax(0, filter_offset - (S32)mLabel.size());
|
||||
F32 match_string_left = text_left + font->getWidthF32(mLabel, 0, mLabel.size()) + suffix_font->getWidthF32(mLabelSuffix, 0, suffix_offset + suffix_filter_length) - suffix_font->getWidthF32(mLabelSuffix, suffix_offset, suffix_filter_length);
|
||||
F32 yy = (F32)getRect().getHeight() - suffix_font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD;
|
||||
suffix_font->renderUTF8( mLabelSuffix, suffix_offset, match_string_left, yy, sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, suffix_filter_length, S32_MAX, &right_x, FALSE );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//Gilbert Linden 9-20-2012: Although this should be legal, removing it because it causes the mLabelSuffix rendering to
|
||||
|
|
@ -1277,7 +1346,7 @@ BOOL LLFolderViewFolder::setSelection(LLFolderViewItem* selection, BOOL openitem
|
|||
child_selected = TRUE;
|
||||
}
|
||||
}
|
||||
if(openitem && child_selected)
|
||||
if(openitem && child_selected && !mSingleFolderMode)
|
||||
{
|
||||
setOpenArrangeRecursively(TRUE);
|
||||
}
|
||||
|
|
@ -1702,6 +1771,11 @@ BOOL LLFolderViewFolder::isRemovable()
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
void LLFolderViewFolder::destroyRoot()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
// this is an internal method used for adding items to folders.
|
||||
void LLFolderViewFolder::addItem(LLFolderViewItem* item)
|
||||
{
|
||||
|
|
@ -1770,7 +1844,19 @@ void LLFolderViewFolder::toggleOpen()
|
|||
// Force a folder open or closed
|
||||
void LLFolderViewFolder::setOpen(BOOL openitem)
|
||||
{
|
||||
setOpenArrangeRecursively(openitem);
|
||||
if(mSingleFolderMode)
|
||||
{
|
||||
// navigateToFolder can destroy this view
|
||||
// delay it in case setOpen was called from click or key processing
|
||||
doOnIdleOneTime([this]()
|
||||
{
|
||||
getViewModelItem()->navigateToFolder();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
setOpenArrangeRecursively(openitem);
|
||||
}
|
||||
}
|
||||
|
||||
void LLFolderViewFolder::setOpenArrangeRecursively(BOOL openitem, ERecurseType recurse)
|
||||
|
|
@ -1973,7 +2059,8 @@ BOOL LLFolderViewFolder::handleMouseDown( S32 x, S32 y, MASK mask )
|
|||
}
|
||||
if( !handled )
|
||||
{
|
||||
if(mIndentation < x && x < mIndentation + (isCollapsed() ? 0 : mArrowSize) + mTextPad)
|
||||
if((mIndentation < x && x < mIndentation + (isCollapsed() ? 0 : mArrowSize) + mTextPad)
|
||||
&& !mSingleFolderMode)
|
||||
{
|
||||
toggleOpen();
|
||||
handled = TRUE;
|
||||
|
|
@ -1991,12 +2078,45 @@ BOOL LLFolderViewFolder::handleMouseDown( S32 x, S32 y, MASK mask )
|
|||
BOOL LLFolderViewFolder::handleDoubleClick( S32 x, S32 y, MASK mask )
|
||||
{
|
||||
BOOL handled = FALSE;
|
||||
if(mSingleFolderMode)
|
||||
{
|
||||
static LLUICachedControl<bool> double_click_new_window("SingleModeDoubleClickOpenWindow", false);
|
||||
if (double_click_new_window)
|
||||
{
|
||||
getViewModelItem()->navigateToFolder(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// navigating is going to destroy views and change children
|
||||
// delay it untill handleDoubleClick processing is complete
|
||||
doOnIdleOneTime([this]()
|
||||
{
|
||||
getViewModelItem()->navigateToFolder(false);
|
||||
});
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if( isOpen() )
|
||||
{
|
||||
handled = childrenHandleDoubleClick( x, y, mask ) != NULL;
|
||||
}
|
||||
if( !handled )
|
||||
{
|
||||
if(mDoubleClickOverride)
|
||||
{
|
||||
static LLUICachedControl<U32> double_click_action("MultiModeDoubleClickFolder", false);
|
||||
if (double_click_action == 1)
|
||||
{
|
||||
getViewModelItem()->navigateToFolder(true);
|
||||
return TRUE;
|
||||
}
|
||||
if (double_click_action == 2)
|
||||
{
|
||||
getViewModelItem()->navigateToFolder(false, true);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
if(mIndentation < x && x < mIndentation + (isCollapsed() ? 0 : mArrowSize) + mTextPad)
|
||||
{
|
||||
// don't select when user double-clicks plus sign
|
||||
|
|
|
|||
|
|
@ -72,6 +72,8 @@ public:
|
|||
text_pad_right,
|
||||
arrow_size,
|
||||
max_folder_item_overlap;
|
||||
Optional<bool> single_folder_mode,
|
||||
double_click_override;
|
||||
Params();
|
||||
};
|
||||
|
||||
|
|
@ -121,6 +123,8 @@ protected:
|
|||
mIsMouseOverTitle,
|
||||
mAllowWear,
|
||||
mAllowDrop,
|
||||
mSingleFolderMode,
|
||||
mDoubleClickOverride,
|
||||
mSelectPending,
|
||||
mIsItemCut;
|
||||
|
||||
|
|
@ -174,7 +178,7 @@ public:
|
|||
// Finds width and height of this object and it's children. Also
|
||||
// makes sure that this view and it's children are the right size.
|
||||
virtual S32 arrange( S32* width, S32* height );
|
||||
virtual S32 getItemHeight();
|
||||
virtual S32 getItemHeight() const;
|
||||
virtual S32 getLabelXPos();
|
||||
S32 getIconPad();
|
||||
S32 getTextPad();
|
||||
|
|
@ -213,9 +217,9 @@ public:
|
|||
|
||||
void setIsCurSelection(BOOL select) { mIsCurSelection = select; }
|
||||
|
||||
BOOL getIsCurSelection() { return mIsCurSelection; }
|
||||
BOOL getIsCurSelection() const { return mIsCurSelection; }
|
||||
|
||||
BOOL hasVisibleChildren() { return mHasVisibleChildren; }
|
||||
BOOL hasVisibleChildren() const { return mHasVisibleChildren; }
|
||||
|
||||
// true if object can't have children
|
||||
virtual bool isFolderComplete() { return true; }
|
||||
|
|
@ -264,7 +268,7 @@ public:
|
|||
virtual LLFolderView* getRoot();
|
||||
virtual const LLFolderView* getRoot() const;
|
||||
BOOL isDescendantOf( const LLFolderViewFolder* potential_ancestor );
|
||||
S32 getIndentation() { return mIndentation; }
|
||||
S32 getIndentation() const { return mIndentation; }
|
||||
|
||||
virtual BOOL passedFilter(S32 filter_generation = -1);
|
||||
virtual BOOL isPotentiallyVisible(S32 filter_generation = -1);
|
||||
|
|
@ -277,6 +281,8 @@ public:
|
|||
// Does not need filter update
|
||||
virtual void refreshSuffix();
|
||||
|
||||
bool isSingleFolderMode() { return mSingleFolderMode; }
|
||||
|
||||
// LLView functionality
|
||||
virtual BOOL handleRightMouseDown( S32 x, S32 y, MASK mask );
|
||||
virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask );
|
||||
|
|
@ -387,6 +393,7 @@ public:
|
|||
|
||||
// destroys this folder, and all children
|
||||
virtual void destroyView();
|
||||
void destroyRoot();
|
||||
|
||||
// whether known children are fully loaded (arrange sets to true)
|
||||
virtual bool isFolderComplete() { return mIsFolderComplete; }
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ bool LLFolderViewModelCommon::needsSort(LLFolderViewModelItem* item)
|
|||
return item->getSortVersion() < mTargetSortVersion;
|
||||
}
|
||||
|
||||
std::string LLFolderViewModelCommon::getStatusText()
|
||||
std::string LLFolderViewModelCommon::getStatusText(bool is_empty_folder)
|
||||
{
|
||||
if (!contentsReady() || mFolderView->getViewModelItem()->getLastFilterGeneration() < getFilter().getCurrentGeneration())
|
||||
{
|
||||
|
|
@ -42,7 +42,7 @@ std::string LLFolderViewModelCommon::getStatusText()
|
|||
}
|
||||
else
|
||||
{
|
||||
return getFilter().getEmptyLookupMessage();
|
||||
return getFilter().getEmptyLookupMessage(is_empty_folder);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ public:
|
|||
virtual bool checkFolder(const LLFolderViewModelItem* folder) const = 0;
|
||||
|
||||
virtual void setEmptyLookupMessage(const std::string& message) = 0;
|
||||
virtual std::string getEmptyLookupMessage() const = 0;
|
||||
virtual std::string getEmptyLookupMessage(bool is_empty_folder = false) const = 0;
|
||||
|
||||
virtual bool showAllResults() const = 0;
|
||||
|
||||
|
|
@ -125,7 +125,7 @@ public:
|
|||
virtual void setFolderView(LLFolderView* folder_view) = 0;
|
||||
virtual LLFolderViewFilter& getFilter() = 0;
|
||||
virtual const LLFolderViewFilter& getFilter() const = 0;
|
||||
virtual std::string getStatusText() = 0;
|
||||
virtual std::string getStatusText(bool is_empty_folder = false) = 0;
|
||||
|
||||
virtual bool startDrag(std::vector<LLFolderViewModelItem*>& items) = 0;
|
||||
};
|
||||
|
|
@ -159,6 +159,8 @@ public:
|
|||
virtual void openItem( void ) = 0;
|
||||
virtual void closeItem( void ) = 0;
|
||||
virtual void selectItem(void) = 0;
|
||||
|
||||
virtual void navigateToFolder(bool new_window = false, bool change_mode = false) = 0;
|
||||
|
||||
virtual BOOL isItemWearable() const { return FALSE; }
|
||||
|
||||
|
|
@ -392,7 +394,7 @@ public:
|
|||
// sort everything
|
||||
mTargetSortVersion++;
|
||||
}
|
||||
virtual std::string getStatusText();
|
||||
virtual std::string getStatusText(bool is_empty_folder = false);
|
||||
virtual void filter();
|
||||
|
||||
void setFolderView(LLFolderView* folder_view) { mFolderView = folder_view;}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,8 @@
|
|||
#include "lluiimage.h"
|
||||
#include "llwindow.h"
|
||||
|
||||
#include "llgltexture.h"
|
||||
|
||||
static LLDefaultChildRegistry::Register<LLIconCtrl> r("icon");
|
||||
|
||||
LLIconCtrl::Params::Params()
|
||||
|
|
@ -94,6 +96,22 @@ BOOL LLIconCtrl::handleHover(S32 x, S32 y, MASK mask)
|
|||
return LLUICtrl::handleHover(x, y, mask);
|
||||
}
|
||||
|
||||
void LLIconCtrl::onVisibilityChange(BOOL new_visibility)
|
||||
{
|
||||
LLUICtrl::onVisibilityChange(new_visibility);
|
||||
if (mPriority == LLGLTexture::BOOST_ICON)
|
||||
{
|
||||
if (new_visibility)
|
||||
{
|
||||
loadImage(getValue(), mPriority);
|
||||
}
|
||||
else
|
||||
{
|
||||
mImagep = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// virtual
|
||||
// value might be a string or a UUID
|
||||
void LLIconCtrl::setValue(const LLSD& value)
|
||||
|
|
@ -110,6 +128,14 @@ void LLIconCtrl::setValue(const LLSD& value, S32 priority)
|
|||
tvalue = LLSD(LLUUID(value.asString()));
|
||||
}
|
||||
LLUICtrl::setValue(tvalue);
|
||||
|
||||
loadImage(tvalue, priority);
|
||||
}
|
||||
|
||||
void LLIconCtrl::loadImage(const LLSD& tvalue, S32 priority)
|
||||
{
|
||||
if(mPriority == LLGLTexture::BOOST_ICON && !getVisible()) return;
|
||||
|
||||
if (tvalue.isUUID())
|
||||
{
|
||||
mImagep = LLUI::getUIImageByID(tvalue.asUUID(), priority);
|
||||
|
|
|
|||
|
|
@ -39,7 +39,9 @@ class LLUICtrlFactory;
|
|||
// Classes
|
||||
//
|
||||
|
||||
//
|
||||
// Class for diplaying named UI textures
|
||||
// Do not use for displaying textures from network,
|
||||
// UI textures are stored permanently!
|
||||
class LLIconCtrl
|
||||
: public LLUICtrl
|
||||
{
|
||||
|
|
@ -72,6 +74,7 @@ public:
|
|||
virtual BOOL handleHover(S32 x, S32 y, MASK mask);
|
||||
|
||||
// lluictrl overrides
|
||||
void onVisibilityChange(BOOL new_visibility);
|
||||
virtual void setValue(const LLSD& value );
|
||||
|
||||
std::string getImageName() const;
|
||||
|
|
@ -95,6 +98,8 @@ protected:
|
|||
bool mInteractable;
|
||||
|
||||
private:
|
||||
void loadImage(const LLSD& value, S32 priority);
|
||||
|
||||
LLUIColor mColor;
|
||||
LLPointer<LLUIImage> mImagep;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -89,6 +89,8 @@ LLLayoutPanel::~LLLayoutPanel()
|
|||
// probably not necessary, but...
|
||||
delete mResizeBar;
|
||||
mResizeBar = NULL;
|
||||
|
||||
gFocusMgr.removeKeyboardFocusWithoutCallback(this);
|
||||
}
|
||||
|
||||
F32 LLLayoutPanel::getAutoResizeFactor() const
|
||||
|
|
@ -214,7 +216,8 @@ LLLayoutStack::Params::Params()
|
|||
drag_handle_first_indent("drag_handle_first_indent", 0),
|
||||
drag_handle_second_indent("drag_handle_second_indent", 0),
|
||||
drag_handle_thickness("drag_handle_thickness", 5),
|
||||
drag_handle_shift("drag_handle_shift", 2)
|
||||
drag_handle_shift("drag_handle_shift", 2),
|
||||
drag_handle_color("drag_handle_color", LLUIColorTable::instance().getColor("ResizebarBody"))
|
||||
{
|
||||
addSynonym(border_size, "drag_handle_gap");
|
||||
}
|
||||
|
|
@ -234,7 +237,8 @@ LLLayoutStack::LLLayoutStack(const LLLayoutStack::Params& p)
|
|||
mDragHandleFirstIndent(p.drag_handle_first_indent),
|
||||
mDragHandleSecondIndent(p.drag_handle_second_indent),
|
||||
mDragHandleThickness(p.drag_handle_thickness),
|
||||
mDragHandleShift(p.drag_handle_shift)
|
||||
mDragHandleShift(p.drag_handle_shift),
|
||||
mDragHandleColor(p.drag_handle_color())
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -282,6 +286,17 @@ void LLLayoutStack::draw()
|
|||
}
|
||||
}
|
||||
|
||||
void LLLayoutStack::deleteAllChildren()
|
||||
{
|
||||
mPanels.clear();
|
||||
LLView::deleteAllChildren();
|
||||
|
||||
// Not really needed since nothing is left to
|
||||
// display, but for the sake of consistency
|
||||
updateFractionalSizes();
|
||||
mNeedsLayout = true;
|
||||
}
|
||||
|
||||
void LLLayoutStack::removeChild(LLView* view)
|
||||
{
|
||||
LLLayoutPanel* embedded_panelp = findEmbeddedPanel(dynamic_cast<LLPanel*>(view));
|
||||
|
|
@ -289,12 +304,14 @@ void LLLayoutStack::removeChild(LLView* view)
|
|||
if (embedded_panelp)
|
||||
{
|
||||
mPanels.erase(std::find(mPanels.begin(), mPanels.end(), embedded_panelp));
|
||||
delete embedded_panelp;
|
||||
LLView::removeChild(view);
|
||||
updateFractionalSizes();
|
||||
mNeedsLayout = true;
|
||||
}
|
||||
|
||||
LLView::removeChild(view);
|
||||
else
|
||||
{
|
||||
LLView::removeChild(view);
|
||||
}
|
||||
}
|
||||
|
||||
BOOL LLLayoutStack::postBuild()
|
||||
|
|
@ -508,6 +525,15 @@ void LLLayoutStack::updateLayout()
|
|||
mNeedsLayout = continue_animating;
|
||||
} // end LLLayoutStack::updateLayout
|
||||
|
||||
void LLLayoutStack::setPanelSpacing(S32 val)
|
||||
{
|
||||
if (mPanelSpacing != val)
|
||||
{
|
||||
mPanelSpacing = val;
|
||||
mNeedsLayout = true;
|
||||
}
|
||||
}
|
||||
|
||||
LLLayoutPanel* LLLayoutStack::findEmbeddedPanel(LLPanel* panelp) const
|
||||
{
|
||||
if (!panelp) return NULL;
|
||||
|
|
@ -561,7 +587,7 @@ void LLLayoutStack::createResizeBar(LLLayoutPanel* panelp)
|
|||
resize_bar_bg_panel_p.follows.flags = FOLLOWS_ALL;
|
||||
resize_bar_bg_panel_p.tab_stop = false;
|
||||
resize_bar_bg_panel_p.background_visible = true;
|
||||
resize_bar_bg_panel_p.bg_alpha_color = LLUIColorTable::instance().getColor("ResizebarBody");
|
||||
resize_bar_bg_panel_p.bg_alpha_color = mDragHandleColor;
|
||||
resize_bar_bg_panel_p.has_border = true;
|
||||
resize_bar_bg_panel_p.border.border_thickness = 1;
|
||||
resize_bar_bg_panel_p.border.highlight_light_color = LLUIColorTable::instance().getColor("ResizebarBorderLight");
|
||||
|
|
|
|||
|
|
@ -59,6 +59,8 @@ public:
|
|||
Optional<S32> drag_handle_thickness;
|
||||
Optional<S32> drag_handle_shift;
|
||||
|
||||
Optional<LLUIColor> drag_handle_color;
|
||||
|
||||
Params();
|
||||
};
|
||||
|
||||
|
|
@ -67,6 +69,7 @@ public:
|
|||
virtual ~LLLayoutStack();
|
||||
|
||||
/*virtual*/ void draw();
|
||||
/*virtual*/ void deleteAllChildren();
|
||||
/*virtual*/ void removeChild(LLView*);
|
||||
/*virtual*/ BOOL postBuild();
|
||||
/*virtual*/ bool addChild(LLView* child, S32 tab_group = 0);
|
||||
|
|
@ -88,6 +91,7 @@ public:
|
|||
void updateLayout();
|
||||
|
||||
S32 getPanelSpacing() const { return mPanelSpacing; }
|
||||
void setPanelSpacing(S32 val);
|
||||
|
||||
static void updateClass();
|
||||
|
||||
|
|
@ -127,6 +131,7 @@ private:
|
|||
S32 mDragHandleSecondIndent;
|
||||
S32 mDragHandleThickness;
|
||||
S32 mDragHandleShift;
|
||||
LLUIColor mDragHandleColor;
|
||||
}; // end class LLLayoutStack
|
||||
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue