From f5659945b5a177b325f98b6d598af47a214e7abc Mon Sep 17 00:00:00 2001 From: Brad Linden Date: Mon, 17 Jun 2024 18:54:45 -0700 Subject: [PATCH 01/30] Fix secret name since GITHUB_ prefix is reserved --- .github/workflows/tag-release.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/tag-release.yaml b/.github/workflows/tag-release.yaml index b73ec502f1..2083b414f5 100644 --- a/.github/workflows/tag-release.yaml +++ b/.github/workflows/tag-release.yaml @@ -27,7 +27,7 @@ jobs: tag-release: runs-on: ubuntu-latest env: - GITHUB_TAG_TOKEN: ${{ secrets.GITHUB_TAG_TOKEN }} + LL_TAG_RELEASE_TOKEN: ${{ secrets.LL_TAG_RELEASE_TOKEN }} steps: - name: Setup Env Vars run: | @@ -36,9 +36,9 @@ jobs: echo NIGHTLY_DATE=$(date --rfc-3339=date) >> ${GITHUB_ENV} - name: Update Tag uses: actions/github-script@v7.0.1 - if: env.GITHUB_TAG_TOKEN + if: env.LL_TAG_RELEASE_TOKEN with: - github-token: ${{ env.GITHUB_TAG_TOKEN }} + github-token: ${{ env.LL_TAG_RELEASE_TOKEN }} script: | github.rest.git.createRef( owner: context.repo.owner, From 05efb1494ddf2b3e68bc98835dc353f01482c25e Mon Sep 17 00:00:00 2001 From: Brad Linden Date: Mon, 17 Jun 2024 18:57:26 -0700 Subject: [PATCH 02/30] Fix yaml indentation of javascript snippet in tag-release workflow --- .github/workflows/tag-release.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tag-release.yaml b/.github/workflows/tag-release.yaml index 2083b414f5..cb9babaea8 100644 --- a/.github/workflows/tag-release.yaml +++ b/.github/workflows/tag-release.yaml @@ -45,4 +45,4 @@ jobs: repo: context.repo.repo, ref: "refs/tags/${{ env.VIEWER_CHANNEL }}#${{ env.NIGHTLY_DATE }}", sha: context.sha - ) + ) From e165be000781034c0d56659f3f021b1efb323108 Mon Sep 17 00:00:00 2001 From: Brad Linden Date: Tue, 18 Jun 2024 14:23:43 -0700 Subject: [PATCH 03/30] Attempt to use provided GITHUB_TOKEN and generate tag id from inputs --- .github/workflows/tag-release.yaml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/.github/workflows/tag-release.yaml b/.github/workflows/tag-release.yaml index cb9babaea8..24d8fbb8bf 100644 --- a/.github/workflows/tag-release.yaml +++ b/.github/workflows/tag-release.yaml @@ -26,23 +26,22 @@ on: jobs: tag-release: runs-on: ubuntu-latest - env: - LL_TAG_RELEASE_TOKEN: ${{ secrets.LL_TAG_RELEASE_TOKEN }} steps: - name: Setup Env Vars run: | CHANNEL="${{ inputs.channel }}" echo VIEWER_CHANNEL="Second_Life_${CHANNEL:-Develop}" >> ${GITHUB_ENV} - echo NIGHTLY_DATE=$(date --rfc-3339=date) >> ${GITHUB_ENV} + NIGHTLY_DATE=$(date --rfc-3339=date) + echo NIGHTLY_DATE=${NIGHTLY_DATE} >> ${GITHUB_ENV} + echo TAG_ID="${{ github.sha }}-${{ inputs.project || '${NIGHTLY_DATE}' }}" - name: Update Tag uses: actions/github-script@v7.0.1 - if: env.LL_TAG_RELEASE_TOKEN with: - github-token: ${{ env.LL_TAG_RELEASE_TOKEN }} + github-token: ${{ secrets.GITHUB_TOKEN }} script: | github.rest.git.createRef( owner: context.repo.owner, repo: context.repo.repo, - ref: "refs/tags/${{ env.VIEWER_CHANNEL }}#${{ env.NIGHTLY_DATE }}", + ref: "refs/tags/${{ env.VIEWER_CHANNEL }}#${{ env.TAG_ID }}", sha: context.sha ) From aa6161ca94d5bd8640840f981ca8b243b553acaa Mon Sep 17 00:00:00 2001 From: Brad Linden Date: Tue, 18 Jun 2024 14:35:22 -0700 Subject: [PATCH 04/30] Shorten SHA value used in tag id and attempt to fix js/yaml syntax error --- .github/workflows/tag-release.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/tag-release.yaml b/.github/workflows/tag-release.yaml index 24d8fbb8bf..18fe686d36 100644 --- a/.github/workflows/tag-release.yaml +++ b/.github/workflows/tag-release.yaml @@ -33,15 +33,15 @@ jobs: echo VIEWER_CHANNEL="Second_Life_${CHANNEL:-Develop}" >> ${GITHUB_ENV} NIGHTLY_DATE=$(date --rfc-3339=date) echo NIGHTLY_DATE=${NIGHTLY_DATE} >> ${GITHUB_ENV} - echo TAG_ID="${{ github.sha }}-${{ inputs.project || '${NIGHTLY_DATE}' }}" + echo TAG_ID="$(echo ${{ github.sha }} | cut -c1-8)-${{ inputs.project || '${NIGHTLY_DATE}' }}" - name: Update Tag uses: actions/github-script@v7.0.1 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | - github.rest.git.createRef( + github.rest.git.createRef({ owner: context.repo.owner, repo: context.repo.repo, ref: "refs/tags/${{ env.VIEWER_CHANNEL }}#${{ env.TAG_ID }}", sha: context.sha - ) + }) From 32b912af9a821b0edaebb75d037da05df6ff25e5 Mon Sep 17 00:00:00 2001 From: Brad Linden Date: Thu, 20 Jun 2024 17:15:16 -0700 Subject: [PATCH 05/30] Make sure TAG_ID actually gets added to GITHUB_ENV --- .github/workflows/tag-release.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tag-release.yaml b/.github/workflows/tag-release.yaml index 18fe686d36..65d1d43a83 100644 --- a/.github/workflows/tag-release.yaml +++ b/.github/workflows/tag-release.yaml @@ -33,7 +33,7 @@ jobs: echo VIEWER_CHANNEL="Second_Life_${CHANNEL:-Develop}" >> ${GITHUB_ENV} NIGHTLY_DATE=$(date --rfc-3339=date) echo NIGHTLY_DATE=${NIGHTLY_DATE} >> ${GITHUB_ENV} - echo TAG_ID="$(echo ${{ github.sha }} | cut -c1-8)-${{ inputs.project || '${NIGHTLY_DATE}' }}" + echo TAG_ID="$(echo ${{ github.sha }} | cut -c1-8)-${{ inputs.project || '${NIGHTLY_DATE}' }}" >> ${GITHUB_ENV} - name: Update Tag uses: actions/github-script@v7.0.1 with: From 3eab42ebd832545d4ba51a39168110859b869370 Mon Sep 17 00:00:00 2001 From: Roxie Linden Date: Fri, 21 Jun 2024 13:22:12 -0700 Subject: [PATCH 06/30] Disable voice morphing and throw up a warning if it's previously enabled. --- indra/newview/app_settings/settings.xml | 2 +- indra/newview/llviewermenu.cpp | 19 ---------- indra/newview/llvoiceclient.cpp | 33 +++++++++++++++-- indra/newview/llvoiceclient.h | 3 ++ .../skins/default/xui/de/menu_viewer.xml | 6 ---- .../skins/default/xui/en/menu_viewer.xml | 36 ------------------- .../skins/default/xui/en/notifications.xml | 14 ++++++++ .../skins/default/xui/es/menu_viewer.xml | 6 ---- .../skins/default/xui/it/menu_viewer.xml | 6 ---- .../skins/default/xui/ja/menu_viewer.xml | 1 - .../skins/default/xui/pl/menu_viewer.xml | 5 --- .../skins/default/xui/pt/menu_viewer.xml | 6 ---- .../skins/default/xui/ru/menu_viewer.xml | 6 ---- .../skins/default/xui/tr/menu_viewer.xml | 6 ---- .../skins/default/xui/zh/menu_viewer.xml | 6 ---- 15 files changed, 48 insertions(+), 107 deletions(-) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 0a84bf8390..38d7555053 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -13043,7 +13043,7 @@ Type Boolean Value - 1 + 0 AutoDisengageMic diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 4dcfb18b30..be93c58faf 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -9342,15 +9342,6 @@ class LLUpdateMembershipLabel : public view_listener_t } }; -void handle_voice_morphing_subscribe() -{ - LLWeb::loadURL(LLTrans::getString("voice_morphing_url")); -} - -void handle_premium_voice_morphing_subscribe() -{ - LLWeb::loadURL(LLTrans::getString("premium_voice_morphing_url")); -} class LLToggleUIHints : public view_listener_t { @@ -9551,16 +9542,6 @@ void initialize_menus() //Communicate Nearby chat view_listener_t::addMenu(new LLCommunicateNearbyChat(), "Communicate.NearbyChat"); - // Communicate > Voice morphing > Subscribe... - commit.add("Communicate.VoiceMorphing.Subscribe", boost::bind(&handle_voice_morphing_subscribe)); - // Communicate > Voice morphing > Premium perk... - commit.add("Communicate.VoiceMorphing.PremiumPerk", boost::bind(&handle_premium_voice_morphing_subscribe)); - LLVivoxVoiceClient * voice_clientp = LLVivoxVoiceClient::getInstance(); - enable.add("Communicate.VoiceMorphing.NoVoiceMorphing.Check" - , boost::bind(&LLVivoxVoiceClient::onCheckVoiceEffect, voice_clientp, "NoVoiceMorphing")); - commit.add("Communicate.VoiceMorphing.NoVoiceMorphing.Click" - , boost::bind(&LLVivoxVoiceClient::onClickVoiceEffect, voice_clientp, "NoVoiceMorphing")); - // World menu view_listener_t::addMenu(new LLWorldAlwaysRun(), "World.AlwaysRun"); view_listener_t::addMenu(new LLWorldCreateLandmark(), "World.CreateLandmark"); diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp index fb3377e9c0..779f4e3176 100644 --- a/indra/newview/llvoiceclient.cpp +++ b/indra/newview/llvoiceclient.cpp @@ -137,8 +137,9 @@ LLVoiceClient::LLVoiceClient(LLPumpIO *pump) mSpatialVoiceModule(NULL), mNonSpatialVoiceModule(NULL), m_servicePump(NULL), - mVoiceEffectEnabled(LLCachedControl(gSavedSettings, "VoiceMorphingEnabled", true)), + mVoiceEffectEnabled(LLCachedControl(gSavedSettings, "VoiceMorphingEnabled", false)), mVoiceEffectDefault(LLCachedControl(gSavedPerAccountSettings, "VoiceEffectDefault", "00000000-0000-0000-0000-000000000000")), + mVoiceEffectSupportNotified(false), mPTTDirty(true), mPTT(true), mUsePTT(true), @@ -569,11 +570,37 @@ void LLVoiceClient::setMicGain(F32 gain) //------------------------------------------ // enable/disable voice features +// static +bool LLVoiceClient::onVoiceEffectsNotSupported(const LLSD ¬ification, const LLSD &response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + switch (option) + { + case 0: // "Okay" + gSavedSettings.setBOOL("VoiceMorphingEnabled", FALSE); + break; + + case 1: // "Cancel" + break; + + default: + llassert(0); + break; + } + return false; +} + bool LLVoiceClient::voiceEnabled() { static LLCachedControl enable_voice_chat(gSavedSettings, "EnableVoiceChat"); static LLCachedControl cmd_line_disable_voice(gSavedSettings, "CmdLineDisableVoice"); - return enable_voice_chat && !cmd_line_disable_voice && !gNonInteractive; + bool enabled = enable_voice_chat && !cmd_line_disable_voice && !gNonInteractive; + if (enabled && !mVoiceEffectSupportNotified && getVoiceEffectEnabled() && !getVoiceEffectDefault().isNull()) + { + LLNotificationsUtil::add("VoiceEffectsNotSupported", LLSD(), LLSD(), &LLVoiceClient::onVoiceEffectsNotSupported); + mVoiceEffectSupportNotified = true; + } + return enabled; } void LLVoiceClient::setVoiceEnabled(bool enabled) @@ -812,7 +839,7 @@ std::string LLVoiceClient::sipURIFromID(const LLUUID &id) LLVoiceEffectInterface* LLVoiceClient::getVoiceEffectInterface() const { - return getVoiceEffectEnabled() ? dynamic_cast(mSpatialVoiceModule) : NULL; + return NULL; } /////////////////// diff --git a/indra/newview/llvoiceclient.h b/indra/newview/llvoiceclient.h index 8eadc82437..d603125759 100644 --- a/indra/newview/llvoiceclient.h +++ b/indra/newview/llvoiceclient.h @@ -508,6 +508,8 @@ public: protected: + static bool onVoiceEffectsNotSupported(const LLSD ¬ification, const LLSD &response); + LLVoiceModuleInterface* mSpatialVoiceModule; LLVoiceModuleInterface* mNonSpatialVoiceModule; LLSD mSpatialCredentials; // used to store spatial credentials for vivox @@ -519,6 +521,7 @@ protected: LLCachedControl mVoiceEffectEnabled; LLCachedControl mVoiceEffectDefault; + bool mVoiceEffectSupportNotified; bool mPTTDirty; bool mPTT; diff --git a/indra/newview/skins/default/xui/de/menu_viewer.xml b/indra/newview/skins/default/xui/de/menu_viewer.xml index f6724d4993..8c446c1975 100644 --- a/indra/newview/skins/default/xui/de/menu_viewer.xml +++ b/indra/newview/skins/default/xui/de/menu_viewer.xml @@ -42,12 +42,6 @@ - - - - - - diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index f3d44cf647..d17aec0f6a 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -561,42 +561,6 @@ parameter="conversation" /> - - - - - - - - - - - - - - - - - voice + +Voice Morphs are not supported by this viewer. + + voice + + - - - - - - diff --git a/indra/newview/skins/default/xui/it/menu_viewer.xml b/indra/newview/skins/default/xui/it/menu_viewer.xml index 043fd28ddb..85999ccbe0 100644 --- a/indra/newview/skins/default/xui/it/menu_viewer.xml +++ b/indra/newview/skins/default/xui/it/menu_viewer.xml @@ -42,12 +42,6 @@ - - - - - - diff --git a/indra/newview/skins/default/xui/ja/menu_viewer.xml b/indra/newview/skins/default/xui/ja/menu_viewer.xml index a1f3980df4..f6b10bb121 100644 --- a/indra/newview/skins/default/xui/ja/menu_viewer.xml +++ b/indra/newview/skins/default/xui/ja/menu_viewer.xml @@ -74,7 +74,6 @@ - diff --git a/indra/newview/skins/default/xui/pl/menu_viewer.xml b/indra/newview/skins/default/xui/pl/menu_viewer.xml index 4d03e7c780..ee162addd2 100644 --- a/indra/newview/skins/default/xui/pl/menu_viewer.xml +++ b/indra/newview/skins/default/xui/pl/menu_viewer.xml @@ -35,11 +35,6 @@ - - - - - diff --git a/indra/newview/skins/default/xui/pt/menu_viewer.xml b/indra/newview/skins/default/xui/pt/menu_viewer.xml index b70adc3ad2..0f4873d11c 100644 --- a/indra/newview/skins/default/xui/pt/menu_viewer.xml +++ b/indra/newview/skins/default/xui/pt/menu_viewer.xml @@ -42,12 +42,6 @@ - - - - - - diff --git a/indra/newview/skins/default/xui/ru/menu_viewer.xml b/indra/newview/skins/default/xui/ru/menu_viewer.xml index 8361464f4c..4a6390329d 100644 --- a/indra/newview/skins/default/xui/ru/menu_viewer.xml +++ b/indra/newview/skins/default/xui/ru/menu_viewer.xml @@ -40,12 +40,6 @@ - - - - - - diff --git a/indra/newview/skins/default/xui/tr/menu_viewer.xml b/indra/newview/skins/default/xui/tr/menu_viewer.xml index 1c977ba5ce..fb6111248c 100644 --- a/indra/newview/skins/default/xui/tr/menu_viewer.xml +++ b/indra/newview/skins/default/xui/tr/menu_viewer.xml @@ -40,12 +40,6 @@ - - - - - - diff --git a/indra/newview/skins/default/xui/zh/menu_viewer.xml b/indra/newview/skins/default/xui/zh/menu_viewer.xml index 972434dfc5..a048af7b68 100644 --- a/indra/newview/skins/default/xui/zh/menu_viewer.xml +++ b/indra/newview/skins/default/xui/zh/menu_viewer.xml @@ -40,12 +40,6 @@ - - - - - - From 08f2236736f00a1f1d8b2d042b7423fb306dc94f Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Fri, 21 Jun 2024 17:00:45 -0500 Subject: [PATCH 07/30] #1831 Fix for redundantly rebuilding bounding boxes forever (#1832) --- indra/newview/llviewerobject.cpp | 2 +- indra/newview/llvovolume.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 8af0057c88..e108f9c268 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -3676,7 +3676,7 @@ bool LLViewerObject::updateLOD() bool LLViewerObject::updateGeometry(LLDrawable *drawable) { - return false; + return true; } void LLViewerObject::updateGL() diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index de62256134..71f3c2a3aa 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -2039,6 +2039,7 @@ bool LLVOVolume::updateGeometry(LLDrawable *drawable) if (mDrawable->isState(LLDrawable::REBUILD_RIGGED)) { + LL_PROFILE_ZONE_NAMED_CATEGORY_VOLUME("rebuild rigged"); updateRiggedVolume(false); genBBoxes(false); mDrawable->clearState(LLDrawable::REBUILD_RIGGED); From 34a2fd525f5dde075bfc5615e6deb241ae61b94c Mon Sep 17 00:00:00 2001 From: Roxie Linden Date: Mon, 24 Jun 2024 14:42:30 -0700 Subject: [PATCH 08/30] [WebRTC] control microphone gain via custom audio processor. Previously, there were two places audio gain could be controlled: - the device manager - the audio track The device manager audio gain control sets the system gain for all applications, not just the webrtc application. The audio track gain happens well after the audio processing where we want it to happen. So, gain control was added to the existing custom audio processor, which previously only handled calculating and retrieving the audio levels. After these changes, the microphone gain slider does impact the audio volume heard by peers. --- indra/llwebrtc/llwebrtc.cpp | 20 ++++++++++++++------ indra/llwebrtc/llwebrtc.h | 1 + indra/llwebrtc/llwebrtc_impl.h | 5 +++++ indra/newview/llvoicewebrtc.cpp | 31 ++----------------------------- indra/newview/llvoicewebrtc.h | 5 ----- 5 files changed, 22 insertions(+), 40 deletions(-) diff --git a/indra/llwebrtc/llwebrtc.cpp b/indra/llwebrtc/llwebrtc.cpp index 14fb63ec2a..d5bd913315 100644 --- a/indra/llwebrtc/llwebrtc.cpp +++ b/indra/llwebrtc/llwebrtc.cpp @@ -35,6 +35,7 @@ #include "api/media_stream_interface.h" #include "api/media_stream_track.h" #include "modules/audio_processing/audio_buffer.h" +#include "modules/audio_mixer/audio_mixer_impl.h" namespace llwebrtc { @@ -88,7 +89,7 @@ void LLAudioDeviceObserver::OnRenderData(const void *audio_samples, { } -LLCustomProcessor::LLCustomProcessor() : mSampleRateHz(0), mNumChannels(0), mMicrophoneEnergy(0.0) +LLCustomProcessor::LLCustomProcessor() : mSampleRateHz(0), mNumChannels(0), mMicrophoneEnergy(0.0), mGain(1.0) { memset(mSumVector, 0, sizeof(mSumVector)); } @@ -128,9 +129,13 @@ void LLCustomProcessor::Process(webrtc::AudioBuffer *audio_in) for (size_t index = 0; index < stream_config.num_samples(); index++) { float sample = frame_samples[index]; + sample = sample * mGain; // apply gain + frame_samples[index] = sample; // write processed sample back to buffer. energy += sample * sample; } + audio_in->CopyFrom(&frame[0], stream_config); + // smooth it. size_t buffer_size = sizeof(mSumVector) / sizeof(mSumVector[0]); float totalSum = 0; @@ -236,9 +241,9 @@ void LLWebRTCImpl::init() webrtc::AudioProcessing::Config apm_config; apm_config.echo_canceller.enabled = false; apm_config.echo_canceller.mobile_mode = false; - apm_config.gain_controller1.enabled = true; + apm_config.gain_controller1.enabled = false; apm_config.gain_controller1.mode = webrtc::AudioProcessing::Config::GainController1::kAdaptiveAnalog; - apm_config.gain_controller2.enabled = true; + apm_config.gain_controller2.enabled = false; apm_config.high_pass_filter.enabled = true; apm_config.noise_suppression.enabled = true; apm_config.noise_suppression.level = webrtc::AudioProcessing::Config::NoiseSuppression::kVeryHigh; @@ -260,6 +265,7 @@ void LLWebRTCImpl::init() mAudioProcessingModule->ApplyConfig(apm_config); mAudioProcessingModule->Initialize(processing_config); + mPeerConnectionFactory = webrtc::CreatePeerConnectionFactory(mNetworkThread.get(), mWorkerThread.get(), mSignalingThread.get(), @@ -336,9 +342,9 @@ void LLWebRTCImpl::setAudioConfig(LLWebRTCDeviceInterface::AudioConfig config) webrtc::AudioProcessing::Config apm_config; apm_config.echo_canceller.enabled = config.mEchoCancellation; apm_config.echo_canceller.mobile_mode = false; - apm_config.gain_controller1.enabled = true; + apm_config.gain_controller1.enabled = config.mAGC; apm_config.gain_controller1.mode = webrtc::AudioProcessing::Config::GainController1::kAdaptiveAnalog; - apm_config.gain_controller2.enabled = true; + apm_config.gain_controller2.enabled = false; apm_config.high_pass_filter.enabled = true; apm_config.transient_suppression.enabled = true; apm_config.pipeline.multi_channel_render = true; @@ -612,6 +618,8 @@ float LLWebRTCImpl::getTuningAudioLevel() { return -20 * log10f(mTuningAudioDevi float LLWebRTCImpl::getPeerConnectionAudioLevel() { return -20 * log10f(mPeerCustomProcessor->getMicrophoneEnergy()); } +void LLWebRTCImpl::setPeerConnectionGain(float gain) { mPeerCustomProcessor->setGain(gain); } + // // Peer Connection Helpers @@ -937,7 +945,7 @@ void LLWebRTCPeerConnectionImpl::setSendVolume(float volume) { for (auto &track : mLocalStream->GetAudioTracks()) { - track->GetSource()->SetVolume(volume); + track->GetSource()->SetVolume(volume*5.0); } } }); diff --git a/indra/llwebrtc/llwebrtc.h b/indra/llwebrtc/llwebrtc.h index ecbab81538..f447ea990a 100644 --- a/indra/llwebrtc/llwebrtc.h +++ b/indra/llwebrtc/llwebrtc.h @@ -145,6 +145,7 @@ class LLWebRTCDeviceInterface virtual void setTuningMode(bool enable) = 0; virtual float getTuningAudioLevel() = 0; // for use during tuning virtual float getPeerConnectionAudioLevel() = 0; // for use when not tuning + virtual void setPeerConnectionGain(float gain) = 0; }; // LLWebRTCAudioInterface provides the viewer with a way diff --git a/indra/llwebrtc/llwebrtc_impl.h b/indra/llwebrtc/llwebrtc_impl.h index 448d36e3ea..6672f8ce90 100644 --- a/indra/llwebrtc/llwebrtc_impl.h +++ b/indra/llwebrtc/llwebrtc_impl.h @@ -121,6 +121,8 @@ class LLCustomProcessor : public webrtc::CustomProcessing float getMicrophoneEnergy() { return mMicrophoneEnergy; } + void setGain(float gain) { mGain = gain; } + protected: static const int NUM_PACKETS_TO_FILTER = 30; // 300 ms of smoothing int mSampleRateHz; @@ -128,6 +130,7 @@ class LLCustomProcessor : public webrtc::CustomProcessing float mSumVector[NUM_PACKETS_TO_FILTER]; float mMicrophoneEnergy; + float mGain; }; @@ -160,6 +163,8 @@ class LLWebRTCImpl : public LLWebRTCDeviceInterface, public webrtc::AudioDeviceS float getTuningAudioLevel() override; float getPeerConnectionAudioLevel() override; + void setPeerConnectionGain(float gain) override; + // // AudioDeviceSink // diff --git a/indra/newview/llvoicewebrtc.cpp b/indra/newview/llvoicewebrtc.cpp index ddad470149..36e998af89 100644 --- a/indra/newview/llvoicewebrtc.cpp +++ b/indra/newview/llvoicewebrtc.cpp @@ -87,7 +87,7 @@ namespace { const F32 VOLUME_SCALE_WEBRTC = 0.01f; const F32 LEVEL_SCALE_WEBRTC = 0.008f; - const F32 SPEAKING_AUDIO_LEVEL = 0.35; + const F32 SPEAKING_AUDIO_LEVEL = 0.30; static const std::string REPORTED_VOICE_SERVER_TYPE = "Secondlife WebRTC Gateway"; @@ -1484,14 +1484,10 @@ void LLWebRTCVoiceClient::setMicGain(F32 gain) if (gain != mMicGain) { mMicGain = gain; - sessionState::for_each(boost::bind(predSetMicGain, _1, gain)); + mWebRTCDeviceInterface->setPeerConnectionGain(gain); } } -void LLWebRTCVoiceClient::predSetMicGain(const LLWebRTCVoiceClient::sessionStatePtr_t &session, F32 gain) -{ - session->setMicGain(gain); -} void LLWebRTCVoiceClient::setVoiceEnabled(bool enabled) { @@ -1690,7 +1686,6 @@ std::map LLWebRTCVoiceCli LLWebRTCVoiceClient::sessionState::sessionState() : mHangupOnLastLeave(false), mNotifyOnFirstJoin(false), - mMicGain(1.0), mMuted(false), mSpeakerVolume(1.0), mShuttingDown(false) @@ -1735,15 +1730,6 @@ void LLWebRTCVoiceClient::sessionState::setMuteMic(bool muted) } } -void LLWebRTCVoiceClient::sessionState::setMicGain(F32 gain) -{ - mMicGain = gain; - for (auto &connection : mWebRTCConnections) - { - connection->setMicGain(gain); - } -} - void LLWebRTCVoiceClient::sessionState::setSpeakerVolume(F32 volume) { mSpeakerVolume = volume; @@ -1848,7 +1834,6 @@ LLWebRTCVoiceClient::sessionStatePtr_t LLWebRTCVoiceClient::addSession(const std LL_DEBUGS("Voice") << "adding new session with channel: " << channel_id << LL_ENDL; session->setMuteMic(mMuteMic); - session->setMicGain(mMicGain); session->setSpeakerVolume(mSpeakerVolume); sessionState::addSession(channel_id, session); @@ -1974,7 +1959,6 @@ bool LLWebRTCVoiceClient::estateSessionState::processConnectionStates() connectionPtr_t connection(new LLVoiceWebRTCSpatialConnection(neighbor, INVALID_PARCEL_ID, mChannelID)); mWebRTCConnections.push_back(connection); - connection->setMicGain(mMicGain); connection->setMuteMic(mMuted); connection->setSpeakerVolume(mSpeakerVolume); } @@ -2104,7 +2088,6 @@ LLVoiceWebRTCConnection::LLVoiceWebRTCConnection(const LLUUID ®ionID, const s mShutDown(false), mIceCompleted(false), mSpeakerVolume(0.0), - mMicGain(0.0), mOutstandingRequests(0), mChannelID(channelID), mRegionID(regionID), @@ -2367,15 +2350,6 @@ void LLVoiceWebRTCConnection::setMuteMic(bool muted) } } -void LLVoiceWebRTCConnection::setMicGain(F32 gain) -{ - mMicGain = gain; - if (mWebRTCAudioInterface) - { - mWebRTCAudioInterface->setSendVolume(gain); - } -} - void LLVoiceWebRTCConnection::setSpeakerVolume(F32 volume) { mSpeakerVolume = volume; @@ -2683,7 +2657,6 @@ bool LLVoiceWebRTCConnection::connectionStateMachine() // this connection. mWebRTCAudioInterface->setMute(mMuted); mWebRTCAudioInterface->setReceiveVolume(mSpeakerVolume); - mWebRTCAudioInterface->setSendVolume(mMicGain); LLWebRTCVoiceClient::getInstance()->OnConnectionEstablished(mChannelID, mRegionID); setVoiceConnectionState(VOICE_STATE_WAIT_FOR_DATA_CHANNEL); break; diff --git a/indra/newview/llvoicewebrtc.h b/indra/newview/llvoicewebrtc.h index 60724a4a2a..7042bbae00 100644 --- a/indra/newview/llvoicewebrtc.h +++ b/indra/newview/llvoicewebrtc.h @@ -282,7 +282,6 @@ public: virtual void sendData(const std::string &data); void setMuteMic(bool muted); - void setMicGain(F32 volume); void setSpeakerVolume(F32 volume); void setUserVolume(const LLUUID& id, F32 volume); @@ -303,7 +302,6 @@ public: std::string mName; bool mMuted; // this session is muted. - F32 mMicGain; // gain for this session. F32 mSpeakerVolume; // volume for this session. bool mShuttingDown; @@ -382,7 +380,6 @@ public: static void predSendData(const LLWebRTCVoiceClient::sessionStatePtr_t &session, const std::string& spatial_data); static void predUpdateOwnVolume(const LLWebRTCVoiceClient::sessionStatePtr_t &session, F32 audio_level); static void predSetMuteMic(const LLWebRTCVoiceClient::sessionStatePtr_t &session, bool mute); - static void predSetMicGain(const LLWebRTCVoiceClient::sessionStatePtr_t &session, F32 volume); static void predSetSpeakerVolume(const LLWebRTCVoiceClient::sessionStatePtr_t &session, F32 volume); static void predShutdownSession(const LLWebRTCVoiceClient::sessionStatePtr_t &session); static void predSetUserMute(const LLWebRTCVoiceClient::sessionStatePtr_t &session, const LLUUID& id, bool mute); @@ -607,7 +604,6 @@ class LLVoiceWebRTCConnection : void processIceUpdatesCoro(); virtual void setMuteMic(bool muted); - virtual void setMicGain(F32 volume); virtual void setSpeakerVolume(F32 volume); void setUserVolume(const LLUUID& id, F32 volume); @@ -686,7 +682,6 @@ class LLVoiceWebRTCConnection : std::string mRemoteChannelSDP; bool mMuted; - F32 mMicGain; F32 mSpeakerVolume; bool mShutDown; From 244566cc3fcde45e555011c520ed7107b591663d Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 24 Jun 2024 18:24:57 +0300 Subject: [PATCH 09/30] viewer#1506 The Dynamic probe checkbox wasn't working --- indra/newview/llpanelvolume.cpp | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp index 16c38bf1f0..4e096ecc95 100644 --- a/indra/newview/llpanelvolume.cpp +++ b/indra/newview/llpanelvolume.cpp @@ -151,6 +151,7 @@ bool LLPanelVolume::postBuild() { childSetCommitCallback("Reflection Probe", onCommitIsReflectionProbe, this); childSetCommitCallback("Probe Update Type", onCommitProbe, this); + childSetCommitCallback("Probe Dynamic", onCommitProbe, this); childSetCommitCallback("Probe Volume Type", onCommitProbe, this); childSetCommitCallback("Probe Ambiance", onCommitProbe, this); childSetCommitCallback("Probe Near Clip", onCommitProbe, this); @@ -412,6 +413,7 @@ void LLPanelVolume::getState( ) getChild("Probe Ambiance", true)->clear(); getChild("Probe Near Clip", true)->clear(); getChild("Probe Update Type", true)->clear(); + getChild("Probe Dynamic")->setValue(false); } else { @@ -446,6 +448,7 @@ void LLPanelVolume::getState( ) getChild("Probe Ambiance", true)->setValue(volobjp->getReflectionProbeAmbiance()); getChild("Probe Near Clip", true)->setValue(volobjp->getReflectionProbeNearClip()); getChild("Probe Update Type", true)->setValue(update_type); + getChild("Probe Dynamic")->setValue(volobjp->getReflectionProbeIsDynamic()); } // Animated Mesh @@ -733,6 +736,7 @@ void LLPanelVolume::clearCtrls() getChildView("Reflection Probe")->setEnabled(false);; getChildView("Probe Volume Type")->setEnabled(false); getChildView("Probe Update Type")->setEnabled(false); + getChildView("Probe Dynamic")->setEnabled(false); getChildView("Probe Ambiance")->setEnabled(false); getChildView("Probe Near Clip")->setEnabled(false); getChildView("Animated Mesh Checkbox Ctrl")->setEnabled(false); @@ -1428,15 +1432,26 @@ void LLPanelVolume::onCommitProbe(LLUICtrl* ctrl, void* userdata) volobjp->setReflectionProbeAmbiance((F32)self->getChild("Probe Ambiance")->getValue().asReal()); volobjp->setReflectionProbeNearClip((F32)self->getChild("Probe Near Clip")->getValue().asReal()); - std::string update_type = self->getChild("Probe Update Type")->getValue().asString(); + bool mirrors_enabled = LLPipeline::RenderMirrors; + bool is_mirror = false; - bool is_mirror = update_type.find("Mirror") != std::string::npos; + if (mirrors_enabled) + { + std::string update_type = self->getChild("Probe Update Type")->getValue().asString(); + + is_mirror = update_type.find("Mirror") != std::string::npos; + + volobjp->setReflectionProbeIsDynamic(update_type.find("Dynamic") != std::string::npos); + volobjp->setReflectionProbeIsMirror(is_mirror); + } + else + { + is_mirror = volobjp->getReflectionProbeIsMirror(); + bool is_dynamic = self->getChild("Probe Dynamic")->getValue().asBoolean(); + volobjp->setReflectionProbeIsDynamic(is_dynamic); + } self->getChildView("Probe Volume Type")->setEnabled(!is_mirror); - - volobjp->setReflectionProbeIsDynamic(update_type.find("Dynamic") != std::string::npos); - volobjp->setReflectionProbeIsMirror(is_mirror); - self->getChildView("Probe Ambiance")->setEnabled(!is_mirror); self->getChildView("Probe Near Clip")->setEnabled(!is_mirror); From 0f47b68e92a3951392ff2fc6bba7147860c1ce4d Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 21 Jun 2024 11:46:09 +0300 Subject: [PATCH 10/30] viewer#1821 Crash at getSessionID() --- indra/newview/llspeakers.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp index 407e058132..b12e8d15fc 100644 --- a/indra/newview/llspeakers.cpp +++ b/indra/newview/llspeakers.cpp @@ -288,6 +288,10 @@ LLSpeakerMgr::~LLSpeakerMgr() LLPointer LLSpeakerMgr::setSpeaker(const LLUUID& id, const std::string& name, LLSpeaker::ESpeakerStatus status, LLSpeaker::ESpeakerType type) { + if (!mVoiceChannel) + { + return NULL; + } LLUUID session_id = getSessionID(); if (id.isNull() || (id == session_id)) { @@ -490,7 +494,7 @@ void LLSpeakerMgr::updateSpeakerList() (LLVoiceClient::getInstance()->isParticipantAvatar(*participant_it)?LLSpeaker::SPEAKER_AGENT:LLSpeaker::SPEAKER_EXTERNAL)); } } - else + else if (mVoiceChannel) { // If not, check if the list is empty, except if it's Nearby Chat (session_id NULL). LLUUID session_id = getSessionID(); @@ -816,7 +820,7 @@ void LLIMSpeakerMgr::updateSpeakers(const LLSD& update) void LLIMSpeakerMgr::toggleAllowTextChat(const LLUUID& speaker_id) { LLPointer speakerp = findSpeaker(speaker_id); - if (!speakerp) return; + if (!speakerp || !mVoiceChannel) return; std::string url = gAgent.getRegionCapability("ChatSessionRequest"); LLSD data; @@ -835,7 +839,7 @@ void LLIMSpeakerMgr::toggleAllowTextChat(const LLUUID& speaker_id) void LLIMSpeakerMgr::moderateVoiceParticipant(const LLUUID& avatar_id, bool unmute) { LLPointer speakerp = findSpeaker(avatar_id); - if (!speakerp) return; + if (!speakerp || !mVoiceChannel) return; // *NOTE: mantipov: probably this condition will be incorrect when avatar will be blocked for // text chat via moderation (LLSpeaker::mModeratorMutedText == TRUE) From 454821bb5968ce59e0738b38f135de659b8e349f Mon Sep 17 00:00:00 2001 From: Roxie Linden Date: Tue, 25 Jun 2024 18:30:18 -0700 Subject: [PATCH 11/30] #1806 - crash in initVoiceChannel --- indra/newview/llimview.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index 014dd90406..2978de6a22 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -3413,11 +3413,11 @@ LLUUID LLIMMgr::addSession( ((IM_NOTHING_SPECIAL == dialog) || (IM_SESSION_P2P_INVITE == dialog) || (IM_SESSION_CONFERENCE_START == dialog)) && ids.size()) { - LLIMModel::LLIMSession* ad_hoc_found = LLIMModel::getInstance()->findAdHocIMSession(ids); - if (ad_hoc_found) + session = LLIMModel::getInstance()->findAdHocIMSession(ids); + if (session) { new_session = false; - session_id = ad_hoc_found->mSessionID; + session_id = session->mSessionID; } } From 39f0da7ab623ee99106058deb1d0c6a3295b567f Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 23 Feb 2024 04:18:03 +0200 Subject: [PATCH 12/30] Issue#880 Crash on a dead pointer in a chat session --- indra/newview/llconversationmodel.cpp | 26 +++++++------- indra/newview/llfloaterimsessiontab.cpp | 45 +++++++++++++++++++++++-- 2 files changed, 55 insertions(+), 16 deletions(-) diff --git a/indra/newview/llconversationmodel.cpp b/indra/newview/llconversationmodel.cpp index 4335168417..4cd85ac756 100644 --- a/indra/newview/llconversationmodel.cpp +++ b/indra/newview/llconversationmodel.cpp @@ -357,22 +357,20 @@ void LLConversationItemSession::clearParticipants() void LLConversationItemSession::clearAndDeparentModels() { - std::for_each(mChildren.begin(), mChildren.end(), - [](LLFolderViewModelItem* c) + for (LLFolderViewModelItem* child : mChildren) + { + if (child->getNumRefs() == 0) { - if (c->getNumRefs() == 0) - { - // LLConversationItemParticipant can be created but not assigned to any view, - // it was waiting for an "add_participant" event to be processed - delete c; - } - else - { - // Model is still assigned to some view/widget - c->setParent(NULL); - } + // LLConversationItemParticipant can be created but not assigned to any view, + // it was waiting for an "add_participant" event to be processed + delete child; } - ); + else + { + // Model is still assigned to some view/widget + child->setParent(NULL); + } + } mChildren.clear(); } diff --git a/indra/newview/llfloaterimsessiontab.cpp b/indra/newview/llfloaterimsessiontab.cpp index dc64d09f9f..aaf839c50c 100644 --- a/indra/newview/llfloaterimsessiontab.cpp +++ b/indra/newview/llfloaterimsessiontab.cpp @@ -102,6 +102,26 @@ LLFloaterIMSessionTab::LLFloaterIMSessionTab(const LLSD& session_id) LLFloaterIMSessionTab::~LLFloaterIMSessionTab() { delete mRefreshTimer; + + LLFloaterIMContainer* im_container = LLFloaterIMContainer::findInstance(); + if (im_container) + { + LLParticipantList* session = dynamic_cast(im_container->getSessionModel(mSessionID)); + if (session) + { + for (const conversations_widgets_map::value_type& widget_pair : mConversationsWidgets) + { + LLFolderViewItem* widget = widget_pair.second; + LLFolderViewModelItem* item_vmi = widget->getViewModelItem(); + if (item_vmi && item_vmi->getNumRefs() == 1) + { + // This is the last pointer, remove participant from session + // before participant gets deleted on destroyView. + session->removeChild(item_vmi); + } + } + } + } } // static @@ -663,9 +683,30 @@ void LLFloaterIMSessionTab::removeConversationViewParticipant(const LLUUID& part LLFolderViewItem* widget = get_ptr_in_map(mConversationsWidgets,participant_id); if (widget) { + LLFolderViewModelItem* item_vmi = widget->getViewModelItem(); + if (item_vmi && item_vmi->getNumRefs() == 1) + { + // This is the last pointer, remove participant from session + // before participant gets deleted on destroyView. + // + // Floater (widget) and participant's view can simultaneously + // co-own the model, in which case view is responsible for + // the deletion and floater is free to clear and recreate + // the list, yet there are cases where only widget owns + // the pointer so it should do the cleanup. + // See "add_participant". + // + // Todo: If it keeps causing issues turn participants + // into LLPointers in the session + LLParticipantList* session = getParticipantList(); + if (session) + { + session->removeChild(item_vmi); + } + } widget->destroyView(); - } - mConversationsWidgets.erase(participant_id); + } + mConversationsWidgets.erase(participant_id); } void LLFloaterIMSessionTab::updateConversationViewParticipant(const LLUUID& participant_id) From 8804c019a817812828aa8b4602fd7af11c276478 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Wed, 26 Jun 2024 20:38:51 +0200 Subject: [PATCH 13/30] Increase texture discard bias if system memory gets low --- indra/newview/app_settings/settings.xml | 22 ++++++++++++ indra/newview/lltextureview.cpp | 2 -- indra/newview/llviewertexture.cpp | 48 ++++++++++++++++++++----- indra/newview/llviewertexture.h | 1 + 4 files changed, 63 insertions(+), 10 deletions(-) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 50632a7b07..e7e9fc5b88 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -7716,6 +7716,28 @@ Value 0 + RenderMinFreeMainMemoryThreshold + + Comment + Minimum of available physical memory in MB before textures get scaled down + Persist + 1 + Type + U32 + Value + 512 + + RenderLowMemMinDiscardIncrement + + Comment + Minimum increment of discard level if system memory gets low + Persist + 1 + Type + F32 + Value + 0.1 + RenderMaxTextureIndex Comment diff --git a/indra/newview/lltextureview.cpp b/indra/newview/lltextureview.cpp index f521293b96..b51bcc5601 100644 --- a/indra/newview/lltextureview.cpp +++ b/indra/newview/lltextureview.cpp @@ -59,8 +59,6 @@ #include "llvoavatarself.h" #include "lltexlayer.h" -extern F32 texmem_lower_bound_scale; - LLTextureView *gTextureView = NULL; #define HIGH_PRIORITY 100000000.f diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index c1062b9a01..c716eb4e86 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -101,6 +101,7 @@ U32 LLViewerTexture::sMaxSmallImageSize = MAX_CACHED_RAW_IMAGE_AREA; bool LLViewerTexture::sFreezeImageUpdates = false; F32 LLViewerTexture::sCurrentTime = 0.0f; +constexpr F32 MEMORY_CHECK_WAIT_TIME = 1.0f; constexpr F32 MIN_VRAM_BUDGET = 768.f; F32 LLViewerTexture::sFreeVRAMMegabytes = MIN_VRAM_BUDGET; @@ -484,10 +485,6 @@ void LLViewerTexture::initClass() LLImageGL::sDefaultGLTexture = LLViewerFetchedTexture::sDefaultImagep->getGLTexture(); } -// non-const (used externally -F32 texmem_lower_bound_scale = 0.85f; -F32 texmem_middle_bound_scale = 0.925f; - //static void LLViewerTexture::updateClass() { @@ -519,14 +516,49 @@ void LLViewerTexture::updateClass() sFreeVRAMMegabytes = target - used; F32 over_pct = llmax((used-target) / target, 0.f); - sDesiredDiscardBias = llmax(sDesiredDiscardBias, 1.f + over_pct); - if (sDesiredDiscardBias > 1.f) + if (isSystemMemoryLow()) { - sDesiredDiscardBias -= gFrameIntervalSeconds * 0.01; + // System RAM is low -> ramp up discard bias over time to free memory + if (sEvaluationTimer.getElapsedTimeF32() > MEMORY_CHECK_WAIT_TIME) + { + static LLCachedControl low_mem_min_discard_increment(gSavedSettings, "RenderLowMemMinDiscardIncrement", .1f); + sDesiredDiscardBias += llmax(low_mem_min_discard_increment, over_pct); + sEvaluationTimer.reset(); + } + } + else + { + sDesiredDiscardBias = llmax(sDesiredDiscardBias, 1.f + over_pct); + + if (sDesiredDiscardBias > 1.f) + { + sDesiredDiscardBias -= gFrameIntervalSeconds * 0.01; + } } - LLViewerTexture::sFreezeImageUpdates = false; // sDesiredDiscardBias > (desired_discard_bias_max - 1.0f); + LLViewerTexture::sFreezeImageUpdates = false; +} + +//static +bool LLViewerTexture::isSystemMemoryLow() +{ + static LLFrameTimer timer; + static U32Megabytes physical_res = U32Megabytes(U32_MAX); + + static LLCachedControl min_free_main_memory(gSavedSettings, "RenderMinFreeMainMemoryThreshold", 512); + const U32Megabytes MIN_FREE_MAIN_MEMORY(min_free_main_memory); + + if (timer.getElapsedTimeF32() < MEMORY_CHECK_WAIT_TIME) //call this once per second. + { + return physical_res < MIN_FREE_MAIN_MEMORY; + } + + timer.reset(); + + LLMemory::updateMemoryInfo(); + physical_res = LLMemory::getAvailableMemKB(); + return physical_res < MIN_FREE_MAIN_MEMORY; } //end of static functions diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h index dc9182bf1b..9963626ada 100644 --- a/indra/newview/llviewertexture.h +++ b/indra/newview/llviewertexture.h @@ -117,6 +117,7 @@ protected: public: static void initClass(); static void updateClass(); + static bool isSystemMemoryLow(); LLViewerTexture(bool usemipmaps = true); LLViewerTexture(const LLUUID& id, bool usemipmaps) ; From 0f2bb1bd8307a0802a6e24c7eb50f6a0082edea4 Mon Sep 17 00:00:00 2001 From: Roxie Linden Date: Wed, 26 Jun 2024 12:53:49 -0700 Subject: [PATCH 14/30] Make the webrtc viewer work for vivox adhoc/group calls. There was an issue on the release grid where old-style credentials were being sent over and the webrtc viewer wasn't dealing with them properly. --- indra/newview/llimview.cpp | 2 +- indra/newview/llvoicechannel.cpp | 12 ++++++------ indra/newview/llvoicevivox.cpp | 18 ++++++++++++------ 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index 2978de6a22..d3f013c67c 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -3853,7 +3853,7 @@ bool LLIMMgr::startCall(const LLUUID& session_id, LLVoiceChannel::EDirection dir { LLVoiceChannel* voice_channel = LLIMModel::getInstance()->getVoiceChannel(session_id); if (!voice_channel) return false; - if (!voice_channel_info.isUndefined()) + if (voice_channel_info.isDefined() && voice_channel_info.isMap() && voice_channel_info.size() > 0) { voice_channel->setChannelInfo(voice_channel_info); } diff --git a/indra/newview/llvoicechannel.cpp b/indra/newview/llvoicechannel.cpp index f6556b7128..8681411a98 100644 --- a/indra/newview/llvoicechannel.cpp +++ b/indra/newview/llvoicechannel.cpp @@ -96,7 +96,7 @@ void LLVoiceChannel::setChannelInfo(const LLSD &channelInfo) if (mState == STATE_NO_CHANNEL_INFO) { - if (mChannelInfo.isUndefined()) + if (mChannelInfo.isUndefined() || !mChannelInfo.isMap() || mChannelInfo.size() == 0) { LLNotificationsUtil::add("VoiceChannelJoinFailed", mNotifyArgs); LL_WARNS("Voice") << "Received empty channel info for channel " << mSessionName << LL_ENDL; @@ -122,7 +122,7 @@ void LLVoiceChannel::onChange(EStatusType type, const LLSD& channelInfo, bool pr { LL_DEBUGS("Voice") << "Incoming channel info: " << channelInfo << LL_ENDL; LL_DEBUGS("Voice") << "Current channel info: " << mChannelInfo << LL_ENDL; - if (mChannelInfo.isUndefined()) + if (mChannelInfo.isUndefined() || (mChannelInfo.isMap() && mChannelInfo.size() == 0)) { mChannelInfo = channelInfo; } @@ -477,7 +477,7 @@ void LLVoiceChannelGroup::setChannelInfo(const LLSD& channelInfo) if (mState == STATE_NO_CHANNEL_INFO) { - if(!mChannelInfo.isUndefined()) + if(mChannelInfo.isDefined() && mChannelInfo.isMap()) { setState(STATE_READY); @@ -676,9 +676,9 @@ void LLVoiceChannelProximal::activate() // we're connected to a non-spatial channel, so disconnect. LLVoiceClient::getInstance()->leaveNonSpatialChannel(); } + LLVoiceClient::getInstance()->activateSpatialChannel(true); LLVoiceChannel::activate(); - } void LLVoiceChannelProximal::onChange(EStatusType type, const LLSD& channelInfo, bool proximal) @@ -751,7 +751,7 @@ void LLVoiceChannelProximal::deactivate() { setState(STATE_HUNG_UP); } - + LLVoiceClient::getInstance()->removeObserver(this); LLVoiceClient::getInstance()->activateSpatialChannel(false); } @@ -907,7 +907,7 @@ void LLVoiceChannelP2P::setChannelInfo(const LLSD& channel_info) } mReceivedCall = TRUE; - if (!channel_info.isUndefined()) + if (channel_info.isDefined() && channel_info.isMap()) { mIncomingCallInterface = LLVoiceClient::getInstance()->getIncomingCallInterface(channel_info); } diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index 3554933a52..1833aeb54f 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -5105,25 +5105,31 @@ void LLVivoxVoiceClient::processChannels(bool process) bool LLVivoxVoiceClient::isCurrentChannel(const LLSD &channelInfo) { - if (!mProcessChannels || (channelInfo["voice_server_type"].asString() != VIVOX_VOICE_SERVER_TYPE)) + if (!mProcessChannels || (channelInfo.has("voice_server_type") && channelInfo["voice_server_type"].asString() != VIVOX_VOICE_SERVER_TYPE)) { return false; } - if (mAudioSession) + // favor the next audio session, as that's the one we're bringing up. + sessionStatePtr_t session = mNextAudioSession; + if (!session) + { + session = mAudioSession; + } + if (session) { if (!channelInfo["session_handle"].asString().empty()) { - return mAudioSession->mHandle == channelInfo["session_handle"].asString(); + return session->mHandle == channelInfo["session_handle"].asString(); } - return channelInfo["channel_uri"].asString() == mAudioSession->mSIPURI; + return channelInfo["channel_uri"].asString() == session->mSIPURI; } return false; } bool LLVivoxVoiceClient::compareChannels(const LLSD& channelInfo1, const LLSD& channelInfo2) { - return (channelInfo1["voice_server_type"] == VIVOX_VOICE_SERVER_TYPE) && - (channelInfo1["voice_server_type"] == channelInfo2["voice_server_type"]) && + return (!channelInfo1.has("voice_server_type") || (channelInfo1["voice_server_type"] == VIVOX_VOICE_SERVER_TYPE)) && + (!channelInfo2.has("voice_server_type") || (channelInfo2["voice_server_type"] == VIVOX_VOICE_SERVER_TYPE)) && (channelInfo1["channel_uri"] == channelInfo2["channel_uri"]); } From 33418a77b716e122da9778869cdbabe97c83ff37 Mon Sep 17 00:00:00 2001 From: Roxie Linden Date: Wed, 26 Jun 2024 14:43:22 -0700 Subject: [PATCH 15/30] Convert tabs to spaces --- indra/newview/llfloaterimsessiontab.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/newview/llfloaterimsessiontab.cpp b/indra/newview/llfloaterimsessiontab.cpp index aaf839c50c..0ed84c381f 100644 --- a/indra/newview/llfloaterimsessiontab.cpp +++ b/indra/newview/llfloaterimsessiontab.cpp @@ -705,8 +705,8 @@ void LLFloaterIMSessionTab::removeConversationViewParticipant(const LLUUID& part } } widget->destroyView(); - } - mConversationsWidgets.erase(participant_id); + } + mConversationsWidgets.erase(participant_id); } void LLFloaterIMSessionTab::updateConversationViewParticipant(const LLUUID& participant_id) From ab87978cbc71cd4c83648627998055a010700f05 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Thu, 27 Jun 2024 13:12:43 -0500 Subject: [PATCH 16/30] 1836 dont store texture in system memory unless absolutely necessary (#1843) * #1836 Texture memory usage overhaul. Much decrufting - don't keep a copy of textures in system memory - use GPU to downrez textures instead of reloading from cache - use GPU to generate brightness/darkness bumpmaps --- indra/llrender/llgltexture.cpp | 21 - indra/llrender/llgltexture.h | 6 +- indra/llrender/llimagegl.cpp | 260 ++++------- indra/llrender/llimagegl.h | 35 +- .../shaders/class1/deferred/normgenF.glsl | 41 +- indra/newview/gltf/buffer_util.h | 10 + indra/newview/gltfscenemanager.cpp | 3 +- indra/newview/lldebugview.cpp | 6 +- indra/newview/lldrawpoolbump.cpp | 434 +++++------------- indra/newview/lldrawpoolbump.h | 5 +- .../newview/llfloaterchangeitemthumbnail.cpp | 22 +- indra/newview/lllocalbitmaps.cpp | 1 - indra/newview/llnetmap.cpp | 20 - indra/newview/llsurface.cpp | 169 +------ indra/newview/llsurface.h | 11 +- indra/newview/llsurfacepatch.cpp | 9 +- indra/newview/lltextureview.cpp | 65 ++- indra/newview/llviewermedia.cpp | 61 +-- indra/newview/llviewerobject.cpp | 4 +- indra/newview/llviewerregion.cpp | 6 +- indra/newview/llviewerregion.h | 2 +- indra/newview/llviewertexture.cpp | 312 ++----------- indra/newview/llviewertexture.h | 25 +- indra/newview/llviewertexturelist.cpp | 24 +- indra/newview/llviewertexturelist.h | 18 +- indra/newview/llviewerwindow.cpp | 134 +----- indra/newview/llviewerwindow.h | 9 +- indra/newview/llvlcomposition.cpp | 412 +---------------- indra/newview/llvlcomposition.h | 2 - indra/newview/llvovolume.cpp | 36 +- indra/newview/llvowater.cpp | 15 +- indra/newview/llvowater.h | 3 - indra/newview/llworld.cpp | 2 - indra/newview/llworldmipmap.cpp | 1 + indra/newview/llworldmipmap.h | 6 +- scripts/messages/message_template.msg.sha1 | 2 +- 36 files changed, 485 insertions(+), 1707 deletions(-) diff --git a/indra/llrender/llgltexture.cpp b/indra/llrender/llgltexture.cpp index e614f45986..4dcca5a726 100644 --- a/indra/llrender/llgltexture.cpp +++ b/indra/llrender/llgltexture.cpp @@ -351,20 +351,6 @@ void LLGLTexture::forceUpdateBindStats(void) const return mGLTexturep->forceUpdateBindStats() ; } -U32 LLGLTexture::getTexelsInAtlas() const -{ - llassert(mGLTexturep.notNull()) ; - - return mGLTexturep->getTexelsInAtlas() ; -} - -U32 LLGLTexture::getTexelsInGLTexture() const -{ - llassert(mGLTexturep.notNull()) ; - - return mGLTexturep->getTexelsInGLTexture() ; -} - bool LLGLTexture::isGLTextureCreated() const { llassert(mGLTexturep.notNull()) ; @@ -372,13 +358,6 @@ bool LLGLTexture::isGLTextureCreated() const return mGLTexturep->isGLTextureCreated() ; } -S32 LLGLTexture::getDiscardLevelInAtlas() const -{ - llassert(mGLTexturep.notNull()) ; - - return mGLTexturep->getDiscardLevelInAtlas() ; -} - void LLGLTexture::destroyGLTexture() { if(mGLTexturep.notNull() && mGLTexturep->getHasGLTexture()) diff --git a/indra/llrender/llgltexture.h b/indra/llrender/llgltexture.h index 0901243f8f..a7de20dc5c 100644 --- a/indra/llrender/llgltexture.h +++ b/indra/llrender/llgltexture.h @@ -51,10 +51,10 @@ public: BOOST_NONE = 0, BOOST_AVATAR , BOOST_AVATAR_BAKED , - BOOST_SCULPTED , BOOST_TERRAIN , // Needed for minimap generation for now. Lower than BOOST_HIGH so the texture stats don't get forced, i.e. texture stats are manually managed by minimap/terrain instead. BOOST_HIGH = 10, + BOOST_SCULPTED , BOOST_BUMP , BOOST_UNUSED_1 , // Placeholder to avoid disrupting habits around texture debug BOOST_SELECTED , @@ -75,7 +75,6 @@ public: AVATAR_SCRATCH_TEX, DYNAMIC_TEX, MEDIA, - ATLAS, OTHER, MAX_GL_IMAGE_CATEGORY }; @@ -156,10 +155,7 @@ public: bool isJustBound()const ; void forceUpdateBindStats(void) const; - U32 getTexelsInAtlas() const ; - U32 getTexelsInGLTexture() const ; bool isGLTextureCreated() const ; - S32 getDiscardLevelInAtlas() const ; LLGLTextureState getTextureState() const { return mTextureState; } //--------------------------------------------------------------------------------------------- diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 7e5cd628c1..956bcef352 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -41,6 +41,7 @@ #include "llrender.h" #include "llwindow.h" #include "llframetimer.h" +#include extern LL_COMMON_API bool on_main_thread(); @@ -130,10 +131,9 @@ S32 LLImageGL::sCount = 0; bool LLImageGL::sGlobalUseAnisotropic = false; F32 LLImageGL::sLastFrameTime = 0.f; -bool LLImageGL::sAllowReadBackRaw = false ; LLImageGL* LLImageGL::sDefaultGLTexture = NULL ; bool LLImageGL::sCompressTextures = false; -std::set LLImageGL::sImageList; +std::unordered_set LLImageGL::sImageList; bool LLImageGLThread::sEnabledTextures = false; @@ -150,6 +150,9 @@ S32 LLImageGL::sMaxCategories = 1 ; //optimization for when we don't need to calculate mIsMask bool LLImageGL::sSkipAnalyzeAlpha; +U32 LLImageGL::sScratchPBO = 0; +U32 LLImageGL::sScratchPBOSize = 0; + //------------------------ //**************************************************************************************************** @@ -159,20 +162,6 @@ bool LLImageGL::sSkipAnalyzeAlpha; //************************************************************************************** //below are functions for debug use //do not delete them even though they are not currently being used. -void check_all_images() -{ - for (std::set::iterator iter = LLImageGL::sImageList.begin(); - iter != LLImageGL::sImageList.end(); iter++) - { - LLImageGL* glimage = *iter; - if (glimage->getTexName() && glimage->isGLTextureCreated()) - { - gGL.getTexUnit(0)->bind(glimage) ; - glimage->checkTexSize() ; - gGL.getTexUnit(0)->unbind(glimage->getTarget()) ; - } - } -} void LLImageGL::checkTexSize(bool forced) const { @@ -252,6 +241,11 @@ void LLImageGL::initClass(LLWindow* window, S32 num_catagories, bool skip_analyz LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; sSkipAnalyzeAlpha = skip_analyze_alpha; + if (sScratchPBO == 0) + { + glGenBuffers(1, &sScratchPBO); + } + if (thread_texture_loads || thread_media_updates) { LLImageGLThread::createInstance(window); @@ -265,6 +259,12 @@ void LLImageGL::cleanupClass() { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; LLImageGLThread::deleteSingleton(); + if (sScratchPBO != 0) + { + glDeleteBuffers(1, &sScratchPBO); + sScratchPBO = 0; + sScratchPBOSize = 0; + } } @@ -360,66 +360,19 @@ void LLImageGL::updateStats(F32 current_time) //---------------------------------------------------------------------------- //static -void LLImageGL::destroyGL(bool save_state) +void LLImageGL::destroyGL() { for (S32 stage = 0; stage < gGLManager.mNumTextureImageUnits; stage++) { gGL.getTexUnit(stage)->unbind(LLTexUnit::TT_TEXTURE); } - - sAllowReadBackRaw = true ; - for (std::set::iterator iter = sImageList.begin(); - iter != sImageList.end(); iter++) - { - LLImageGL* glimage = *iter; - if (glimage->mTexName) - { - if (save_state && glimage->isGLTextureCreated() && glimage->mComponents) - { - glimage->mSaveData = new LLImageRaw; - if(!glimage->readBackRaw(glimage->mCurrentDiscardLevel, glimage->mSaveData, false)) //necessary, keep it. - { - glimage->mSaveData = NULL ; - } - } - - glimage->destroyGLTexture(); - stop_glerror(); - } - } - sAllowReadBackRaw = false ; -} - -//static -void LLImageGL::restoreGL() -{ - for (std::set::iterator iter = sImageList.begin(); - iter != sImageList.end(); iter++) - { - LLImageGL* glimage = *iter; - if(glimage->getTexName()) - { - LL_ERRS() << "tex name is not 0." << LL_ENDL ; - } - if (glimage->mSaveData.notNull()) - { - if (glimage->getComponents() && glimage->mSaveData->getComponents()) - { - glimage->createGLTexture(glimage->mCurrentDiscardLevel, glimage->mSaveData, 0, true, glimage->getCategory()); - stop_glerror(); - } - glimage->mSaveData = NULL; // deletes data - } - } } //static void LLImageGL::dirtyTexOptions() { - for (std::set::iterator iter = sImageList.begin(); - iter != sImageList.end(); iter++) + for (auto& glimage : sImageList) { - LLImageGL* glimage = *iter; glimage->mTexOptionsDirty = true; stop_glerror(); } @@ -542,10 +495,6 @@ void LLImageGL::init(bool usemipmaps) mHeight = 0; mCurrentDiscardLevel = -1; - mDiscardLevelInAtlas = -1 ; - mTexelsInAtlas = 0 ; - mTexelsInGLTexture = 0 ; - mAllowCompression = true; mTarget = GL_TEXTURE_2D; @@ -622,9 +571,6 @@ bool LLImageGL::setSize(S32 width, S32 height, S32 ncomponents, S32 discard_leve return false; } - // pickmask validity depends on old image size, delete it - freePickMask(); - mWidth = width; mHeight = height; mComponents = ncomponents; @@ -1025,98 +971,6 @@ bool LLImageGL::setImage(const U8* data_in, bool data_hasmips /* = false */, S32 return true; } -bool LLImageGL::preAddToAtlas(S32 discard_level, const LLImageRaw* raw_image) -{ - //not compatible with core GL profile - llassert(!LLRender::sGLCoreProfile); - - if (gGLManager.mIsDisabled) - { - LL_WARNS() << "Trying to create a texture while GL is disabled!" << LL_ENDL; - return false; - } - llassert(gGLManager.mInited); - stop_glerror(); - - if (discard_level < 0) - { - llassert(mCurrentDiscardLevel >= 0); - discard_level = mCurrentDiscardLevel; - } - - // Actual image width/height = raw image width/height * 2^discard_level - S32 w = raw_image->getWidth() << discard_level; - S32 h = raw_image->getHeight() << discard_level; - - // setSize may call destroyGLTexture if the size does not match - if (!setSize(w, h, raw_image->getComponents(), discard_level)) - { - LL_WARNS() << "Trying to create a texture with incorrect dimensions!" << LL_ENDL; - return false; - } - - if (!mHasExplicitFormat) - { - switch (mComponents) - { - case 1: - // Use luminance alpha (for fonts) - mFormatInternal = GL_LUMINANCE8; - mFormatPrimary = GL_LUMINANCE; - mFormatType = GL_UNSIGNED_BYTE; - break; - case 2: - // Use luminance alpha (for fonts) - mFormatInternal = GL_LUMINANCE8_ALPHA8; - mFormatPrimary = GL_LUMINANCE_ALPHA; - mFormatType = GL_UNSIGNED_BYTE; - break; - case 3: - mFormatInternal = GL_RGB8; - mFormatPrimary = GL_RGB; - mFormatType = GL_UNSIGNED_BYTE; - break; - case 4: - mFormatInternal = GL_RGBA8; - mFormatPrimary = GL_RGBA; - mFormatType = GL_UNSIGNED_BYTE; - break; - default: - LL_ERRS() << "Bad number of components for texture: " << (U32) getComponents() << LL_ENDL; - } - } - - mCurrentDiscardLevel = discard_level; - mDiscardLevelInAtlas = discard_level; - mTexelsInAtlas = raw_image->getWidth() * raw_image->getHeight() ; - mLastBindTime = sLastFrameTime; - mGLTextureCreated = false ; - - glPixelStorei(GL_UNPACK_ROW_LENGTH, raw_image->getWidth()); - stop_glerror(); - - if(mFormatSwapBytes) - { - glPixelStorei(GL_UNPACK_SWAP_BYTES, 1); - stop_glerror(); - } - - return true ; -} - -void LLImageGL::postAddToAtlas() -{ - if(mFormatSwapBytes) - { - glPixelStorei(GL_UNPACK_SWAP_BYTES, 0); - stop_glerror(); - } - - glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - gGL.getTexUnit(0)->setTextureFilteringOption(mFilterOption); - stop_glerror(); -} - U32 type_width_from_pixtype(U32 pixtype) { U32 type_width = 0; @@ -1752,7 +1606,6 @@ bool LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, bool data_ mTextureMemory = (S64Bytes)getMipBytes(mCurrentDiscardLevel); - mTexelsInGLTexture = getWidth() * getHeight(); // mark this as bound at this point, so we don't throw it out immediately mLastBindTime = sLastFrameTime; @@ -1830,8 +1683,7 @@ void LLImageGL::syncTexName(LLGLuint texname) bool LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok) const { - llassert_always(sAllowReadBackRaw) ; - //LL_ERRS() << "should not call this function!" << LL_ENDL ; + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; if (discard_level < 0) { @@ -2297,6 +2149,8 @@ void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h) //---------------------------------------------------------------------------- U32 LLImageGL::createPickMask(S32 pWidth, S32 pHeight) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + freePickMask(); U32 pick_width = pWidth/2 + 1; U32 pick_height = pHeight/2 + 1; @@ -2314,7 +2168,6 @@ U32 LLImageGL::createPickMask(S32 pWidth, S32 pHeight) //---------------------------------------------------------------------------- void LLImageGL::freePickMask() { - // pickmask validity depends on old image size, delete it if (mPickMask != NULL) { delete [] mPickMask; @@ -2352,16 +2205,16 @@ void LLImageGL::updatePickMask(S32 width, S32 height, const U8* data_in) return ; } - freePickMask(); - if (mFormatType != GL_UNSIGNED_BYTE || ((mFormatPrimary != GL_RGBA) && (mFormatPrimary != GL_SRGB_ALPHA))) { //cannot generate a pick mask for this texture + freePickMask(); return; } + #ifdef SHOW_ASSERT const U32 pickSize = createPickMask(width, height); #else // SHOW_ASSERT @@ -2460,6 +2313,73 @@ void LLImageGL::resetCurTexSizebar() sCurTexSizeBar = -1 ; sCurTexPickSize = -1 ; } + +bool LLImageGL::scaleDown(S32 desired_discard) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + + if (mTarget != GL_TEXTURE_2D) + { + return false; + } + + desired_discard = llmin(desired_discard, mMaxDiscardLevel); + + if (desired_discard <= mCurrentDiscardLevel) + { + return false; + } + + S32 mip = desired_discard - mCurrentDiscardLevel; + + S32 desired_width = getWidth(desired_discard); + S32 desired_height = getHeight(desired_discard); + + U64 size = getBytes(desired_discard); + llassert(size <= 2048*2048*4); // we shouldn't be using this method to downscale huge textures, but it'll work + gGL.getTexUnit(0)->bind(this); + + + if (sScratchPBO == 0) + { + glGenBuffers(1, &sScratchPBO); + sScratchPBOSize = 0; + } + + glBindBuffer(GL_PIXEL_PACK_BUFFER, sScratchPBO); + + if (size > sScratchPBOSize) + { + glBufferData(GL_PIXEL_PACK_BUFFER, size, NULL, GL_STREAM_COPY); + sScratchPBOSize = size; + } + + glGetTexImage(mTarget, mip, mFormatPrimary, mFormatType, nullptr); + + free_tex_image(mTexName); + + glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); + + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, sScratchPBO); + glTexImage2D(mTarget, 0, mFormatPrimary, desired_width, desired_height, 0, mFormatPrimary, mFormatType, nullptr); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + + alloc_tex_image(desired_width, desired_height, mFormatPrimary); + + if (mHasMipMaps) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("scaleDown - glGenerateMipmap"); + glGenerateMipmap(mTarget); + } + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + + mCurrentDiscardLevel = desired_discard; + + return true; +} + + //---------------------------------------------------------------------------- #if LL_IMAGEGL_THREAD_CHECK void LLImageGL::checkActiveThread() diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h index 5c7a5ce821..3892e9c014 100644 --- a/indra/llrender/llimagegl.h +++ b/indra/llrender/llimagegl.h @@ -39,6 +39,7 @@ #include "llrender.h" #include "threadpool.h" #include "workqueue.h" +#include #define LL_IMAGEGL_THREAD_CHECK 0 //set to 1 to enable thread debugging for ImageGL @@ -83,9 +84,8 @@ public: // needs to be called every frame static void updateStats(F32 current_time); - // Save off / restore GL textures - static void destroyGL(bool save_state = true); - static void restoreGL(); + // cleanup GL state + static void destroyGL(); static void dirtyTexOptions(); static bool checkSize(S32 width, S32 height); @@ -148,6 +148,10 @@ public: S32 getDiscardLevel() const { return mCurrentDiscardLevel; } S32 getMaxDiscardLevel() const { return mMaxDiscardLevel; } + // override the current discard level + // should only be used for local textures where you know exactly what you're doing + void setDiscardLevel(S32 level) { mCurrentDiscardLevel = level; } + S32 getCurrentWidth() const { return mWidth ;} S32 getCurrentHeight() const { return mHeight ;} S32 getWidth(S32 discard_level = -1) const; @@ -194,26 +198,26 @@ public: void setFilteringOption(LLTexUnit::eTextureFilterOptions option); LLTexUnit::eTextureFilterOptions getFilteringOption(void) const { return mFilterOption; } - LLGLenum getTexTarget()const { return mTarget ;} - S8 getDiscardLevelInAtlas()const {return mDiscardLevelInAtlas;} - U32 getTexelsInAtlas()const { return mTexelsInAtlas ;} - U32 getTexelsInGLTexture()const {return mTexelsInGLTexture;} - + LLGLenum getTexTarget()const { return mTarget; } void init(bool usemipmaps); virtual void cleanup(); // Clean up the LLImageGL so it can be reinitialized. Be careful when using this in derived class destructors void setNeedsAlphaAndPickMask(bool need_mask); - bool preAddToAtlas(S32 discard_level, const LLImageRaw* raw_image); - void postAddToAtlas() ; - #if LL_IMAGEGL_THREAD_CHECK // thread debugging std::thread::id mActiveThread; void checkActiveThread(); #endif + // scale down to the desired discard level using GPU + // returns true if texture was scaled down + // desired discard will be clamped to max discard + // if desired discard is less than or equal to current discard, no scaling will occur + // only works for GL_TEXTURE_2D target + bool scaleDown(S32 desired_discard); + public: // Various GL/Rendering options S64Bytes mTextureMemory; @@ -240,15 +244,10 @@ private: bool mGLTextureCreated ; LLGLuint mTexName; - //LLGLuint mNewTexName = 0; // tex name set by background thread to be applied in main thread U16 mWidth; U16 mHeight; S8 mCurrentDiscardLevel; - S8 mDiscardLevelInAtlas; - U32 mTexelsInAtlas ; - U32 mTexelsInGLTexture; - bool mAllowCompression; protected: @@ -275,7 +274,7 @@ protected: // STATICS public: - static std::set sImageList; + static std::unordered_set sImageList; static S32 sCount; static F32 sLastFrameTime; @@ -301,6 +300,8 @@ public: private: static S32 sMaxCategories; static bool sSkipAnalyzeAlpha; + static U32 sScratchPBO; + static U32 sScratchPBOSize; //the flag to allow to call readBackRaw(...). //can be removed if we do not use that function at all. diff --git a/indra/newview/app_settings/shaders/class1/deferred/normgenF.glsl b/indra/newview/app_settings/shaders/class1/deferred/normgenF.glsl index 902746366d..6d05d983f3 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/normgenF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/normgenF.glsl @@ -25,24 +25,53 @@ /*[EXTRA_CODE_HERE]*/ + + +// generate a normal map using an approximation of the old emboss bump map "brightness/darkness" technique +// srcMap is a source color image, output should be a normal + out vec4 frag_color; -uniform sampler2D alphaMap; +uniform sampler2D srcMap; in vec2 vary_texcoord0; uniform float stepX; uniform float stepY; uniform float norm_scale; +uniform int bump_code; + +#define BE_BRIGHTNESS 1 +#define BE_DARKNESS 2 + +// get luminance or inverse luminance depending on bump_code +float getBumpValue(vec2 texcoord) +{ + vec3 c = texture(srcMap, texcoord).rgb; + + vec3 WEIGHT = vec3(0.2995, 0.5875, 0.1145); + + float l = dot(c, WEIGHT); + + if (bump_code == BE_DARKNESS) + { + l = 1.0 - l; + } + + return l; +} + void main() { - float c = texture(alphaMap, vary_texcoord0).r; + float c = getBumpValue(vary_texcoord0).r; - vec3 right = vec3(norm_scale, 0, (texture(alphaMap, vary_texcoord0+vec2(stepX, 0)).r-c)*255); - vec3 left = vec3(-norm_scale, 0, (texture(alphaMap, vary_texcoord0-vec2(stepX, 0)).r-c)*255); - vec3 up = vec3(0, -norm_scale, (texture(alphaMap, vary_texcoord0-vec2(0, stepY)).r-c)*255); - vec3 down = vec3(0, norm_scale, (texture(alphaMap, vary_texcoord0+vec2(0, stepY)).r-c)*255); + float scaler = 512.0; + + vec3 right = vec3(norm_scale, 0, (getBumpValue(vary_texcoord0+vec2(stepX, 0)).r-c)*scaler); + vec3 left = vec3(-norm_scale, 0, (getBumpValue(vary_texcoord0-vec2(stepX, 0)).r-c)*scaler); + vec3 up = vec3(0, -norm_scale, (getBumpValue(vary_texcoord0-vec2(0, stepY)).r-c)*scaler); + vec3 down = vec3(0, norm_scale, (getBumpValue(vary_texcoord0+vec2(0, stepY)).r-c)*scaler); vec3 norm = cross(right, down) + cross(down, left) + cross(left,up) + cross(up, right); diff --git a/indra/newview/gltf/buffer_util.h b/indra/newview/gltf/buffer_util.h index 40f9448aaf..89cedf4a47 100644 --- a/indra/newview/gltf/buffer_util.h +++ b/indra/newview/gltf/buffer_util.h @@ -180,6 +180,16 @@ namespace LL data[3] = src[3]; } + template<> + inline void copyVec4(U8* src, U64& dst) + { + U8* data = (U8*)&dst; + data[0] = src[0]; + data[1] = src[1]; + data[2] = src[2]; + data[3] = src[3]; + } + template<> inline void copyVec4(U16* src, LLColor4U& dst) { diff --git a/indra/newview/gltfscenemanager.cpp b/indra/newview/gltfscenemanager.cpp index 7b2de4d6de..a0cbe9290c 100644 --- a/indra/newview/gltfscenemanager.cpp +++ b/indra/newview/gltfscenemanager.cpp @@ -144,7 +144,7 @@ void GLTFSceneManager::uploadSelection() } else { - raw = image.mTexture->getCachedRawImage(); + raw = image.mTexture->getRawImage(); } if (raw.notNull()) @@ -339,6 +339,7 @@ void GLTFSceneManager::renderAlpha() void GLTFSceneManager::addGLTFObject(LLViewerObject* obj, LLUUID gltf_id) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_GLTF; llassert(obj->getVolume()->getParams().getSculptID() == gltf_id); llassert(obj->getVolume()->getParams().getSculptType() == LL_SCULPT_TYPE_GLTF); diff --git a/indra/newview/lldebugview.cpp b/indra/newview/lldebugview.cpp index b88d11886a..0596a8fe7d 100644 --- a/indra/newview/lldebugview.cpp +++ b/indra/newview/lldebugview.cpp @@ -105,10 +105,7 @@ void LLDebugView::init() addChild(gSceneMonitorView); gSceneMonitorView->setRect(rect); - r.setLeftTopAndSize(25, rect.getHeight() - 50, (S32) (gViewerWindow->getWindowRectScaled().getWidth() * 0.75f), - (S32) (gViewerWindow->getWindowRectScaled().getHeight() * 0.75f)); - - r.set(150, rect.getHeight() - 50, 820, 100); + r.set(150, rect.getHeight() - 60, 820, 110); LLTextureView::Params tvp; tvp.name("gTextureView"); tvp.rect(r); @@ -116,7 +113,6 @@ void LLDebugView::init() tvp.visible(false); gTextureView = LLUICtrlFactory::create(tvp); addChild(gTextureView); - //gTextureView->reshape(r.getWidth(), r.getHeight(), true); } void LLDebugView::draw() diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp index 055f99d764..7289e95b6e 100644 --- a/indra/newview/lldrawpoolbump.cpp +++ b/indra/newview/lldrawpoolbump.cpp @@ -79,11 +79,6 @@ static S32 diffuse_channel = -1; static S32 bump_channel = -1; static bool shiny = false; -// Enabled after changing LLViewerTexture::mNeedsCreateTexture to an -// LLAtomicBool; this should work just fine, now. HB -#define LL_BUMPLIST_MULTITHREADED 1 - - // static void LLStandardBumpmap::shutdown() { @@ -764,24 +759,21 @@ LLViewerTexture* LLBumpImageList::getBrightnessDarknessImage(LLViewerFetchedText LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; llassert( (bump_code == BE_BRIGHTNESS) || (bump_code == BE_DARKNESS) ); - LLViewerTexture* bump = NULL; + LLViewerTexture* bump = nullptr; - bump_image_map_t* entries_list = NULL; - void (*callback_func)( bool success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, bool final, void* userdata ) = NULL; + bump_image_map_t* entries_list = nullptr; switch( bump_code ) { case BE_BRIGHTNESS: entries_list = &mBrightnessEntries; - callback_func = LLBumpImageList::onSourceBrightnessLoaded; break; case BE_DARKNESS: entries_list = &mDarknessEntries; - callback_func = LLBumpImageList::onSourceDarknessLoaded; break; default: llassert(0); - return NULL; + return nullptr; } bump_image_map_t::iterator iter = entries_list->find(src_image->getID()); @@ -789,51 +781,18 @@ LLViewerTexture* LLBumpImageList::getBrightnessDarknessImage(LLViewerFetchedText { bump = iter->second; } - else + + if (bump == nullptr || + src_image->getWidth() != bump->getWidth() || + src_image->getHeight() != bump->getHeight()) { - (*entries_list)[src_image->getID()] = LLViewerTextureManager::getLocalTexture( true ); - bump = (*entries_list)[src_image->getID()]; // In case callback was called immediately and replaced the image + onSourceUpdated(src_image, (EBumpEffect) bump_code); } - if (!src_image->hasCallbacks()) - { //if image has no callbacks but resolutions don't match, trigger raw image loaded callback again - if (src_image->getWidth() != bump->getWidth() || - src_image->getHeight() != bump->getHeight())// || - //(LLPipeline::sRenderDeferred && bump->getComponents() != 4)) - { - src_image->setBoostLevel(LLGLTexture::BOOST_BUMP) ; - src_image->setLoadedCallback( callback_func, 0, true, false, new LLUUID(src_image->getID()), NULL ); - src_image->forceToSaveRawImage(0) ; - } - } - - return bump; + return (*entries_list)[src_image->getID()]; } -// static -void LLBumpImageList::onSourceBrightnessLoaded( bool success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, bool final, void* userdata ) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; - LLUUID* source_asset_id = (LLUUID*)userdata; - LLBumpImageList::onSourceLoaded( success, src_vi, src, *source_asset_id, BE_BRIGHTNESS ); - if( final ) - { - delete source_asset_id; - } -} - -// static -void LLBumpImageList::onSourceDarknessLoaded( bool success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, bool final, void* userdata ) -{ - LLUUID* source_asset_id = (LLUUID*)userdata; - LLBumpImageList::onSourceLoaded( success, src_vi, src, *source_asset_id, BE_DARKNESS ); - if( final ) - { - delete source_asset_id; - } -} - void LLBumpImageList::onSourceStandardLoaded( bool success, LLViewerFetchedTexture* src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, bool final, void* userdata) { if (success && LLPipeline::sRenderDeferred) @@ -909,289 +868,108 @@ void LLBumpImageList::generateNormalMapFromAlpha(LLImageRaw* src, LLImageRaw* nr } // static -void LLBumpImageList::onSourceLoaded( bool success, LLViewerTexture *src_vi, LLImageRaw* src, LLUUID& source_asset_id, EBumpEffect bump_code ) +void LLBumpImageList::onSourceUpdated(LLViewerTexture* src, EBumpEffect bump_code) { - LL_PROFILE_ZONE_SCOPED; + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; - if( success ) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; + const LLUUID& src_id = src->getID(); - LLImageDataSharedLock lock(src); + bump_image_map_t& entries_list(bump_code == BE_BRIGHTNESS ? gBumpImageList.mBrightnessEntries : gBumpImageList.mDarknessEntries); + bump_image_map_t::iterator iter = entries_list.find(src_id); - bump_image_map_t& entries_list(bump_code == BE_BRIGHTNESS ? gBumpImageList.mBrightnessEntries : gBumpImageList.mDarknessEntries ); - bump_image_map_t::iterator iter = entries_list.find(source_asset_id); - - { - if (iter == entries_list.end() || - iter->second.isNull() || - iter->second->getWidth() != src->getWidth() || - iter->second->getHeight() != src->getHeight()) // bump not cached yet or has changed resolution - { //make sure an entry exists for this image - entries_list[src_vi->getID()] = LLViewerTextureManager::getLocalTexture(true); - iter = entries_list.find(src_vi->getID()); - } - } - - if (iter->second->getWidth() != src->getWidth() || - iter->second->getHeight() != src->getHeight()) // bump not cached yet or has changed resolution - { - LLPointer dst_image = new LLImageRaw(src->getWidth(), src->getHeight(), 1); - U8* dst_data = dst_image->getData(); - S32 dst_data_size = dst_image->getDataSize(); - - const U8* src_data = src->getData(); - S32 src_data_size = src->getDataSize(); - - S32 src_components = src->getComponents(); - - // Convert to luminance and then scale and bias that to get ready for - // embossed bump mapping. (0-255 maps to 127-255) - - // Convert to fixed point so we don't have to worry about precision/clamping. - const S32 FIXED_PT = 8; - const S32 R_WEIGHT = S32(0.2995f * (1< maximum ) - { - maximum = dst_data[i]; - } - } - } - else - { - llassert(0); - dst_image->clear(); - } - } - break; - case 3: - case 4: - { - if( src_data_size == dst_data_size * src_components ) - { - for( S32 i = 0, j=0; i < dst_data_size; i++, j+= src_components ) - { - // RGB to luminance - dst_data[i] = (R_WEIGHT * src_data[j] + G_WEIGHT * src_data[j+1] + B_WEIGHT * src_data[j+2]) >> FIXED_PT; - //llassert( dst_data[i] <= 255 );true because it's 8bit - if( dst_data[i] < minimum ) - { - minimum = dst_data[i]; - } - if( dst_data[i] > maximum ) - { - maximum = dst_data[i]; - } - } - } - else - { - llassert(0); - dst_image->clear(); - } - } - break; - default: - llassert(0); - dst_image->clear(); - break; - } - - if( maximum > minimum ) - { - U8 bias_and_scale_lut[256]; - F32 twice_one_over_range = 2.f / (maximum - minimum); - S32 i; - - const F32 ARTIFICIAL_SCALE = 2.f; // Advantage: exaggerates the effect in midrange. Disadvantage: clamps at the extremes. - if (BE_DARKNESS == bump_code) - { - for( i = minimum; i <= maximum; i++ ) - { - F32 minus_one_to_one = F32(maximum - i) * twice_one_over_range - 1.f; - bias_and_scale_lut[i] = llclampb(ll_round(127 * minus_one_to_one * ARTIFICIAL_SCALE + 128)); - } - } - else - { - for( i = minimum; i <= maximum; i++ ) - { - F32 minus_one_to_one = F32(i - minimum) * twice_one_over_range - 1.f; - bias_and_scale_lut[i] = llclampb(ll_round(127 * minus_one_to_one * ARTIFICIAL_SCALE + 128)); - } - } - - for( i = 0; i < dst_data_size; i++ ) - { - dst_data[i] = bias_and_scale_lut[dst_data[i]]; - } - } - - //--------------------------------------------------- - // immediately assign bump to a smart pointer in case some local smart pointer - // accidentally releases it. - LLPointer bump = iter->second; - - if (!LLPipeline::sRenderDeferred) - { - bump->setExplicitFormat(GL_ALPHA8, GL_ALPHA); - -#if LL_BUMPLIST_MULTITHREADED - auto tex_queue = LLImageGLThread::sEnabledTextures ? sTexUpdateQueue.lock() : nullptr; - - if (tex_queue) - { //dispatch creation to background thread - LLImageRaw* dst_ptr = dst_image; - LLViewerTexture* bump_ptr = bump; - dst_ptr->ref(); - bump_ptr->ref(); - tex_queue->post( - [=]() - { - LL_PROFILE_ZONE_NAMED("bil - create texture"); - bump_ptr->createGLTexture(0, dst_ptr); - bump_ptr->unref(); - dst_ptr->unref(); - }); - - } - else -#endif - { - bump->createGLTexture(0, dst_image); - } - } - else - { //convert to normal map - LL_PROFILE_ZONE_NAMED("bil - create normal map"); - LLImageGL* img = bump->getGLTexture(); - LLImageRaw* dst_ptr = dst_image.get(); - LLGLTexture* bump_ptr = bump.get(); - - dst_ptr->ref(); - img->ref(); - bump_ptr->ref(); - auto create_func = [=]() - { - img->setUseMipMaps(true); - // upload dst_image to GPU (greyscale in red channel) - img->setExplicitFormat(GL_RED, GL_RED); - - bump_ptr->createGLTexture(0, dst_ptr); - dst_ptr->unref(); - }; - - auto generate_func = [=]() - { - // Allocate an empty RGBA texture at "tex_name" the same size as bump - // Note: bump will still point at GPU copy of dst_image - bump_ptr->setExplicitFormat(GL_RGBA, GL_RGBA); - LLGLuint tex_name; - img->createGLTexture(0, nullptr, false, 0, true, &tex_name); - - // point render target at empty buffer - sRenderTarget.setColorAttachment(img, tex_name); - - // generate normal map in empty texture - { - sRenderTarget.bindTarget(); - - LLGLDepthTest depth(GL_FALSE); - LLGLDisable cull(GL_CULL_FACE); - LLGLDisable blend(GL_BLEND); - gGL.setColorMask(true, true); - - gNormalMapGenProgram.bind(); - - static LLStaticHashedString sNormScale("norm_scale"); - static LLStaticHashedString sStepX("stepX"); - static LLStaticHashedString sStepY("stepY"); - - gNormalMapGenProgram.uniform1f(sNormScale, gSavedSettings.getF32("RenderNormalMapScale")); - gNormalMapGenProgram.uniform1f(sStepX, 1.f / bump_ptr->getWidth()); - gNormalMapGenProgram.uniform1f(sStepY, 1.f / bump_ptr->getHeight()); - - gGL.getTexUnit(0)->bind(bump_ptr); - - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.texCoord2f(0, 0); - gGL.vertex2f(0, 0); - - gGL.texCoord2f(0, 1); - gGL.vertex2f(0, 1); - - gGL.texCoord2f(1, 0); - gGL.vertex2f(1, 0); - - gGL.texCoord2f(1, 1); - gGL.vertex2f(1, 1); - - gGL.end(); - - gGL.flush(); - - gNormalMapGenProgram.unbind(); - - sRenderTarget.flush(); - sRenderTarget.releaseColorAttachment(); - } - - // point bump at normal map and free gpu copy of dst_image - img->syncTexName(tex_name); - - // generate mipmap - gGL.getTexUnit(0)->bind(img); - glGenerateMipmap(GL_TEXTURE_2D); - gGL.getTexUnit(0)->disable(); - - bump_ptr->unref(); - img->unref(); - }; - -#if LL_BUMPLIST_MULTITHREADED - auto main_queue = LLImageGLThread::sEnabledTextures ? sMainQueue.lock() : nullptr; - - if (main_queue) - { //dispatch texture upload to background thread, issue GPU commands to generate normal map on main thread - main_queue->postTo( - sTexUpdateQueue, - create_func, - generate_func); - } - else -#endif - { // immediate upload texture and generate normal map - create_func(); - generate_func(); - } - - - } - - iter->second = bump; // derefs (and deletes) old image - //--------------------------------------------------- - } + if (iter == entries_list.end()) + { //make sure an entry exists for this image + entries_list[src_id] = LLViewerTextureManager::getLocalTexture(true); + iter = entries_list.find(src_id); } + + //--------------------------------------------------- + // immediately assign bump to a smart pointer in case some local smart pointer + // accidentally releases it. + LLPointer bump = iter->second; + + if (bump->getWidth() != src->getWidth() || + bump->getHeight() != src->getHeight()) // bump not cached yet or has changed resolution + { + //convert to normal map + LL_PROFILE_ZONE_NAMED("bil - create normal map"); + + bump->setExplicitFormat(GL_RGBA, GL_RGBA); + + LLImageGL* src_img = src->getGLTexture(); + LLImageGL* dst_img = bump->getGLTexture(); + dst_img->setSize(src->getWidth(), src->getHeight(), 4, 0); + dst_img->setUseMipMaps(true); + dst_img->setDiscardLevel(0); + dst_img->createGLTexture(); + + gGL.getTexUnit(0)->bind(bump); + + LLImageGL::setManualImage(GL_TEXTURE_2D, 0, dst_img->getPrimaryFormat(), dst_img->getWidth(), dst_img->getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, nullptr, false); + + LLGLuint tex_name = dst_img->getTexName(); + // point render target at empty buffer + sRenderTarget.setColorAttachment(bump->getGLTexture(), tex_name); + + // generate normal map in empty texture + { + sRenderTarget.bindTarget(); + + LLGLDepthTest depth(GL_FALSE); + LLGLDisable cull(GL_CULL_FACE); + LLGLDisable blend(GL_BLEND); + gGL.setColorMask(true, true); + + LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; + gNormalMapGenProgram.bind(); + + static LLStaticHashedString sNormScale("norm_scale"); + static LLStaticHashedString sStepX("stepX"); + static LLStaticHashedString sStepY("stepY"); + static LLStaticHashedString sBumpCode("bump_code"); + + gNormalMapGenProgram.uniform1f(sNormScale, gSavedSettings.getF32("RenderNormalMapScale")); + gNormalMapGenProgram.uniform1f(sStepX, 1.f / bump->getWidth()); + gNormalMapGenProgram.uniform1f(sStepY, 1.f / bump->getHeight()); + gNormalMapGenProgram.uniform1i(sBumpCode, bump_code); + + gGL.getTexUnit(0)->bind(src); + + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.texCoord2f(0, 0); + gGL.vertex2f(0, 0); + + gGL.texCoord2f(0, 1); + gGL.vertex2f(0, 1); + + gGL.texCoord2f(1, 0); + gGL.vertex2f(1, 0); + + gGL.texCoord2f(1, 1); + gGL.vertex2f(1, 1); + + gGL.end(); + + gGL.flush(); + + sRenderTarget.flush(); + sRenderTarget.releaseColorAttachment(); + + if (shader) + { + shader->bind(); + } + } + + // generate mipmap + gGL.getTexUnit(0)->bind(bump); + glGenerateMipmap(GL_TEXTURE_2D); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + } + + iter->second = bump; // derefs (and deletes) old image + //--------------------------------------------------- + } void LLDrawPoolBump::pushBumpBatches(U32 type) diff --git a/indra/newview/lldrawpoolbump.h b/indra/newview/lldrawpoolbump.h index 65cb9af015..15976884ca 100644 --- a/indra/newview/lldrawpoolbump.h +++ b/indra/newview/lldrawpoolbump.h @@ -140,14 +140,13 @@ public: LLViewerTexture* getBrightnessDarknessImage(LLViewerFetchedTexture* src_image, U8 bump_code); void addTextureStats(U8 bump, const LLUUID& base_image_id, F32 virtual_size); - static void onSourceBrightnessLoaded( bool success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, bool final, void* userdata ); - static void onSourceDarknessLoaded( bool success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, bool final, void* userdata ); static void onSourceStandardLoaded( bool success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, bool final, void* userdata ); static void generateNormalMapFromAlpha(LLImageRaw* src, LLImageRaw* nrm_image); private: - static void onSourceLoaded( bool success, LLViewerTexture *src_vi, LLImageRaw* src, LLUUID& source_asset_id, EBumpEffect bump ); + // should be called whenever resolution of src_vi changes compared to the current entry + static void onSourceUpdated( LLViewerTexture *src_vi, EBumpEffect bump ); private: typedef std::unordered_map > bump_image_map_t; diff --git a/indra/newview/llfloaterchangeitemthumbnail.cpp b/indra/newview/llfloaterchangeitemthumbnail.cpp index 3e2e7cb7a3..fb31361fd9 100644 --- a/indra/newview/llfloaterchangeitemthumbnail.cpp +++ b/indra/newview/llfloaterchangeitemthumbnail.cpp @@ -951,8 +951,8 @@ void LLFloaterChangeItemThumbnail::onTexturePickerCommit() || texturep->getFullWidth() == 0) { if (texturep->isFullyLoaded() - && (texturep->getCachedRawImageLevel() == 0 || texturep->getRawImageLevel() == 0) - && (texturep->isCachedRawImageReady() || texturep->isRawImageValid())) + && (texturep->getRawImageLevel() == 0) + && (texturep->isRawImageValid())) { LLUUID task_id = mTaskId; uuid_set_t inventory_ids = mItemList; @@ -962,20 +962,10 @@ void LLFloaterChangeItemThumbnail::onTexturePickerCommit() { onUploadComplete(asset_id, task_id, inventory_ids, handle); }; - if (texturep->isRawImageValid()) - { - LLFloaterSimpleSnapshot::uploadThumbnail(texturep->getRawImage(), - *mItemList.begin(), - mTaskId, - callback); - } - else - { - LLFloaterSimpleSnapshot::uploadThumbnail(texturep->getCachedRawImage(), - *mItemList.begin(), - mTaskId, - callback); - } + LLFloaterSimpleSnapshot::uploadThumbnail(texturep->getRawImage(), + *mItemList.begin(), + mTaskId, + callback); } else { diff --git a/indra/newview/lllocalbitmaps.cpp b/indra/newview/lllocalbitmaps.cpp index 6ab5e05b7d..0e2b3cb409 100644 --- a/indra/newview/lllocalbitmaps.cpp +++ b/indra/newview/lllocalbitmaps.cpp @@ -215,7 +215,6 @@ bool LLLocalBitmap::updateSelf(EUpdateType optional_firstupdate) ("file://"+mFilename, FTT_LOCAL_FILE, mWorldID, LL_LOCAL_USE_MIPMAPS); texture->createGLTexture(LL_LOCAL_DISCARD_LEVEL, raw_image); - texture->setCachedRawImage(LL_LOCAL_DISCARD_LEVEL, raw_image); texture->ref(); gTextureList.addImage(texture, TEX_LIST_STANDARD); diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp index 1410232a0f..fd968d9027 100644 --- a/indra/newview/llnetmap.cpp +++ b/indra/newview/llnetmap.cpp @@ -296,8 +296,6 @@ void LLNetMap::draw() gGL.color4f(1.f, 0.5f, 0.5f, 1.f); } - - // Draw using texture. gGL.getTexUnit(0)->bind(regionp->getLand().getSTexture()); gGL.begin(LLRender::QUADS); @@ -311,24 +309,6 @@ void LLNetMap::draw() gGL.vertex2f(right, top); gGL.end(); - // Draw water - gGL.flush(); - { - if (regionp->getLand().getWaterTexture()) - { - gGL.getTexUnit(0)->bind(regionp->getLand().getWaterTexture()); - gGL.begin(LLRender::QUADS); - gGL.texCoord2f(0.f, 1.f); - gGL.vertex2f(left, top); - gGL.texCoord2f(0.f, 0.f); - gGL.vertex2f(left, bottom); - gGL.texCoord2f(1.f, 0.f); - gGL.vertex2f(right, bottom); - gGL.texCoord2f(1.f, 1.f); - gGL.vertex2f(right, top); - gGL.end(); - } - } gGL.flush(); } diff --git a/indra/newview/llsurface.cpp b/indra/newview/llsurface.cpp index e6bced5c92..1826885069 100644 --- a/indra/newview/llsurface.cpp +++ b/indra/newview/llsurface.cpp @@ -54,6 +54,7 @@ #include "llglheaders.h" #include "lldrawpoolterrain.h" #include "lldrawable.h" +#include "llworldmipmap.h" extern LLPipeline gPipeline; extern bool gShiftFrame; @@ -74,7 +75,6 @@ LLSurface::LLSurface(U32 type, LLViewerRegion *regionp) : mDetailTextureScale(0.f), mOriginGlobal(0.0, 0.0, 0.0), mSTexturep(NULL), - mWaterTexturep(NULL), mGridsPerPatchEdge(0), mMetersPerGrid(1.0f), mMetersPerEdge(1.0f), @@ -129,14 +129,7 @@ LLSurface::~LLSurface() { gPipeline.removePool(poolp); // Don't enable this until we blitz the draw pool for it as well. -- djs - if (mSTexturep) - { - mSTexturep = NULL; - } - if (mWaterTexturep) - { - mWaterTexturep = NULL; - } + mSTexturep = NULL; } else { @@ -216,62 +209,17 @@ LLViewerTexture* LLSurface::getSTexture() return mSTexturep; } -LLViewerTexture* LLSurface::getWaterTexture() -{ - if (mWaterTexturep.notNull() && !mWaterTexturep->hasGLTexture()) - { - createWaterTexture(); - } - return mWaterTexturep; -} - void LLSurface::createSTexture() { if (!mSTexturep) { - // Fill with dummy gray data. - // GL NOT ACTIVE HERE - LLPointer raw = new LLImageRaw(sTextureSize, sTextureSize, 3); - U8 *default_texture = raw->getData(); - for (S32 i = 0; i < sTextureSize; i++) - { - for (S32 j = 0; j < sTextureSize; j++) - { - *(default_texture + (i*sTextureSize + j)*3) = 128; - *(default_texture + (i*sTextureSize + j)*3 + 1) = 128; - *(default_texture + (i*sTextureSize + j)*3 + 2) = 128; - } - } + U64 handle = mRegionp->getHandle(); - mSTexturep = LLViewerTextureManager::getLocalTexture(raw.get(), false); - mSTexturep->dontDiscard(); - gGL.getTexUnit(0)->bind(mSTexturep); - mSTexturep->setAddressMode(LLTexUnit::TAM_CLAMP); - } -} + U32 grid_x, grid_y; -void LLSurface::createWaterTexture() -{ - if (!mWaterTexturep) - { - // Create the water texture - LLPointer raw = new LLImageRaw(sTextureSize/2, sTextureSize/2, 4); - U8 *default_texture = raw->getData(); - for (S32 i = 0; i < sTextureSize/2; i++) - { - for (S32 j = 0; j < sTextureSize/2; j++) - { - *(default_texture + (i*sTextureSize/2 + j)*4) = MAX_WATER_COLOR.mV[0]; - *(default_texture + (i*sTextureSize/2 + j)*4 + 1) = MAX_WATER_COLOR.mV[1]; - *(default_texture + (i*sTextureSize/2 + j)*4 + 2) = MAX_WATER_COLOR.mV[2]; - *(default_texture + (i*sTextureSize/2 + j)*4 + 3) = MAX_WATER_COLOR.mV[3]; - } - } + grid_from_region_handle(handle, &grid_x, &grid_y); - mWaterTexturep = LLViewerTextureManager::getLocalTexture(raw.get(), false); - mWaterTexturep->dontDiscard(); - gGL.getTexUnit(0)->bind(mWaterTexturep); - mWaterTexturep->setAddressMode(LLTexUnit::TAM_CLAMP); + mSTexturep = LLWorldMipmap::loadObjectsTile(grid_x, grid_y, 1); } } @@ -285,11 +233,10 @@ void LLSurface::initTextures() /////////////////////// // - // Water texture + // Water object // if (gSavedSettings.getBOOL("RenderWater") ) { - createWaterTexture(); mWaterObjp = (LLVOWater *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_WATER, mRegionp); gPipeline.createObject(mWaterObjp); LLVector3d water_pos_global = from_region_handle(mRegionp->getHandle()); @@ -683,11 +630,8 @@ bool LLSurface::idleUpdate(F32 max_update_time) } } - if (did_update) - { - // some patches changed, update region reflection probes - mRegionp->updateReflectionProbes(); - } + // some patches changed, update region reflection probes + mRegionp->updateReflectionProbes(did_update); return did_update; } @@ -1221,98 +1165,3 @@ F32 LLSurface::getWaterHeight() const } } - -bool LLSurface::generateWaterTexture(const F32 x, const F32 y, - const F32 width, const F32 height) -{ - LL_PROFILE_ZONE_SCOPED - if (!getWaterTexture()) - { - return false; - } - - S32 tex_width = mWaterTexturep->getWidth(); - S32 tex_height = mWaterTexturep->getHeight(); - S32 tex_comps = mWaterTexturep->getComponents(); - S32 tex_stride = tex_width * tex_comps; - LLPointer raw = new LLImageRaw(tex_width, tex_height, tex_comps); - U8 *rawp = raw->getData(); - - F32 scale = 256.f * getMetersPerGrid() / (F32)tex_width; - F32 scale_inv = 1.f / scale; - - S32 x_begin, y_begin, x_end, y_end; - - x_begin = ll_round(x * scale_inv); - y_begin = ll_round(y * scale_inv); - x_end = ll_round((x + width) * scale_inv); - y_end = ll_round((y + width) * scale_inv); - - if (x_end > tex_width) - { - x_end = tex_width; - } - if (y_end > tex_width) - { - y_end = tex_width; - } - - // OK, for now, just have the composition value equal the height at the point. - LLVector3 location; - LLColor4U coloru; - - const F32 WATER_HEIGHT = getWaterHeight(); - - S32 i, j, offset; - for (j = y_begin; j < y_end; j++) - { - for (i = x_begin; i < x_end; i++) - { - //F32 nv[2]; - //nv[0] = i/256.f; - //nv[1] = j/256.f; - // const S32 modulation = noise2(nv)*40; - offset = j*tex_stride + i*tex_comps; - location.mV[VX] = i*scale; - location.mV[VY] = j*scale; - - // Sample multiple points - const F32 height = resolveHeightRegion(location); - - if (height > WATER_HEIGHT) - { - // Above water... - coloru = MAX_WATER_COLOR; - coloru.mV[3] = ABOVE_WATERLINE_ALPHA; - *(rawp + offset++) = coloru.mV[0]; - *(rawp + offset++) = coloru.mV[1]; - *(rawp + offset++) = coloru.mV[2]; - *(rawp + offset++) = coloru.mV[3]; - } - else - { - // Want non-linear curve for transparency gradient - coloru = MAX_WATER_COLOR; - const F32 frac = 1.f - 2.f/(2.f - (height - WATER_HEIGHT)); - S32 alpha = 64 + ll_round((255-64)*frac); - - alpha = llmin(ll_round((F32)MAX_WATER_COLOR.mV[3]), alpha); - alpha = llmax(64, alpha); - - coloru.mV[3] = alpha; - *(rawp + offset++) = coloru.mV[0]; - *(rawp + offset++) = coloru.mV[1]; - *(rawp + offset++) = coloru.mV[2]; - *(rawp + offset++) = coloru.mV[3]; - } - } - } - - if (!mWaterTexturep->hasGLTexture()) - { - mWaterTexturep->createGLTexture(0, raw); - } - - mWaterTexturep->setSubImage(raw, x_begin, y_begin, x_end - x_begin, y_end - y_begin); - return true; -} diff --git a/indra/newview/llsurface.h b/indra/newview/llsurface.h index 324296a4d3..68295225b6 100644 --- a/indra/newview/llsurface.h +++ b/indra/newview/llsurface.h @@ -128,7 +128,7 @@ public: F32 getWaterHeight() const; LLViewerTexture *getSTexture(); - LLViewerTexture *getWaterTexture(); + bool hasZData() const { return mHasZData; } void dirtyAllPatches(); // Use this to dirty all patches when changing terrain parameters @@ -171,19 +171,11 @@ public: protected: void createSTexture(); - void createWaterTexture(); void initTextures(); - void initWater(); - void createPatchData(); // Allocates memory for patches. void destroyPatchData(); // Deallocates memory for patches. - bool generateWaterTexture(const F32 x, const F32 y, - const F32 width, const F32 height); // Generate texture from composition values. - - //F32 updateTexture(LLSurfacePatch *ppatch); - LLSurfacePatch *getPatch(const S32 x, const S32 y) const; protected: @@ -201,7 +193,6 @@ protected: // The textures should never be directly initialized - use the setter methods! LLPointer mSTexturep; // Texture for surface - LLPointer mWaterTexturep; // Water texture LLPointer mWaterObjp; diff --git a/indra/newview/llsurfacepatch.cpp b/indra/newview/llsurfacepatch.cpp index 042d770550..2a21170b07 100644 --- a/indra/newview/llsurfacepatch.cpp +++ b/indra/newview/llsurfacepatch.cpp @@ -906,15 +906,8 @@ void LLSurfacePatch::updateGL() updateCompositionStats(); F32 tex_patch_size = meters_per_grid*grids_per_patch_edge; - if (comp->generateMinimapTileLand((F32)origin_region[VX], (F32)origin_region[VY], - tex_patch_size, tex_patch_size)) - { - mSTexUpdate = false; - // Also generate the water texture - mSurfacep->generateWaterTexture((F32)origin_region.mdV[VX], (F32)origin_region.mdV[VY], - tex_patch_size, tex_patch_size); - } + mSTexUpdate = false; } void LLSurfacePatch::dirtyZ() diff --git a/indra/newview/lltextureview.cpp b/indra/newview/lltextureview.cpp index b51bcc5601..9d7319d5b8 100644 --- a/indra/newview/lltextureview.cpp +++ b/indra/newview/lltextureview.cpp @@ -461,7 +461,7 @@ public: : texture_view("texture_view") { S32 line_height = LLFontGL::getFontMonospace()->getLineHeight(); - changeDefault(rect, LLRect(0,0,100,line_height * 4)); + changeDefault(rect, LLRect(0,0,0,line_height * 7)); } }; @@ -492,19 +492,51 @@ void LLGLTexMemBar::draw() U32 total_objects = gObjectList.getNumObjects(); F32 x_right = 0.0; + U32 image_count = gTextureList.getNumImages(); + U32 raw_image_count = 0; + U64 raw_image_bytes = 0; + + U32 saved_raw_image_count = 0; + U64 saved_raw_image_bytes = 0; + + U32 aux_raw_image_count = 0; + U64 aux_raw_image_bytes = 0; + + for (auto& image : gTextureList) + { + const LLImageRaw* raw_image = image->getRawImage(); + + if (raw_image) + { + raw_image_count++; + raw_image_bytes += raw_image->getDataSize(); + } + + raw_image = image->getSavedRawImage(); + if (raw_image) + { + saved_raw_image_count++; + saved_raw_image_bytes += raw_image->getDataSize(); + } + + raw_image = image->getAuxRawImage(); + if (raw_image) + { + aux_raw_image_count++; + aux_raw_image_bytes += raw_image->getDataSize(); + } + } + + F64 raw_image_bytes_MB = raw_image_bytes / (1024.0 * 1024.0); + F64 saved_raw_image_bytes_MB = saved_raw_image_bytes / (1024.0 * 1024.0); + F64 aux_raw_image_bytes_MB = aux_raw_image_bytes / (1024.0 * 1024.0); + //---------------------------------------------------------------------------- LLGLSUIDefault gls_ui; LLColor4 text_color(1.f, 1.f, 1.f, 0.75f); LLColor4 color; - // Gray background using completely magic numbers - gGL.color4f(0.f, 0.f, 0.f, 0.25f); - // const LLRect & rect(getRect()); - // gl_rect_2d(-4, v_offset, rect.mRight - rect.mLeft + 2, v_offset + line_height*4); - std::string text = ""; - LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, v_offset + line_height*6, - text_color, LLFontGL::LEFT, LLFontGL::TOP); LLTrace::Recording& recording = LLViewerStats::instance().getRecording(); @@ -525,6 +557,10 @@ void LLGLTexMemBar::draw() U32 texFetchLatMed = U32(recording.getMean(LLTextureFetch::sTexFetchLatency).value() * 1000.0f); U32 texFetchLatMax = U32(recording.getMax(LLTextureFetch::sTexFetchLatency).value() * 1000.0f); + // draw a background above first line.... no idea where the rest of the background comes from for the below text + gGL.color4f(0.f, 0.f, 0.f, 0.25f); + gl_rect_2d(-10, getRect().getHeight() + line_height + 1, getRect().getWidth()+2, getRect().getHeight()+2); + text = llformat("Est. Free: %d MB Sys Free: %d MB FBO: %d MB Bias: %.2f Cache: %.1f/%.1f MB", (S32)LLViewerTexture::sFreeVRAMMegabytes, LLMemory::getAvailableMemKB()/1024, @@ -532,11 +568,15 @@ void LLGLTexMemBar::draw() discard_bias, cache_usage, cache_max_usage); - //, cache_entries, cache_max_entries - - LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, v_offset + line_height*6, + LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, v_offset + line_height*7, text_color, LLFontGL::LEFT, LLFontGL::TOP); + text = llformat("Images: %d Raw: %d (%.2f MB) Saved: %d (%.2f MB) Aux: %d (%.2f MB)", image_count, raw_image_count, raw_image_bytes_MB, + saved_raw_image_count, saved_raw_image_bytes_MB, + aux_raw_image_count, aux_raw_image_bytes_MB); + LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, v_offset + line_height * 6, + text_color, LLFontGL::LEFT, LLFontGL::TOP); + U32 cache_read(0U), cache_write(0U), res_wait(0U); LLAppViewer::getTextureFetch()->getStateStats(&cache_read, &cache_write, &res_wait); @@ -549,7 +589,6 @@ void LLGLTexMemBar::draw() cache_read, cache_write, res_wait); - LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, v_offset + line_height*5, text_color, LLFontGL::LEFT, LLFontGL::TOP); @@ -789,7 +828,7 @@ void LLTextureView::draw() LL_INFOS() << "ID\tMEM\tBOOST\tPRI\tWIDTH\tHEIGHT\tDISCARD" << LL_ENDL; } - for (LLViewerTextureList::image_priority_list_t::iterator iter = gTextureList.mImageList.begin(); + for (LLViewerTextureList::image_list_t::iterator iter = gTextureList.mImageList.begin(); iter != gTextureList.mImageList.end(); ) { LLPointer imagep = *iter++; diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 23931ecf03..f62d929e9a 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -1253,41 +1253,46 @@ void LLViewerMedia::getOpenIDCookieCoro(std::string url) hostEnd = authority.size(); } - LLViewerMedia* inst = getInstance(); if (url.length()) { - LLMediaCtrl* media_instance = LLFloaterReg::getInstance("destinations")->getChild("destination_guide_contents"); - if (media_instance) - { - std::string cookie_host = authority.substr(hostStart, hostEnd - hostStart); - std::string cookie_name = ""; - std::string cookie_value = ""; - std::string cookie_path = ""; - bool httponly = true; - bool secure = true; - if (inst->parseRawCookie(inst->mOpenIDCookie, cookie_name, cookie_value, cookie_path, httponly, secure) && - media_instance->getMediaPlugin()) + LLAppViewer::instance()->postToMainCoro([=]() { - // MAINT-5711 - inexplicably, the CEF setCookie function will no longer set the cookie if the - // url and domain are not the same. This used to be my.sl.com and id.sl.com respectively and worked. - // For now, we use the URL for the OpenID POST request since it will have the same authority - // as the domain field. - // (Feels like there must be a less dirty way to construct a URL from component LLURL parts) - // MAINT-6392 - Rider: Do not change, however, the original URI requested, since it is used further - // down. - std::string cefUrl(std::string(inst->mOpenIDURL.mURI) + "://" + std::string(inst->mOpenIDURL.mAuthority)); + LLMediaCtrl* media_instance = LLFloaterReg::getInstance("destinations")->getChild("destination_guide_contents"); + if (media_instance) + { + LLViewerMedia* inst = getInstance(); + std::string cookie_host = authority.substr(hostStart, hostEnd - hostStart); + std::string cookie_name = ""; + std::string cookie_value = ""; + std::string cookie_path = ""; + bool httponly = true; + bool secure = true; + if (inst->parseRawCookie(inst->mOpenIDCookie, cookie_name, cookie_value, cookie_path, httponly, secure) && + media_instance->getMediaPlugin()) + { + // MAINT-5711 - inexplicably, the CEF setCookie function will no longer set the cookie if the + // url and domain are not the same. This used to be my.sl.com and id.sl.com respectively and worked. + // For now, we use the URL for the OpenID POST request since it will have the same authority + // as the domain field. + // (Feels like there must be a less dirty way to construct a URL from component LLURL parts) + // MAINT-6392 - Rider: Do not change, however, the original URI requested, since it is used further + // down. + std::string cefUrl(std::string(inst->mOpenIDURL.mURI) + "://" + std::string(inst->mOpenIDURL.mAuthority)); - media_instance->getMediaPlugin()->setCookie(cefUrl, cookie_name, cookie_value, cookie_host, - cookie_path, httponly, secure); + media_instance->getMediaPlugin()->setCookie(cefUrl, cookie_name, cookie_value, cookie_host, + cookie_path, httponly, secure); - // Now that we have parsed the raw cookie, we must store it so that each new media instance - // can also get a copy and faciliate logging into internal SL sites. - media_instance->getMediaPlugin()->storeOpenIDCookie(cefUrl, cookie_name, cookie_value, - cookie_host, cookie_path, httponly, secure); - } - } + // Now that we have parsed the raw cookie, we must store it so that each new media instance + // can also get a copy and faciliate logging into internal SL sites. + media_instance->getMediaPlugin()->storeOpenIDCookie(cefUrl, cookie_name, cookie_value, + cookie_host, cookie_path, httponly, secure); + } + } + }); } + LLViewerMedia* inst = getInstance(); + // Note: Rider: MAINT-6392 - Some viewer code requires access to the my.sl.com openid cookie for such // actions as posting snapshots to the feed. This is handled through HTTPCore rather than CEF and so // we must learn to SHARE the cookies. diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 8af0057c88..232b020d3d 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -3676,7 +3676,9 @@ bool LLViewerObject::updateLOD() bool LLViewerObject::updateGeometry(LLDrawable *drawable) { - return false; + // return true means "update complete", return false means "try again next frame" + // default should be return true + return true; } void LLViewerObject::updateGL() diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 19a1990665..39244c8246 100755 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -1269,8 +1269,12 @@ U32 LLViewerRegion::getNumOfVisibleGroups() const return mImpl ? static_cast(mImpl->mVisibleGroups.size()) : 0; } -void LLViewerRegion::updateReflectionProbes() +void LLViewerRegion::updateReflectionProbes(bool full_update) { + if (!full_update && mReflectionMaps.empty()) + { + return; + } LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY; const F32 probe_spacing = 32.f; const F32 probe_radius = sqrtf((probe_spacing * 0.5f) * (probe_spacing * 0.5f) * 3.f); diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h index 68247dc18e..d0ec1fe877 100644 --- a/indra/newview/llviewerregion.h +++ b/indra/newview/llviewerregion.h @@ -428,7 +428,7 @@ public: static bool isNewObjectCreationThrottleDisabled() {return sNewObjectCreationThrottle < 0;} // rebuild reflection probe list - void updateReflectionProbes(); + void updateReflectionProbes(bool full_update); private: void addToVOCacheTree(LLVOCacheEntry* entry); diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index c716eb4e86..b2ed86707c 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -414,8 +414,6 @@ void LLViewerTextureManager::init() } } imagep->createGLTexture(0, image_raw); - //cache the raw image - imagep->setCachedRawImage(0, image_raw); image_raw = NULL; #else LLViewerFetchedTexture::sDefaultImagep = LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT, true, LLGLTexture::BOOST_UI); @@ -728,9 +726,6 @@ bool LLViewerTexture::bindDefaultImage(S32 stage) } stop_glerror(); - //check if there is cached raw image and switch to it if possible - switchToCachedImage(); - LLTexturePipelineTester* tester = (LLTexturePipelineTester*)LLMetricPerformanceTesterBasic::getTester(sTesterName); if (tester) { @@ -931,18 +926,6 @@ void LLViewerTexture::reorganizeVolumeList() } } -//virtual -void LLViewerTexture::switchToCachedImage() -{ - //nothing here. -} - -//virtual -void LLViewerTexture::setCachedRawImage(S32 discard_level, LLImageRaw* imageraw) -{ - //nothing here. -} - bool LLViewerTexture::isLargeImage() { return (S32)mTexelsPerImage > LLViewerTexture::sMinLargeImageSize; @@ -1077,10 +1060,6 @@ void LLViewerFetchedTexture::init(bool firstinit) mIsFetched = false; mInFastCacheList = false; - mCachedRawImage = NULL; - mCachedRawDiscardLevel = -1; - mCachedRawImageReady = false; - mSavedRawImage = NULL; mForceToSaveRawImage = false; mSaveRawImage = false; @@ -1138,9 +1117,6 @@ void LLViewerFetchedTexture::cleanup() // Clean up image data destroyRawImage(); - mCachedRawImage = NULL; - mCachedRawDiscardLevel = -1; - mCachedRawImageReady = false; mSavedRawImage = NULL; mSavedRawDiscardLevel = -1; } @@ -1220,13 +1196,17 @@ void LLViewerFetchedTexture::setForSculpt() { static const S32 MAX_INTERVAL = 8; //frames + forceToSaveRawImage(0, F32_MAX); + + setBoostLevel(llmax((S32)getBoostLevel(), + (S32)LLGLTexture::BOOST_SCULPTED)); + mForSculpt = true; if(isForSculptOnly() && hasGLTexture() && !getBoundRecently()) { destroyGLTexture(); //sculpt image does not need gl texture. mTextureState = ACTIVE; } - checkCachedRawSculptImage(); setMaxVirtualSizeResetInterval(MAX_INTERVAL); } @@ -1339,10 +1319,6 @@ void LLViewerFetchedTexture::addToCreateTexture() } } - //discard the cached raw image and the saved raw image - mCachedRawImageReady = false; - mCachedRawDiscardLevel = -1; - mCachedRawImage = NULL; mSavedRawDiscardLevel = -1; mSavedRawImage = NULL; } @@ -2043,13 +2019,6 @@ bool LLViewerFetchedTexture::updateFetch() LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("vftuf - current < min"); make_request = false; } - else if(mCachedRawImage.notNull() // can be empty - && mCachedRawImageReady - && (current_discard < 0 || current_discard > mCachedRawDiscardLevel)) - { - make_request = false; - switchToCachedImage(); //use the cached raw data first - } if (make_request) { @@ -2542,20 +2511,6 @@ bool LLViewerFetchedTexture::doLoadedCallbacks() } } - // - // Do a readback if required, OR start off a texture decode - // - if (need_readback && (getMaxDiscardLevel() > gl_discard)) - { - // Do a readback to get the GL data into the raw image - // We have GL data. - - destroyRawImage(); - reloadRawImage(mLoadedCallbackDesiredDiscardLevel); - llassert(mRawImage.notNull()); - llassert(!mNeedsAux || mAuxRawImage.notNull()); - } - // // Run raw/auxiliary data callbacks // @@ -2663,61 +2618,6 @@ void LLViewerFetchedTexture::forceImmediateUpdate() return; } -LLImageRaw* LLViewerFetchedTexture::reloadRawImage(S8 discard_level) -{ - llassert(mGLTexturep.notNull()); - llassert(discard_level >= 0); - llassert(mComponents > 0); - - if (mRawImage.notNull()) - { - //mRawImage is in use by somebody else, do not delete it. - return NULL; - } - - if(mSavedRawDiscardLevel >= 0 && mSavedRawDiscardLevel <= discard_level) - { - if (mSavedRawDiscardLevel != discard_level - && mBoostLevel != BOOST_ICON - && mBoostLevel != BOOST_THUMBNAIL) - { - mRawImage = new LLImageRaw(getWidth(discard_level), getHeight(discard_level), getComponents()); - mRawImage->copy(getSavedRawImage()); - } - else - { - mRawImage = getSavedRawImage(); - } - mRawDiscardLevel = discard_level; - } - else - { - //force to fetch raw image again if cached raw image is not good enough. - if(mCachedRawDiscardLevel > discard_level) - { - mRawImage = mCachedRawImage; - mRawDiscardLevel = mCachedRawDiscardLevel; - } - else //cached raw image is good enough, copy it. - { - if(mCachedRawDiscardLevel != discard_level) - { - mRawImage = new LLImageRaw(getWidth(discard_level), getHeight(discard_level), getComponents()); - mRawImage->copy(mCachedRawImage); - } - else - { - mRawImage = mCachedRawImage; - } - mRawDiscardLevel = discard_level; - } - } - mIsRawImageValid = true; - sRawCount++; - - return mRawImage; -} - bool LLViewerFetchedTexture::needsToSaveRawImage() { return mForceToSaveRawImage || mSaveRawImage; @@ -2742,7 +2642,6 @@ void LLViewerFetchedTexture::destroyRawImage() { saveRawImage(); } - setCachedRawImage(); } mRawImage = NULL; @@ -2752,151 +2651,6 @@ void LLViewerFetchedTexture::destroyRawImage() } } -//use the mCachedRawImage to (re)generate the gl texture. -//virtual -void LLViewerFetchedTexture::switchToCachedImage() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - if(mCachedRawImage.notNull() && - !mNeedsCreateTexture) // <--- texture creation is pending, don't step on it - { - mRawImage = mCachedRawImage; - - if (getComponents() != mRawImage->getComponents()) - { - // We've changed the number of components, so we need to move any - // objects using this pool to a different pool. - mComponents = mRawImage->getComponents(); - mGLTexturep->setComponents(mComponents); - gTextureList.dirtyImage(this); - } - - mIsRawImageValid = true; - mRawDiscardLevel = mCachedRawDiscardLevel; - - scheduleCreateTexture(); - } -} - -//cache the imageraw forcefully. -//virtual -void LLViewerFetchedTexture::setCachedRawImage(S32 discard_level, LLImageRaw* imageraw) -{ - if(imageraw != mRawImage.get()) - { - if (mBoostLevel == LLGLTexture::BOOST_ICON) - { - S32 expected_width = mKnownDrawWidth > 0 ? mKnownDrawWidth : DEFAULT_ICON_DIMENSIONS; - S32 expected_height = mKnownDrawHeight > 0 ? mKnownDrawHeight : DEFAULT_ICON_DIMENSIONS; - if (mRawImage->getWidth() > expected_width || mRawImage->getHeight() > expected_height) - { - mCachedRawImage = new LLImageRaw(expected_width, expected_height, imageraw->getComponents()); - mCachedRawImage->copyScaled(imageraw); - } - else - { - mCachedRawImage = imageraw; - } - } - else if (mBoostLevel == LLGLTexture::BOOST_THUMBNAIL) - { - S32 expected_width = mKnownDrawWidth > 0 ? mKnownDrawWidth : DEFAULT_THUMBNAIL_DIMENSIONS; - S32 expected_height = mKnownDrawHeight > 0 ? mKnownDrawHeight : DEFAULT_THUMBNAIL_DIMENSIONS; - if (mRawImage->getWidth() > expected_width || mRawImage->getHeight() > expected_height) - { - mCachedRawImage = new LLImageRaw(expected_width, expected_height, imageraw->getComponents()); - mCachedRawImage->copyScaled(imageraw); - } - else - { - mCachedRawImage = imageraw; - } - } - else - { - mCachedRawImage = imageraw; - } - mCachedRawDiscardLevel = discard_level; - mCachedRawImageReady = true; - } -} - -void LLViewerFetchedTexture::setCachedRawImage() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - if(mRawImage == mCachedRawImage) - { - return; - } - if(!mIsRawImageValid) - { - return; - } - - if(mCachedRawImageReady) - { - return; - } - - if(mCachedRawDiscardLevel < 0 || mCachedRawDiscardLevel > mRawDiscardLevel) - { - S32 i = 0; - S32 w = mRawImage->getWidth(); - S32 h = mRawImage->getHeight(); - - S32 max_size = MAX_CACHED_RAW_IMAGE_AREA; - if(LLGLTexture::BOOST_TERRAIN == mBoostLevel) - { - max_size = MAX_CACHED_RAW_TERRAIN_IMAGE_AREA; - } - if(mForSculpt) - { - max_size = MAX_CACHED_RAW_SCULPT_IMAGE_AREA; - mCachedRawImageReady = !mRawDiscardLevel; - } - else - { - mCachedRawImageReady = (!mRawDiscardLevel || ((w * h) >= max_size)); - } - - while(((w >> i) * (h >> i)) > max_size) - { - ++i; - } - - if(i) - { - if(!(w >> i) || !(h >> i)) - { - --i; - } - - { - //make a duplicate in case somebody else is using this raw image - mRawImage = mRawImage->scaled(w >> i, h >> i); - } - } - mCachedRawImage = mRawImage; - mRawDiscardLevel += i; - mCachedRawDiscardLevel = mRawDiscardLevel; - } -} - -void LLViewerFetchedTexture::checkCachedRawSculptImage() -{ - if(mCachedRawImageReady && mCachedRawDiscardLevel > 0) - { - if(getDiscardLevel() != 0) - { - mCachedRawImageReady = false; - } - else if(isForSculptOnly()) - { - resetTextureStats(); //do not update this image any more. - } - } -} - void LLViewerFetchedTexture::saveRawImage() { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; @@ -2936,6 +2690,20 @@ void LLViewerFetchedTexture::saveRawImage() mSavedRawImage = new LLImageRaw(mRawImage->getData(), mRawImage->getWidth(), mRawImage->getHeight(), mRawImage->getComponents()); } } + else if (mBoostLevel == LLGLTexture::BOOST_SCULPTED) + { + S32 expected_width = mKnownDrawWidth > 0 ? mKnownDrawWidth : sMaxSculptRez; + S32 expected_height = mKnownDrawHeight > 0 ? mKnownDrawHeight : sMaxSculptRez; + if (mRawImage->getWidth() > expected_width || mRawImage->getHeight() > expected_height) + { + mSavedRawImage = new LLImageRaw(expected_width, expected_height, mRawImage->getComponents()); + mSavedRawImage->copyScaled(mRawImage); + } + else + { + mSavedRawImage = new LLImageRaw(mRawImage->getData(), mRawImage->getWidth(), mRawImage->getHeight(), mRawImage->getComponents()); + } + } else { mSavedRawImage = new LLImageRaw(mRawImage->getData(), mRawImage->getWidth(), mRawImage->getHeight(), mRawImage->getComponents()); @@ -2981,20 +2749,23 @@ void LLViewerFetchedTexture::forceToSaveRawImage(S32 desired_discard, F32 kept_t { mForceToSaveRawImage = true; mDesiredSavedRawDiscardLevel = desired_discard; + } +} - //copy from the cached raw image if exists. - if(mCachedRawImage.notNull() && mRawImage.isNull() ) +void LLViewerFetchedTexture::readbackRawImage() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + + if (mGLTexturep.notNull() && mGLTexturep->getTexName() != 0 && mRawImage.isNull()) + { + mRawImage = new LLImageRaw(); + if (!mGLTexturep->readBackRaw(-1, mRawImage, false)) { - mRawImage = mCachedRawImage; - mRawDiscardLevel = mCachedRawDiscardLevel; - - saveRawImage(); - - mRawImage = NULL; - mRawDiscardLevel = INVALID_DISCARD_LEVEL; + mRawImage = nullptr; } } } + void LLViewerFetchedTexture::destroySavedRawImage() { if(mLastReferencedSavedRawImageTime < mKeptSavedRawImageTime) @@ -3029,6 +2800,11 @@ LLImageRaw* LLViewerFetchedTexture::getSavedRawImage() return mSavedRawImage; } +const LLImageRaw* LLViewerFetchedTexture::getSavedRawImage() const +{ + return mSavedRawImage; +} + bool LLViewerFetchedTexture::hasSavedRawImage() const { return mSavedRawImage.notNull(); @@ -3205,20 +2981,14 @@ void LLViewerLODTexture::processTextureStats() bool LLViewerLODTexture::scaleDown() { - if(hasGLTexture() && mCachedRawDiscardLevel > getDiscardLevel()) + if (mGLTexturep.isNull()) { - switchToCachedImage(); - - LLTexturePipelineTester* tester = (LLTexturePipelineTester*)LLMetricPerformanceTesterBasic::getTester(sTesterName); - if (tester) - { - tester->setStablizingTime(); - } - - return true; + return false; } - return false; + + return mGLTexturep->scaleDown(mDesiredDiscardLevel); } + //---------------------------------------------------------------------------------------------- //end of LLViewerLODTexture //---------------------------------------------------------------------------------------------- diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h index 9963626ada..b1e0494a30 100644 --- a/indra/newview/llviewertexture.h +++ b/indra/newview/llviewertexture.h @@ -166,8 +166,6 @@ public: S32 getNumVolumes(U32 channel) const; const ll_volume_list_t* getVolumeList(U32 channel) const { return &mVolumeList[channel]; } - - virtual void setCachedRawImage(S32 discard_level, LLImageRaw* imageraw) ; bool isLargeImage() ; void setParcelMedia(LLViewerMediaTexture* media) {mParcelMedia = media;} @@ -185,8 +183,6 @@ private: friend class LLBumpImageList; friend class LLUIImageList; - virtual void switchToCachedImage(); - protected: friend class LLViewerTextureList; LLUUID mID; @@ -371,7 +367,6 @@ public: U32 getFetchPriority() const { return mFetchPriority ;} F32 getDownloadProgress() const {return mDownloadProgress ;} - LLImageRaw* reloadRawImage(S8 discard_level) ; void destroyRawImage(); bool needsToSaveRawImage(); @@ -390,17 +385,20 @@ public: bool isForSculptOnly() const; //raw image management - void checkCachedRawSculptImage() ; LLImageRaw* getRawImage()const { return mRawImage ;} S32 getRawImageLevel() const {return mRawDiscardLevel;} - LLImageRaw* getCachedRawImage() const { return mCachedRawImage ;} - S32 getCachedRawImageLevel() const {return mCachedRawDiscardLevel;} - bool isCachedRawImageReady() const {return mCachedRawImageReady ;} bool isRawImageValid()const { return mIsRawImageValid ; } void forceToSaveRawImage(S32 desired_discard = 0, F32 kept_time = 0.f) ; - /*virtual*/ void setCachedRawImage(S32 discard_level, LLImageRaw* imageraw) override; + + // readback the raw image from OpenGL if mRawImage is not valid + void readbackRawImage(); + void destroySavedRawImage() ; LLImageRaw* getSavedRawImage() ; + S32 getSavedRawImageLevel() const {return mSavedRawDiscardLevel; } + + const LLImageRaw* getSavedRawImage() const; + const LLImageRaw* getAuxRawImage() const { return mAuxRawImage; } bool hasSavedRawImage() const ; F32 getElapsedLastReferencedSavedRawImageTime() const ; bool isFullyLoaded() const; @@ -417,7 +415,6 @@ public: /*virtual*/bool isActiveFetching() override; //is actively in fetching by the fetching pipeline. protected: - /*virtual*/ void switchToCachedImage() override; S32 getCurrentDiscardLevelForFetching() ; void forceToRefetchTexture(S32 desired_discard = 0, F32 kept_time = 60.f); @@ -426,7 +423,6 @@ private: void cleanup() ; void saveRawImage() ; - void setCachedRawImage() ; //for atlas void resetFaceAtlas() ; @@ -498,11 +494,6 @@ protected: F32 mLastReferencedSavedRawImageTime ; F32 mKeptSavedRawImageTime ; - //a small version of the copy of the raw image (<= 64 * 64) - LLPointer mCachedRawImage; - S32 mCachedRawDiscardLevel; - bool mCachedRawImageReady; //the rez of the mCachedRawImage reaches the upper limit. - LLHost mTargetHost; // if invalid, just request from agent's simulator // Timers diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index b90c1868fc..4d8fd8ddd5 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -296,7 +296,7 @@ void LLViewerTextureList::shutdown() // Write out list of currently loaded textures for precaching on startup typedef std::set > image_area_list_t; image_area_list_t image_area_list; - for (image_priority_list_t::iterator iter = mImageList.begin(); + for (image_list_t::iterator iter = mImageList.begin(); iter != mImageList.end(); ++iter) { LLViewerFetchedTexture* image = *iter; @@ -367,7 +367,7 @@ void LLViewerTextureList::dump() { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; LL_INFOS() << "LLViewerTextureList::dump()" << LL_ENDL; - for (image_priority_list_t::iterator it = mImageList.begin(); it != mImageList.end(); ++it) + for (image_list_t::iterator it = mImageList.begin(); it != mImageList.end(); ++it) { LLViewerFetchedTexture* image = *it; @@ -381,15 +381,9 @@ void LLViewerTextureList::dump() } } -void LLViewerTextureList::destroyGL(bool save_state) +void LLViewerTextureList::destroyGL() { - LLImageGL::destroyGL(save_state); -} - -void LLViewerTextureList::restoreGL() -{ - llassert_always(mInitialized) ; - LLImageGL::restoreGL(); + LLImageGL::destroyGL(); } /* Vertical tab container button image IDs @@ -895,7 +889,7 @@ void LLViewerTextureList::clearFetchingRequests() LLAppViewer::getTextureFetch()->deleteAllRequests(); - for (image_priority_list_t::iterator iter = mImageList.begin(); + for (image_list_t::iterator iter = mImageList.begin(); iter != mImageList.end(); ++iter) { LLViewerFetchedTexture* imagep = *iter; @@ -1208,7 +1202,7 @@ void LLViewerTextureList::updateImagesUpdateStats() LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; if (mForceResetTextureStats) { - for (image_priority_list_t::iterator iter = mImageList.begin(); + for (image_list_t::iterator iter = mImageList.begin(); iter != mImageList.end(); ) { LLViewerFetchedTexture* imagep = *iter++; @@ -1228,7 +1222,7 @@ void LLViewerTextureList::decodeAllImages(F32 max_time) // Update texture stats and priorities std::vector > image_list; - for (image_priority_list_t::iterator iter = mImageList.begin(); + for (image_list_t::iterator iter = mImageList.begin(); iter != mImageList.end(); ) { LLViewerFetchedTexture* imagep = *iter++; @@ -1248,7 +1242,7 @@ void LLViewerTextureList::decodeAllImages(F32 max_time) image_list.clear(); // Update fetch (decode) - for (image_priority_list_t::iterator iter = mImageList.begin(); + for (image_list_t::iterator iter = mImageList.begin(); iter != mImageList.end(); ) { LLViewerFetchedTexture* imagep = *iter++; @@ -1275,7 +1269,7 @@ void LLViewerTextureList::decodeAllImages(F32 max_time) } } // Update fetch again - for (image_priority_list_t::iterator iter = mImageList.begin(); + for (image_list_t::iterator iter = mImageList.begin(); iter != mImageList.end(); ) { LLViewerFetchedTexture* imagep = *iter++; diff --git a/indra/newview/llviewertexturelist.h b/indra/newview/llviewertexturelist.h index e4ebb7b0e8..2779ad9f91 100644 --- a/indra/newview/llviewertexturelist.h +++ b/indra/newview/llviewertexturelist.h @@ -33,7 +33,7 @@ #include "llviewertexture.h" #include "llui.h" #include -#include +#include #include "lluiimage.h" const U32 LL_IMAGE_REZ_LOSSLESS_CUTOFF = 128; @@ -115,8 +115,7 @@ public: void init(); void shutdown(); void dump(); - void destroyGL(bool save_state = true); - void restoreGL(); + void destroyGL(); bool isInitialized() const {return mInitialized;} void findTexturesByID(const LLUUID &image_id, std::vector &output); @@ -188,7 +187,7 @@ private: LLViewerTexture::EBoostLevel boost_priority = LLGLTexture::BOOST_NONE, // Get the requested level immediately upon creation. S8 texture_type = LLViewerTexture::FETCHED_TEXTURE, LLGLint internal_format = 0, - LLGLenum primary_format = 0, + LLGLenum primary_format = 0, const LLUUID& force_id = LLUUID::null ); @@ -211,7 +210,7 @@ private: { return getImage(image_id, f_type, true, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, host); } public: - typedef std::set > image_list_t; + typedef std::unordered_set > image_list_t; image_list_t mLoadingStreamList; image_list_t mCreateTextureList; image_list_t mCallbackList; @@ -222,16 +221,19 @@ public: bool mForceResetTextureStats; + // to make "for (auto& imagep : gTextureList)" work + const image_list_t::iterator begin() const { return mImageList.begin(); } + const image_list_t::iterator end() const { return mImageList.end(); } + private: typedef std::map< LLTextureKey, LLPointer > uuid_map_t; uuid_map_t mUUIDMap; LLTextureKey mLastUpdateKey; - typedef std::set < LLPointer > image_priority_list_t; - image_priority_list_t mImageList; + image_list_t mImageList; // simply holds on to LLViewerFetchedTexture references to stop them from being purged too soon - std::set > mImagePreloads; + std::unordered_set > mImagePreloads; bool mInitialized ; LLFrameTimer mForceDecodeTimer; diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index cfa12bf178..ef85d57416 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -1827,10 +1827,8 @@ LLViewerWindow::LLViewerWindow(const Params& p) mToolStored( NULL ), mHideCursorPermanent( false ), mCursorHidden(false), - mIgnoreActivate( false ), mResDirty(false), mStatesDirty(false), - mCurrResolutionIndex(0), mProgressView(NULL) { // gKeyboard is still NULL, so it doesn't do LLWindowListener any good to @@ -2402,7 +2400,7 @@ void LLViewerWindow::shutdownGL() LLSelectMgr::getInstance()->cleanup(); LL_INFOS() << "Stopping GL during shutdown" << LL_ENDL; - stopGL(false); + stopGL(); stop_glerror(); gGL.shutdown(); @@ -5715,7 +5713,7 @@ void LLViewerWindow::dumpState() << LL_ENDL; } -void LLViewerWindow::stopGL(bool save_state) +void LLViewerWindow::stopGL() { //Note: --bao //if not necessary, do not change the order of the function calls in this function. @@ -5761,7 +5759,7 @@ void LLViewerWindow::stopGL(bool save_state) gPostProcess->invalidate(); } - gTextureList.destroyGL(save_state); + gTextureList.destroyGL(); stop_glerror(); gGLManager.mIsDisabled = true; @@ -5778,6 +5776,14 @@ void LLViewerWindow::stopGL(bool save_state) void LLViewerWindow::restoreGL(const std::string& progress_message) { + llassert(false); + // DEPRECATED -- this is left over from when we would completely destroy and restore a GL context + // when switching from windowed to fullscreen. None of this machinery has been exercised in years + // and is unreliable. If we ever *do* have another use case where completely unloading and reloading + // everthing is necessary, requiring a viewer restart for that operation is a fine thing to do. + // -- davep + + //Note: --bao //if not necessary, do not change the order of the function calls in this function. //if change something, make sure it will not break anything. @@ -5790,8 +5796,6 @@ void LLViewerWindow::restoreGL(const std::string& progress_message) initGLDefaults(); LLGLState::restoreGL(); - gTextureList.restoreGL(); - // for future support of non-square pixels, and fonts that are properly stretched //LLFontGL::destroyDefaultFonts(); initFonts(); @@ -5867,122 +5871,6 @@ void LLViewerWindow::checkSettings() } } -void LLViewerWindow::restartDisplay(bool show_progress_bar) -{ - LL_INFOS() << "Restaring GL" << LL_ENDL; - stopGL(); - if (show_progress_bar) - { - restoreGL(LLTrans::getString("ProgressChangingResolution")); - } - else - { - restoreGL(); - } -} - -bool LLViewerWindow::changeDisplaySettings(LLCoordScreen size, bool enable_vsync, bool show_progress_bar) -{ - //bool was_maximized = gSavedSettings.getBOOL("WindowMaximized"); - - //gResizeScreenTexture = true; - - - //U32 fsaa = gSavedSettings.getU32("RenderFSAASamples"); - //U32 old_fsaa = mWindow->getFSAASamples(); - - // if not maximized, use the request size - if (!mWindow->getMaximized()) - { - mWindow->setSize(size); - } - - //if (fsaa == old_fsaa) - { - return true; - } - -/* - - // Close floaters that don't handle settings change - LLFloaterReg::hideInstance("snapshot"); - - bool result_first_try = false; - bool result_second_try = false; - - LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus(); - send_agent_pause(); - LL_INFOS() << "Stopping GL during changeDisplaySettings" << LL_ENDL; - stopGL(); - mIgnoreActivate = true; - LLCoordScreen old_size; - LLCoordScreen old_pos; - mWindow->getSize(&old_size); - - //mWindow->setFSAASamples(fsaa); - - result_first_try = mWindow->switchContext(false, size, disable_vsync); - if (!result_first_try) - { - // try to switch back - //mWindow->setFSAASamples(old_fsaa); - result_second_try = mWindow->switchContext(false, old_size, disable_vsync); - - if (!result_second_try) - { - // we are stuck...try once again with a minimal resolution? - send_agent_resume(); - mIgnoreActivate = false; - return false; - } - } - send_agent_resume(); - - LL_INFOS() << "Restoring GL during resolution change" << LL_ENDL; - if (show_progress_bar) - { - restoreGL(LLTrans::getString("ProgressChangingResolution")); - } - else - { - restoreGL(); - } - - if (!result_first_try) - { - LLSD args; - args["RESX"] = llformat("%d",size.mX); - args["RESY"] = llformat("%d",size.mY); - LLNotificationsUtil::add("ResolutionSwitchFail", args); - size = old_size; // for reshape below - } - - bool success = result_first_try || result_second_try; - - if (success) - { - // maximize window if was maximized, else reposition - if (was_maximized) - { - mWindow->maximize(); - } - else - { - S32 windowX = gSavedSettings.getS32("WindowX"); - S32 windowY = gSavedSettings.getS32("WindowY"); - - mWindow->setPosition(LLCoordScreen ( windowX, windowY ) ); - } - } - - mIgnoreActivate = false; - gFocusMgr.setKeyboardFocus(keyboard_focus); - - return success; - - */ -} - F32 LLViewerWindow::getWorldViewAspectRatio() const { F32 world_aspect = (F32)mWorldViewRectRaw.getWidth() / (F32)mWorldViewRectRaw.getHeight(); diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index 4a6b901b33..ba59ce4141 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -455,9 +455,7 @@ public: // handle shutting down GL and bringing it back up void requestResolutionUpdate(); void checkSettings(); - void restartDisplay(bool show_progress_bar); - bool changeDisplaySettings(LLCoordScreen size, bool enable_vsync, bool show_progress_bar); - bool getIgnoreDestroyWindow() { return mIgnoreActivate; } + F32 getWorldViewAspectRatio() const; const LLVector2& getDisplayScale() const { return mDisplayScale; } void calcDisplayScale(); @@ -471,7 +469,7 @@ private: void switchToolByMask(MASK mask); void destroyWindow(); void drawMouselookInstructions(); - void stopGL(bool save_state = true); + void stopGL(); void restoreGL(const std::string& progress_message = LLStringUtil::null); void initFonts(F32 zoom_factor = 1.f); void schedulePick(LLPickInfo& pick_info); @@ -528,8 +526,6 @@ private: std::string mOverlayTitle; // Used for special titles such as "Second Life - Special E3 2003 Beta" - bool mIgnoreActivate; - std::string mInitAlert; // Window / GL initialization requires an alert LLHandle mWorldViewPlaceholder; // widget that spans the portion of screen dedicated to rendering the 3d world @@ -542,7 +538,6 @@ private: bool mResDirty; bool mStatesDirty; - U32 mCurrResolutionIndex; std::unique_ptr mWindowListener; std::unique_ptr mViewerWindowListener; diff --git a/indra/newview/llvlcomposition.cpp b/indra/newview/llvlcomposition.cpp index ba255f2b24..f5f058a080 100644 --- a/indra/newview/llvlcomposition.cpp +++ b/indra/newview/llvlcomposition.cpp @@ -317,7 +317,7 @@ bool LLTerrainMaterials::makeMaterialsReady(bool boost, bool strict) // static bool LLTerrainMaterials::makeTextureReady(LLPointer& tex, bool boost) { - llassert(tex); + //llassert(tex); ??? maybe ok ??? if (!tex) { return false; } if (tex->getDiscardLevel() < 0) @@ -571,416 +571,6 @@ bool LLVLComposition::generateComposition() return LLTerrainMaterials::generateMaterials(); } -namespace -{ - void prepare_fallback_image(LLImageRaw* raw_image) - { - raw_image->resize(BASE_SIZE, BASE_SIZE, 4); - raw_image->fill(LLColor4U::white); - } - - // Check if the raw image is loaded for this texture at a discard - // level the minimap can use, and if not then try to get it loaded. - bool prepare_raw_image(LLPointer& raw_image, bool emissive, LLViewerFetchedTexture* tex, bool& delete_raw_post) - { - if (!tex) - { - if (!emissive) - { - prepare_fallback_image(raw_image); - } - else - { - llassert(!raw_image); - raw_image = nullptr; - } - return true; - } - if (raw_image) - { - // Callback already initiated - if (raw_image->getDataSize() > 0) - { - // Callback finished - delete_raw_post = true; - return true; - } - else - { - return false; - } - } - - raw_image = new LLImageRaw(); - - S32 ddiscard = 0; - { - S32 min_dim = llmin(tex->getFullWidth(), tex->getFullHeight()); - while (min_dim > BASE_SIZE && ddiscard < MAX_DISCARD_LEVEL) - { - ddiscard++; - min_dim /= 2; - } - } - - struct PendingImage - { - LLImageRaw* mRawImage; - S32 mDesiredDiscard; - LLUUID mTextureId; - PendingImage(LLImageRaw* raw_image, S32 ddiscard, const LLUUID& texture_id) - : mRawImage(raw_image) - , mDesiredDiscard(ddiscard) - , mTextureId(texture_id) - { - mRawImage->ref(); - } - ~PendingImage() - { - mRawImage->unref(); - } - }; - PendingImage* pending_image = new PendingImage(raw_image, ddiscard, tex->getID()); - - loaded_callback_func cb = [](bool success, LLViewerFetchedTexture * src_vi, LLImageRaw * src, LLImageRaw * src_aux, S32 discard_level, bool is_final, void* userdata) { - PendingImage* pending = (PendingImage*)userdata; - // Owning LLVLComposition still exists - - // Assume mRawImage only used by single LLVLComposition for now - const bool in_use_by_composition = pending->mRawImage->getNumRefs() > 1; - llassert(pending->mRawImage->getNumRefs()); - llassert(pending->mRawImage->getNumRefs() <= 2); - const bool needs_data = !pending->mRawImage->getDataSize(); - if (in_use_by_composition && needs_data) - { - if (success && pending->mDesiredDiscard == discard_level) - { - pending->mRawImage->resize(BASE_SIZE, BASE_SIZE, src->getComponents()); - pending->mRawImage->copyScaled(src); - } - else if (is_final) - { - prepare_fallback_image(pending->mRawImage); - } - } - - if (is_final) { delete pending; } - }; - tex->setLoadedCallback(cb, ddiscard, true, false, pending_image, nullptr); - tex->forceToSaveRawImage(ddiscard); - - return false; - } -}; - -bool LLVLComposition::generateMinimapTileLand(const F32 x, const F32 y, - const F32 width, const F32 height) -{ - LL_PROFILE_ZONE_SCOPED - llassert(mSurfacep); - llassert(x >= 0.f); - llassert(y >= 0.f); - - /////////////////////////// - // - // Generate raw data arrays for surface textures - // - // - - // These have already been validated by generateComposition. - U8* st_data[ASSET_COUNT]; - S32 st_data_size[ASSET_COUNT]; // for debugging - - const bool use_textures = getMaterialType() != LLTerrainMaterials::Type::PBR; - if (use_textures) - { - if (!makeTexturesReady(true, true)) { return false; } - } - else - { - if (!makeMaterialsReady(true, true)) { return false; } - } - - for (S32 i = 0; i < ASSET_COUNT; i++) - { - if (mRawImages[i].isNull()) - { - // Read back a raw image for this discard level, if it exists - LLViewerFetchedTexture* tex; - LLViewerFetchedTexture* tex_emissive; // Can be null - bool has_base_color_factor; - bool has_emissive_factor; - bool has_alpha; - LLColor3 base_color_factor; - LLColor3 emissive_factor; - if (use_textures) - { - tex = mDetailTextures[i]; - tex_emissive = nullptr; - has_base_color_factor = false; - has_emissive_factor = false; - has_alpha = false; - llassert(tex); - } - else - { - LLPointer& mat = mDetailRenderMaterials[i]; - tex = mat->mBaseColorTexture; - tex_emissive = mat->mEmissiveTexture; - base_color_factor = LLColor3(mat->mBaseColor); - // *HACK: Treat alpha as black - base_color_factor *= (mat->mBaseColor.mV[VW]); - emissive_factor = mat->mEmissiveColor; - has_base_color_factor = (base_color_factor.mV[VX] != 1.f || - base_color_factor.mV[VY] != 1.f || - base_color_factor.mV[VZ] != 1.f); - has_emissive_factor = (emissive_factor.mV[VX] != 1.f || - emissive_factor.mV[VY] != 1.f || - emissive_factor.mV[VZ] != 1.f); - has_alpha = mat->mAlphaMode != LLGLTFMaterial::ALPHA_MODE_OPAQUE; - } - - if (!tex) { tex = LLViewerFetchedTexture::sWhiteImagep; } - - bool delete_raw_post = false; - bool delete_raw_post_emissive = false; - if (!prepare_raw_image(mRawImagesBaseColor[i], false, tex, delete_raw_post)) { return false; } - if (tex_emissive && !prepare_raw_image(mRawImagesEmissive[i], true, tex_emissive, delete_raw_post_emissive)) { return false; } - // tex_emissive can be null, and then will be ignored - - // In the simplest case, the minimap image is just the base color. - // This will be replaced if we need to do any tinting/compositing. - mRawImages[i] = mRawImagesBaseColor[i]; - - // *TODO: This isn't quite right for PBR: - // 1) It does not convert the color images from SRGB to linear - // before mixing (which will always require copying the image). - // 2) It mixes emissive and base color before mixing terrain - // materials, but it should be the other way around - // Long-term, we should consider a method that is more - // maintainable. Shaders, perhaps? Bake shaders to textures? - LLPointer raw_emissive; - if (tex_emissive) - { - raw_emissive = mRawImagesEmissive[i]; - if (has_emissive_factor || - tex_emissive->getWidth(tex_emissive->getRawImageLevel()) != BASE_SIZE || - tex_emissive->getHeight(tex_emissive->getRawImageLevel()) != BASE_SIZE || - tex_emissive->getComponents() != 4) - { - LLPointer newraw_emissive = new LLImageRaw(BASE_SIZE, BASE_SIZE, 4); - // Copy RGB, leave alpha alone (set to opaque by default) - newraw_emissive->copy(mRawImagesEmissive[i]); - if (has_emissive_factor) - { - newraw_emissive->tint(emissive_factor); - } - raw_emissive = newraw_emissive; - } - } - if (has_base_color_factor || - raw_emissive || - has_alpha || - tex->getWidth(tex->getRawImageLevel()) != BASE_SIZE || - tex->getHeight(tex->getRawImageLevel()) != BASE_SIZE || - tex->getComponents() != 3) - { - LLPointer newraw = new LLImageRaw(BASE_SIZE, BASE_SIZE, 3); - if (has_alpha) - { - // Approximate the water underneath terrain alpha with solid water color - newraw->clear( - MAX_WATER_COLOR.mV[VX], - MAX_WATER_COLOR.mV[VY], - MAX_WATER_COLOR.mV[VZ], - 255); - } - newraw->composite(mRawImagesBaseColor[i]); - if (has_base_color_factor) - { - newraw->tint(base_color_factor); - } - // Apply emissive texture - if (raw_emissive) - { - newraw->addEmissive(raw_emissive); - } - - mRawImages[i] = newraw; // deletes old - } - - if (delete_raw_post) - { - tex->destroyRawImage(); - } - if (delete_raw_post_emissive) - { - tex_emissive->destroyRawImage(); - } - - // Remove intermediary image references - mRawImagesBaseColor[i] = nullptr; - mRawImagesEmissive[i] = nullptr; - } - st_data[i] = mRawImages[i]->getData(); - st_data_size[i] = mRawImages[i]->getDataSize(); - } - - /////////////////////////////////////// - // - // Generate and clamp x/y bounding box. - // - // - - S32 x_begin, y_begin, x_end, y_end; - x_begin = (S32)(x * mScaleInv); - y_begin = (S32)(y * mScaleInv); - x_end = ll_round( (x + width) * mScaleInv ); - y_end = ll_round( (y + width) * mScaleInv ); - - if (x_end > mWidth) - { - llassert(false); - x_end = mWidth; - } - if (y_end > mWidth) - { - llassert(false); - y_end = mWidth; - } - - - /////////////////////////////////////////// - // - // Generate target texture information, stride ratios. - // - // - - LLViewerTexture *texturep; - U32 tex_width, tex_height, tex_comps; - U32 tex_stride; - F32 tex_x_scalef, tex_y_scalef; - S32 tex_x_begin, tex_y_begin, tex_x_end, tex_y_end; - F32 tex_x_ratiof, tex_y_ratiof; - - texturep = mSurfacep->getSTexture(); - tex_width = texturep->getWidth(); - tex_height = texturep->getHeight(); - tex_comps = texturep->getComponents(); - tex_stride = tex_width * tex_comps; - - U32 st_comps = 3; - U32 st_width = BASE_SIZE; - U32 st_height = BASE_SIZE; - - if (tex_comps != st_comps) - { - llassert(false); - return false; - } - - tex_x_scalef = (F32)tex_width / (F32)mWidth; - tex_y_scalef = (F32)tex_height / (F32)mWidth; - tex_x_begin = (S32)((F32)x_begin * tex_x_scalef); - tex_y_begin = (S32)((F32)y_begin * tex_y_scalef); - tex_x_end = (S32)((F32)x_end * tex_x_scalef); - tex_y_end = (S32)((F32)y_end * tex_y_scalef); - - tex_x_ratiof = (F32)mWidth*mScale / (F32)tex_width; - tex_y_ratiof = (F32)mWidth*mScale / (F32)tex_height; - - LLPointer raw = new LLImageRaw(tex_width, tex_height, tex_comps); - U8 *rawp = raw->getData(); - - F32 st_x_stride, st_y_stride; - st_x_stride = ((F32)st_width / (F32)mTexScaleX)*((F32)mWidth / (F32)tex_width); - st_y_stride = ((F32)st_height / (F32)mTexScaleY)*((F32)mWidth / (F32)tex_height); - - llassert(st_x_stride > 0.f); - llassert(st_y_stride > 0.f); - //////////////////////////////// - // - // Iterate through the target texture, striding through the - // subtextures and interpolating appropriately. - // - // - - F32 sti, stj; - S32 st_offset; - sti = (tex_x_begin * st_x_stride) - st_width*(llfloor((tex_x_begin * st_x_stride)/st_width)); - stj = (tex_y_begin * st_y_stride) - st_height*(llfloor((tex_y_begin * st_y_stride)/st_height)); - - st_offset = (llfloor(stj * st_width) + llfloor(sti)) * st_comps; - for (S32 j = tex_y_begin; j < tex_y_end; j++) - { - U32 offset = j * tex_stride + tex_x_begin * tex_comps; - sti = (tex_x_begin * st_x_stride) - st_width*((U32)(tex_x_begin * st_x_stride)/st_width); - for (S32 i = tex_x_begin; i < tex_x_end; i++) - { - S32 tex0, tex1; - F32 composition = getValueScaled(i*tex_x_ratiof, j*tex_y_ratiof); - - tex0 = llfloor( composition ); - tex0 = llclamp(tex0, 0, 3); - composition -= tex0; - tex1 = tex0 + 1; - tex1 = llclamp(tex1, 0, 3); - - st_offset = (lltrunc(sti) + lltrunc(stj)*st_width) * st_comps; - for (U32 k = 0; k < tex_comps; k++) - { - // Linearly interpolate based on composition. - if (st_offset >= st_data_size[tex0] || st_offset >= st_data_size[tex1]) - { - // SJB: This shouldn't be happening, but does... Rounding error? - //LL_WARNS() << "offset 0 [" << tex0 << "] =" << st_offset << " >= size=" << st_data_size[tex0] << LL_ENDL; - //LL_WARNS() << "offset 1 [" << tex1 << "] =" << st_offset << " >= size=" << st_data_size[tex1] << LL_ENDL; - } - else - { - F32 a = *(st_data[tex0] + st_offset); - F32 b = *(st_data[tex1] + st_offset); - rawp[ offset ] = (U8)lltrunc( a + composition * (b - a) ); - } - offset++; - st_offset++; - } - - sti += st_x_stride; - if (sti >= st_width) - { - sti -= st_width; - } - } - - stj += st_y_stride; - if (stj >= st_height) - { - stj -= st_height; - } - } - - if (!texturep->hasGLTexture()) - { - texturep->createGLTexture(0, raw); - } - texturep->setSubImage(raw, tex_x_begin, tex_y_begin, tex_x_end - tex_x_begin, tex_y_end - tex_y_begin); - - // Un-boost detail textures (will get re-boosted if rendering in high detail) - for (S32 i = 0; i < ASSET_COUNT; i++) - { - unboost_minimap_texture(mDetailTextures[i]); - } - - // Un-boost textures for each detail material (will get re-boosted if rendering in high detail) - for (S32 i = 0; i < ASSET_COUNT; i++) - { - unboost_minimap_material(mDetailMaterials[i]); - } - - return true; -} - F32 LLVLComposition::getStartHeight(S32 corner) { return mStartHeight[corner]; diff --git a/indra/newview/llvlcomposition.h b/indra/newview/llvlcomposition.h index 61c35ade28..2637d77183 100644 --- a/indra/newview/llvlcomposition.h +++ b/indra/newview/llvlcomposition.h @@ -114,8 +114,6 @@ public: // Viewer side hack to generate composition values bool generateHeights(const F32 x, const F32 y, const F32 width, const F32 height); bool generateComposition(); - // Generate texture from composition values. - bool generateMinimapTileLand(const F32 x, const F32 y, const F32 width, const F32 height); // Use these as indeces ito the get/setters below that use 'corner' enum ECorner diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index de62256134..7d9a3378f9 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -851,19 +851,9 @@ void LLVOVolume::updateTextureVirtualSize(bool forced) if (mSculptTexture.notNull()) { - mSculptTexture->setBoostLevel(llmax((S32)mSculptTexture->getBoostLevel(), - (S32)LLGLTexture::BOOST_SCULPTED)); mSculptTexture->setForSculpt() ; - if(!mSculptTexture->isCachedRawImageReady()) - { - S32 lod = llmin(mLOD, 3); - F32 lodf = ((F32)(lod + 1.0f)/4.f); - F32 tex_size = lodf * LLViewerTexture::sMaxSculptRez ; - mSculptTexture->addTextureStats(2.f * tex_size * tex_size, false); - } - - S32 texture_discard = mSculptTexture->getCachedRawImageLevel(); //try to match the texture + S32 texture_discard = mSculptTexture->getRawImageLevel(); //try to match the texture S32 current_discard = getVolume() ? getVolume()->getSculptLevel() : -2 ; if (texture_discard >= 0 && //texture has some data available @@ -1159,7 +1149,9 @@ void LLVOVolume::updateSculptTexture() LLUUID id = sculpt_params->getSculptTexture(); if (id.notNull()) { - mSculptTexture = LLViewerTextureManager::getFetchedTexture(id, FTT_DEFAULT, true, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); + mSculptTexture = LLViewerTextureManager::getFetchedTexture(id, FTT_DEFAULT, true, LLGLTexture::BOOST_SCULPTED, LLViewerTexture::LOD_TEXTURE); + mSculptTexture->forceToSaveRawImage(0, F32_MAX); + mSculptTexture->addTextureStats(256.f*256.f); } mSkinInfoUnavaliable = false; @@ -1252,8 +1244,22 @@ void LLVOVolume::sculpt() S8 sculpt_components = 0; const U8* sculpt_data = NULL; - S32 discard_level = mSculptTexture->getCachedRawImageLevel() ; - LLImageRaw* raw_image = mSculptTexture->getCachedRawImage() ; + S32 discard_level = mSculptTexture->getRawImageLevel() ; + LLImageRaw* raw_image = mSculptTexture->getRawImage() ; + + if (!raw_image) + { + raw_image = mSculptTexture->getSavedRawImage(); + S32 discard_level = mSculptTexture->getSavedRawImageLevel(); + } + + if (!raw_image) + { + // last resort, read back from GL + mSculptTexture->readbackRawImage(); + raw_image = mSculptTexture->getRawImage(); + discard_level = mSculptTexture->getRawImageLevel(); + } S32 max_discard = mSculptTexture->getMaxDiscardLevel(); if (discard_level > max_discard) @@ -1310,8 +1316,6 @@ void LLVOVolume::sculpt() if(!raw_image) { - llassert(discard_level < 0) ; - sculpt_width = 0; sculpt_height = 0; sculpt_data = NULL ; diff --git a/indra/newview/llvowater.cpp b/indra/newview/llvowater.cpp index 34040e1aca..2bc849a74f 100644 --- a/indra/newview/llvowater.cpp +++ b/indra/newview/llvowater.cpp @@ -59,7 +59,6 @@ LLVOWater::LLVOWater(const LLUUID &id, mbCanSelect = false; setScale(LLVector3(256.f, 256.f, 0.f)); // Hack for setting scale for bounding boxes/visibility. - mUseTexture = true; mIsEdgePatch = false; } @@ -101,14 +100,7 @@ LLDrawable *LLVOWater::createDrawable(LLPipeline *pipeline) LLDrawPoolWater *pool = (LLDrawPoolWater*) gPipeline.getPool(LLDrawPool::POOL_WATER); - if (mUseTexture) - { - mDrawable->setNumFaces(1, pool, mRegionp->getLand().getWaterTexture()); - } - else - { - mDrawable->setNumFaces(1, pool, LLWorld::getInstance()->getDefaultWaterTexture()); - } + mDrawable->setNumFaces(1, pool, LLWorld::getInstance()->getDefaultWaterTexture()); return mDrawable; } @@ -249,11 +241,6 @@ void setVecZ(LLVector3& v) v.mV[VZ] = 1; } -void LLVOWater::setUseTexture(const bool use_texture) -{ - mUseTexture = use_texture; -} - void LLVOWater::setIsEdgePatch(const bool edge_patch) { mIsEdgePatch = edge_patch; diff --git a/indra/newview/llvowater.h b/indra/newview/llvowater.h index adae86691a..ba3da510c4 100644 --- a/indra/newview/llvowater.h +++ b/indra/newview/llvowater.h @@ -70,13 +70,10 @@ public: /*virtual*/ bool isActive() const; // Whether this object needs to do an idleUpdate. - void setUseTexture(const bool use_texture); void setIsEdgePatch(const bool edge_patch); - bool getUseTexture() const { return mUseTexture; } bool getIsEdgePatch() const { return mIsEdgePatch; } protected: - bool mUseTexture; bool mIsEdgePatch; S32 mRenderType; }; diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp index 2eadea20ef..6470c81aaa 100644 --- a/indra/newview/llworld.cpp +++ b/indra/newview/llworld.cpp @@ -961,7 +961,6 @@ void LLWorld::updateWaterObjects() if (!getRegionFromHandle(region_handle)) { // No region at that area, so make water LLVOWater* waterp = (LLVOWater *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_WATER, gAgent.getRegion()); - waterp->setUseTexture(false); waterp->setPositionGlobal(LLVector3d(x + rwidth/2, y + rwidth/2, 256.f + water_height)); @@ -1015,7 +1014,6 @@ void LLWorld::updateWaterObjects() mEdgeWaterObjects[dir] = (LLVOWater *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_VOID_WATER, gAgent.getRegion()); waterp = mEdgeWaterObjects[dir]; - waterp->setUseTexture(false); waterp->setIsEdgePatch(true); gPipeline.createObject(waterp); } diff --git a/indra/newview/llworldmipmap.cpp b/indra/newview/llworldmipmap.cpp index e226fd4748..d8ea2b884f 100644 --- a/indra/newview/llworldmipmap.cpp +++ b/indra/newview/llworldmipmap.cpp @@ -178,6 +178,7 @@ LLPointer LLWorldMipmap::getObjectsTile(U32 grid_x, U32 } } +//static LLPointer LLWorldMipmap::loadObjectsTile(U32 grid_x, U32 grid_y, S32 level) { // Get the grid coordinates diff --git a/indra/newview/llworldmipmap.h b/indra/newview/llworldmipmap.h index ab98b55b72..907f24d1e7 100644 --- a/indra/newview/llworldmipmap.h +++ b/indra/newview/llworldmipmap.h @@ -74,11 +74,13 @@ public: // Convert world coordinates to mipmap grid coordinates at a given level static void globalToMipmap(F64 global_x, F64 global_y, S32 level, U32* grid_x, U32* grid_y); + // Load the relevant tile from S3 + static LLPointer loadObjectsTile(U32 grid_x, U32 grid_y, S32 level); + private: // Get a handle (key) from grid coordinates U64 convertGridToHandle(U32 grid_x, U32 grid_y) { return to_region_handle(grid_x * REGION_WIDTH_UNITS, grid_y * REGION_WIDTH_UNITS); } - // Load the relevant tile from S3 - LLPointer loadObjectsTile(U32 grid_x, U32 grid_y, S32 level); + // Clear a level from its "missing" tiles void cleanMissedTilesFromLevel(S32 level); diff --git a/scripts/messages/message_template.msg.sha1 b/scripts/messages/message_template.msg.sha1 index 9d5517ab68..efa5f3cf48 100755 --- a/scripts/messages/message_template.msg.sha1 +++ b/scripts/messages/message_template.msg.sha1 @@ -1 +1 @@ -d7915d67467e59287857630bd89bf9529d065199 +d7915d67467e59287857630bd89bf9529d065199 \ No newline at end of file From c2fbd139c10408460d94a525b979420cdcfe021b Mon Sep 17 00:00:00 2001 From: Beq Date: Thu, 27 Jun 2024 13:21:35 +0100 Subject: [PATCH 17/30] realign system ram functions make the system ram function align across all supported platforms. Taken from https://github.com/FirestormViewer/phoenix-firestorm/commit/3b074ba4af5e303125db606dd69eb4282a91f957 + clean up FS specific comment markers and upstream code retention --- indra/llcommon/llmemory.cpp | 42 ++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index 4b7d60d654..b9f9fdae17 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -39,6 +39,7 @@ #elif LL_LINUX # include # include +# include #endif #include "llmemory.h" @@ -85,6 +86,7 @@ void LLMemory::initMaxHeapSizeGB(F32Gigabytes max_heap_size) void LLMemory::updateMemoryInfo() { LL_PROFILE_ZONE_SCOPED + U32Kilobytes avail_phys; #if LL_WINDOWS PROCESS_MEMORY_COUNTERS counters; @@ -95,22 +97,10 @@ void LLMemory::updateMemoryInfo() } sAllocatedMemInKB = U32Kilobytes::convert(U64Bytes(counters.WorkingSetSize)); - sample(sAllocatedMem, sAllocatedMemInKB); sAllocatedPageSizeInKB = U32Kilobytes::convert(U64Bytes(counters.PagefileUsage)); sample(sVirtualMem, sAllocatedPageSizeInKB); - - U32Kilobytes avail_phys, avail_virtual; + U32Kilobytes avail_virtual; LLMemoryInfo::getAvailableMemoryKB(avail_phys, avail_virtual) ; - sMaxPhysicalMemInKB = llmin(avail_phys + sAllocatedMemInKB, sMaxHeapSizeInKB); - - if(sMaxPhysicalMemInKB > sAllocatedMemInKB) - { - sAvailPhysicalMemInKB = sMaxPhysicalMemInKB - sAllocatedMemInKB ; - } - else - { - sAvailPhysicalMemInKB = U32Kilobytes(0); - } #elif defined(LL_DARWIN) task_vm_info info; @@ -147,21 +137,39 @@ void LLMemory::updateMemoryInfo() if (result == KERN_SUCCESS) { // This is what Chrome reports as 'the "Physical Memory Free" value reported by the Memory Monitor in Instruments.' // Note though that inactive pages are not included here and not yet free, but could become so under memory pressure. - sAvailPhysicalMemInKB = U32Bytes(vmstat.free_count * page_size); - sMaxPhysicalMemInKB = LLMemoryInfo::getHardwareMemSize(); - } + avail_phys = U32Bytes(vmstat.free_count * page_size); + sMaxHeapSizeInKB = LLMemoryInfo::getHardwareMemSize(); + } else { LL_WARNS() << "task_info failed" << LL_ENDL; } - +#elif defined(LL_LINUX) + // Use sysinfo() to get the total physical memory. + struct sysinfo info; + sysinfo(&info); + sMaxHeapSizeInKB = U32Kilobytes::convert((U64Bytes)info.totalram); // Total RAM in system + avail_phys = U32Kilobytes::convert((U64Bytes)info.freeram); // Total Free RAM in system + sAllocatedMemInKB = U32Kilobytes::convert(U64Bytes(LLMemory::getCurrentRSS())); // represents the RAM allocated by this process only (in line with the windows implementation) #else //not valid for other systems for now. + LL_WARNS() << "LLMemory::updateMemoryInfo() not implemented for this platform." << LL_ENDL; sAllocatedMemInKB = U64Bytes(LLMemory::getCurrentRSS()); sMaxPhysicalMemInKB = U64Bytes(U32_MAX); sAvailPhysicalMemInKB = U64Bytes(U32_MAX); #endif + sample(sAllocatedMem, sAllocatedMemInKB); + // sMaxPhysicalMem - max this process can use = the lesser of (what we already have + what's available) or MaxHeap + sMaxPhysicalMemInKB = llmin(avail_phys + sAllocatedMemInKB, sMaxHeapSizeInKB); + if(sMaxPhysicalMemInKB > sAllocatedMemInKB) + { + sAvailPhysicalMemInKB = sMaxPhysicalMemInKB - sAllocatedMemInKB ; + } + else + { + sAvailPhysicalMemInKB = U32Kilobytes(0); + } return ; } From 7322623a6fe0e5120c07b720259e3beb325b097e Mon Sep 17 00:00:00 2001 From: Brad Linden Date: Fri, 28 Jun 2024 12:44:41 -0700 Subject: [PATCH 18/30] Fix pre-commit whitespace checks and merge PR secondlife/viewer#1874 --- indra/llcommon/llmemory.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index b9f9fdae17..104c40f0d7 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -86,7 +86,7 @@ void LLMemory::initMaxHeapSizeGB(F32Gigabytes max_heap_size) void LLMemory::updateMemoryInfo() { LL_PROFILE_ZONE_SCOPED - U32Kilobytes avail_phys; + U32Kilobytes avail_phys; #if LL_WINDOWS PROCESS_MEMORY_COUNTERS counters; @@ -99,7 +99,7 @@ void LLMemory::updateMemoryInfo() sAllocatedMemInKB = U32Kilobytes::convert(U64Bytes(counters.WorkingSetSize)); sAllocatedPageSizeInKB = U32Kilobytes::convert(U64Bytes(counters.PagefileUsage)); sample(sVirtualMem, sAllocatedPageSizeInKB); - U32Kilobytes avail_virtual; + U32Kilobytes avail_virtual; LLMemoryInfo::getAvailableMemoryKB(avail_phys, avail_virtual) ; #elif defined(LL_DARWIN) @@ -160,7 +160,7 @@ void LLMemory::updateMemoryInfo() #endif sample(sAllocatedMem, sAllocatedMemInKB); // sMaxPhysicalMem - max this process can use = the lesser of (what we already have + what's available) or MaxHeap - sMaxPhysicalMemInKB = llmin(avail_phys + sAllocatedMemInKB, sMaxHeapSizeInKB); + sMaxPhysicalMemInKB = llmin(avail_phys + sAllocatedMemInKB, sMaxHeapSizeInKB); if(sMaxPhysicalMemInKB > sAllocatedMemInKB) { From c63cfaa15dc6829b50fda3a024295f7c0b022650 Mon Sep 17 00:00:00 2001 From: Brad Linden Date: Fri, 28 Jun 2024 13:00:53 -0700 Subject: [PATCH 19/30] Updated git-blame-ignore-revs --- .git-blame-ignore-revs | 1 + 1 file changed, 1 insertion(+) diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index cb070b0881..0851d20be0 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -1,5 +1,6 @@ # Replace tabs with spaces 1b68f71348ecf3983b76b40d7940da8377f049b7 +33418a77b716e122da9778869cdbabe97c83ff37 # Trim trailing whitespace a0b3021bdcf76859054fda8e30abb3ed47749e83 8444cd9562a6a7b755fcb075864e205122354192 From 1142c2c79b79802c47720b10130bd194b2a8abf1 Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy Date: Mon, 1 Jul 2024 16:43:29 +0300 Subject: [PATCH 20/30] Fix trailing spaces to make pre-commit happy --- indra/llwebrtc/llwebrtc.cpp | 6 +++--- indra/llwebrtc/llwebrtc.h | 4 ++-- indra/llwebrtc/llwebrtc_impl.h | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/indra/llwebrtc/llwebrtc.cpp b/indra/llwebrtc/llwebrtc.cpp index d5bd913315..6dc632aba4 100644 --- a/indra/llwebrtc/llwebrtc.cpp +++ b/indra/llwebrtc/llwebrtc.cpp @@ -458,7 +458,7 @@ void ll_set_device_module_render_device(rtc::scoped_refptrSetPlayoutDevice(webrtc::AudioDeviceModule::kDefaultDevice); } - else + else { device_module->SetPlayoutDevice(device); } @@ -656,7 +656,7 @@ void LLWebRTCImpl::freePeerConnection(LLWebRTCPeerConnectionInterface* peer_conn // Most peer connection (signaling) happens on // the signaling thread. -LLWebRTCPeerConnectionImpl::LLWebRTCPeerConnectionImpl() : +LLWebRTCPeerConnectionImpl::LLWebRTCPeerConnectionImpl() : mWebRTCImpl(nullptr), mPeerConnection(nullptr), mMute(false), @@ -1171,7 +1171,7 @@ void LLWebRTCPeerConnectionImpl::OnSuccess(webrtc::SessionDescriptionInterface * { observer->OnOfferAvailable(mangled_sdp); } - + mPeerConnection->SetLocalDescription(std::unique_ptr( webrtc::CreateSessionDescription(webrtc::SdpType::kOffer, mangled_sdp)), rtc::scoped_refptr(this)); diff --git a/indra/llwebrtc/llwebrtc.h b/indra/llwebrtc/llwebrtc.h index f447ea990a..54eefc8554 100644 --- a/indra/llwebrtc/llwebrtc.h +++ b/indra/llwebrtc/llwebrtc.h @@ -129,7 +129,7 @@ class LLWebRTCDeviceInterface }; virtual void setAudioConfig(AudioConfig config) = 0; - + // instructs webrtc to refresh the device list. virtual void refreshDevices() = 0; @@ -231,7 +231,7 @@ class LLWebRTCSignalingObserver class LLWebRTCPeerConnectionInterface { public: - + struct InitOptions { // equivalent of PeerConnectionInterface::IceServer diff --git a/indra/llwebrtc/llwebrtc_impl.h b/indra/llwebrtc/llwebrtc_impl.h index 6672f8ce90..2fb5525519 100644 --- a/indra/llwebrtc/llwebrtc_impl.h +++ b/indra/llwebrtc/llwebrtc_impl.h @@ -235,7 +235,7 @@ class LLWebRTCImpl : public LLWebRTCDeviceInterface, public webrtc::AudioDeviceS // The factory that allows creation of native webrtc PeerConnections. rtc::scoped_refptr mPeerConnectionFactory; - + rtc::scoped_refptr mAudioProcessingModule; // more native webrtc stuff From b9740dfc6e72d34d135fb9dafe7eed250e4e8b6e Mon Sep 17 00:00:00 2001 From: Ansariel Date: Mon, 1 Jul 2024 11:52:47 +0200 Subject: [PATCH 21/30] Fix loop scope issue and rework some strange-looking loops --- indra/llui/llaccordionctrl.cpp | 8 ++--- indra/llui/llaccordionctrltab.cpp | 6 ++-- indra/llui/llflatlistview.cpp | 49 +++++++++++-------------------- 3 files changed, 22 insertions(+), 41 deletions(-) diff --git a/indra/llui/llaccordionctrl.cpp b/indra/llui/llaccordionctrl.cpp index 4682044d6e..06f7a20add 100644 --- a/indra/llui/llaccordionctrl.cpp +++ b/indra/llui/llaccordionctrl.cpp @@ -379,12 +379,10 @@ void LLAccordionCtrl::initNoTabsWidget(const LLTextBox::Params& tb_params) void LLAccordionCtrl::updateNoTabsHelpTextVisibility() { - bool visible_exists = false; - std::vector::const_iterator it = mAccordionTabs.begin(); - const std::vector::const_iterator it_end = mAccordionTabs.end(); - while (it < it_end) + bool visible_exists{ false }; + for (auto accordion_tab : mAccordionTabs) { - if ((*(it++))->getVisible()) + if (accordion_tab->getVisible()) { visible_exists = true; break; diff --git a/indra/llui/llaccordionctrltab.cpp b/indra/llui/llaccordionctrltab.cpp index 6d58a2545c..ac66525030 100644 --- a/indra/llui/llaccordionctrltab.cpp +++ b/indra/llui/llaccordionctrltab.cpp @@ -602,15 +602,13 @@ void LLAccordionCtrlTab::setSelected(bool is_selected) LLView* LLAccordionCtrlTab::findContainerView() { - child_list_const_iter_t it = getChildList()->begin(), it_end = getChildList()->end(); - while (it != it_end) + for (auto child : *getChildList()) { - LLView* child = *(it++); if (DD_HEADER_NAME != child->getName() && child->getVisible()) return child; } - return NULL; + return nullptr; } void LLAccordionCtrlTab::selectOnFocusReceived() diff --git a/indra/llui/llflatlistview.cpp b/indra/llui/llflatlistview.cpp index 1799968afb..53f39766c6 100644 --- a/indra/llui/llflatlistview.cpp +++ b/indra/llui/llflatlistview.cpp @@ -1250,17 +1250,15 @@ void LLFlatListView::detachItems(std::vector& detached_items) detached_items.clear(); // Go through items and detach valid items, remove them from items panel // and add to detached_items. - pairs_iterator_t iter = mItemPairs.begin(), iter_end = mItemPairs.end(); - while (iter != iter_end) + for (auto item_pair : mItemPairs) { - LLPanel* pItem = (*iter)->first; + LLPanel* pItem = item_pair->first; if (1 == pItem->notify(action)) { - selectItemPair((*iter), false); + selectItemPair(item_pair, false); mItemsPanel->removeChild(pItem); - detached_items.push_back(pItem); + detached_items.emplace_back(pItem); } - iter++; } if (!detached_items.empty()) { @@ -1268,12 +1266,10 @@ void LLFlatListView::detachItems(std::vector& detached_items) if (detached_items.size() == mItemPairs.size()) { // This way will be faster if all items were disconnected - pairs_iterator_t iter = mItemPairs.begin(), iter_end = mItemPairs.end(); - while (iter != iter_end) + for (auto item_pair : mItemPairs) { - (*iter)->first = NULL; - delete *iter; - iter++; + item_pair->first = nullptr; + delete item_pair; } mItemPairs.clear(); // Also set items panel height to zero. @@ -1286,26 +1282,16 @@ void LLFlatListView::detachItems(std::vector& detached_items) } else { - std::vector::const_iterator - detached_iter = detached_items.begin(), - detached_iter_end = detached_items.end(); - while (detached_iter < detached_iter_end) + for (auto detached_item : detached_items) { - LLPanel* pDetachedItem = *detached_iter; - pairs_iterator_t iter = mItemPairs.begin(), iter_end = mItemPairs.end(); - while (iter != iter_end) + auto found_pos = std::find_if(mItemPairs.begin(), mItemPairs.end(), [detached_item](auto item_pair) { return item_pair->first == detached_item; }); + if (found_pos != mItemPairs.end()) { - item_pair_t* item_pair = *iter; - if (item_pair->first == pDetachedItem) - { - mItemPairs.erase(iter); - item_pair->first = NULL; - delete item_pair; - break; - } - iter++; + mItemPairs.erase(found_pos); + auto item_pair = *found_pos; + item_pair->first = nullptr; + delete item_pair; } - detached_iter++; } rearrangeItems(); } @@ -1412,11 +1398,10 @@ void LLFlatListViewEx::filterItems(bool re_sort, bool notify_parent) action.with("match_filter", cur_filter); mHasMatchedItems = false; - bool visibility_changed = false; - pairs_const_iterator_t iter = getItemPairs().begin(), iter_end = getItemPairs().end(); - while (iter != iter_end) + bool visibility_changed{ false }; + for (auto item_pair : getItemPairs()) { - LLPanel* pItem = (*(iter++))->first; + LLPanel* pItem = item_pair->first; visibility_changed |= updateItemVisibility(pItem, action); } From 59cc1802814eff0742c8051b2d9200a1d4a2dc62 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Mon, 1 Jul 2024 11:56:41 +0200 Subject: [PATCH 22/30] Remove include of format library that isn't used and can't be used without C++20 support anyway --- indra/newview/llvoicewebrtc.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/indra/newview/llvoicewebrtc.cpp b/indra/newview/llvoicewebrtc.cpp index ede1542bd1..8049bb7a73 100644 --- a/indra/newview/llvoicewebrtc.cpp +++ b/indra/newview/llvoicewebrtc.cpp @@ -24,7 +24,6 @@ * $/LicenseInfo$ */ #include -#include #include "llvoicewebrtc.h" #include "llsdutil.h" From fcc7d161083547e53b2210e20e850794b8faf4c8 Mon Sep 17 00:00:00 2001 From: Beq Date: Mon, 1 Jul 2024 17:13:15 +0100 Subject: [PATCH 23/30] Fix for various TP where a mirror is present these manifest as crashes in isDynamic, isBox and similar calls that are accessed through a dangling probe. --- indra/newview/llheroprobemanager.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/indra/newview/llheroprobemanager.cpp b/indra/newview/llheroprobemanager.cpp index 66ccdd2b32..cbe1105024 100644 --- a/indra/newview/llheroprobemanager.cpp +++ b/indra/newview/llheroprobemanager.cpp @@ -121,6 +121,7 @@ void LLHeroProbeManager::update() // Find our nearest hero candidate. float last_distance = 99999.f; float camera_center_distance = 99999.f; + mNearestHero = nullptr; for (auto vo : mHeroVOList) { if (vo && !vo->isDead() && vo->mDrawable.notNull() && vo->isReflectionProbe() && vo->getReflectionProbeIsBox()) @@ -194,11 +195,17 @@ void LLHeroProbeManager::update() else { mNearestHero = nullptr; + mDefaultProbe->mViewerObject = nullptr; } mHeroProbeStrength = 1; } + else + { + mNearestHero = nullptr; + mDefaultProbe->mViewerObject = nullptr; } +} void LLHeroProbeManager::renderProbes() { From c7bd4528a7bc295a17a12951389fcc499483f6c5 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 25 Jun 2024 19:18:23 +0300 Subject: [PATCH 24/30] viewer#1131 gltf model upload UI WIP --- indra/newview/CMakeLists.txt | 4 + indra/newview/gltfscenemanager.cpp | 2 + indra/newview/llfloateravatar.cpp | 5 - indra/newview/llfloaterdestinations.cpp | 5 - indra/newview/llfloaterfonttest.cpp | 5 - indra/newview/llfloatergltfasseteditor.cpp | 111 ++++++++++++++ indra/newview/llfloatergltfasseteditor.h | 114 ++++++++++++++ indra/newview/llgltffolderviews.cpp | 143 ++++++++++++++++++ indra/newview/llgltffolderviews.h | 110 ++++++++++++++ indra/newview/llviewerfloaterreg.cpp | 2 + indra/newview/llviewermenu.cpp | 10 ++ .../xui/en/floater_gltf_asset_editor.xml | 21 +++ .../skins/default/xui/en/menu_viewer.xml | 8 + 13 files changed, 525 insertions(+), 15 deletions(-) create mode 100644 indra/newview/llfloatergltfasseteditor.cpp create mode 100644 indra/newview/llfloatergltfasseteditor.h create mode 100644 indra/newview/llgltffolderviews.cpp create mode 100644 indra/newview/llgltffolderviews.h create mode 100644 indra/newview/skins/default/xui/en/floater_gltf_asset_editor.xml diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 3aaeb426da..67bcab86ff 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -219,6 +219,7 @@ set(viewer_SOURCE_FILES llfloaterfonttest.cpp llfloaterforgetuser.cpp llfloatergesture.cpp + llfloatergltfasseteditor.cpp llfloatergodtools.cpp llfloatergotoline.cpp llfloatergridstatus.cpp @@ -313,6 +314,7 @@ set(viewer_SOURCE_FILES llgesturemgr.cpp llgiveinventory.cpp llglsandbox.cpp + llgltffolderviews.cpp llgltfmateriallist.cpp llgltfmaterialpreviewmgr.cpp llgroupactions.cpp @@ -879,6 +881,7 @@ set(viewer_HEADER_FILES llfloaterfonttest.h llfloaterforgetuser.h llfloatergesture.h + llfloatergltfasseteditor.h llfloatergodtools.h llfloatergotoline.h llfloatergridstatus.h @@ -975,6 +978,7 @@ set(viewer_HEADER_FILES llgesturelistener.h llgesturemgr.h llgiveinventory.h + llgltffolderviews.h llgltfmateriallist.h llgltfmaterialpreviewmgr.h llgroupactions.h diff --git a/indra/newview/gltfscenemanager.cpp b/indra/newview/gltfscenemanager.cpp index a0cbe9290c..b161ec8492 100644 --- a/indra/newview/gltfscenemanager.cpp +++ b/indra/newview/gltfscenemanager.cpp @@ -42,6 +42,7 @@ #include "llviewertexturelist.h" #include "llimagej2c.h" #include "llfloaterperms.h" +#include "llfloaterreg.h" #include "llagentbenefits.h" #include "llfilesystem.h" #include "boost/json.hpp" @@ -314,6 +315,7 @@ void GLTFSceneManager::load(const std::string& filename) { mObjects.push_back(obj); } + LLFloaterReg::showInstance("gltf_asset_editor"); } } else diff --git a/indra/newview/llfloateravatar.cpp b/indra/newview/llfloateravatar.cpp index 6a38d7549c..404316275d 100644 --- a/indra/newview/llfloateravatar.cpp +++ b/indra/newview/llfloateravatar.cpp @@ -25,11 +25,6 @@ * $/LicenseInfo$ */ -/** - * Floater that appears when buying an object, giving a preview - * of its contents and their permissions. - */ - #include "llviewerprecompiledheaders.h" #include "llfloateravatar.h" diff --git a/indra/newview/llfloaterdestinations.cpp b/indra/newview/llfloaterdestinations.cpp index 93cf02e835..fad9693e8f 100644 --- a/indra/newview/llfloaterdestinations.cpp +++ b/indra/newview/llfloaterdestinations.cpp @@ -25,11 +25,6 @@ * $/LicenseInfo$ */ -/** - * Floater that appears when buying an object, giving a preview - * of its contents and their permissions. - */ - #include "llviewerprecompiledheaders.h" #include "llfloaterdestinations.h" diff --git a/indra/newview/llfloaterfonttest.cpp b/indra/newview/llfloaterfonttest.cpp index 95d08cb9ce..d39b061d40 100644 --- a/indra/newview/llfloaterfonttest.cpp +++ b/indra/newview/llfloaterfonttest.cpp @@ -25,11 +25,6 @@ * $/LicenseInfo$ */ -/** - * Floater that appears when buying an object, giving a preview - * of its contents and their permissions. - */ - #include "llviewerprecompiledheaders.h" #include "llfloaterfonttest.h" diff --git a/indra/newview/llfloatergltfasseteditor.cpp b/indra/newview/llfloatergltfasseteditor.cpp new file mode 100644 index 0000000000..a2b5f573bb --- /dev/null +++ b/indra/newview/llfloatergltfasseteditor.cpp @@ -0,0 +1,111 @@ +/** + * @file llfloatergltfasseteditor.cpp + * @author Brad Payne + * @brief LLFloaterFontTest class implementation + * + * $LicenseInfo:firstyear=2008&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 "llviewerprecompiledheaders.h" + +#include "llfloatergltfasseteditor.h" + +#include "llfolderviewitem.h" +#include "llgltffolderviews.h" + +bool LLGLTFSort::operator()(const LLGLTFItem* const& a, const LLGLTFItem* const& b) const +{ + // Comparison operator: returns "true" is a comes before b, "false" otherwise + S32 compare = LLStringUtil::compareDict(a->getName(), b->getName()); + return (compare < 0); +} + +/// LLGLTFViewModel + +LLGLTFViewModel::LLGLTFViewModel() + : base_t(new LLGLTFSort(), new LLGLTFFilter()) +{} + +void LLGLTFViewModel::sort(LLFolderViewFolder* folder) +{ + base_t::sort(folder); +} + + /// LLGLTFNode +// LLUICtrlFactory::create(params); +class LLGLTFNode : public LLFolderViewItem +{ +public: + struct Params : public LLInitParam::Block + { + Params(); + }; + ~LLGLTFNode(); +protected: + LLGLTFNode(const Params& p); +}; + +LLGLTFNode::LLGLTFNode(const LLGLTFNode::Params& p) + : LLFolderViewItem(p) +{ +} + +LLGLTFNode::~LLGLTFNode() +{ +} + +LLFloaterGltfAssetEditor::LLFloaterGltfAssetEditor(const LLSD& key) + : LLFloater(key) +{ + setTitle("GLTF Asset Editor (WIP)"); +} + +/// LLFloaterGltfAssetEditor + +LLFloaterGltfAssetEditor::~LLFloaterGltfAssetEditor() +{ +} + +bool LLFloaterGltfAssetEditor::postBuild() +{ + mItemListPanel = getChild("item_list_panel"); + + // Create the root model and view for all conversation sessions + LLGLTFItem* base_item = new LLGLTFItem(mGLTFViewModel); + + LLFolderView::Params p(LLUICtrlFactory::getDefaultParams()); + p.name = getName(); + p.title = getLabel(); + p.rect = LLRect(0, 0, getRect().getWidth(), 0); + p.parent_panel = mItemListPanel; + p.tool_tip = p.name; + p.listener = base_item; + p.view_model = &mGLTFViewModel; + p.root = NULL; + p.use_ellipses = true; + p.options_menu = "menu_gltf.xml"; // *TODO : create this or fix to be optional + mConversationsRoot = LLUICtrlFactory::create(p); + mConversationsRoot->setCallbackRegistrar(&mCommitCallbackRegistrar); + mConversationsRoot->setEnableRegistrar(&mEnableCallbackRegistrar); + + return true; +} diff --git a/indra/newview/llfloatergltfasseteditor.h b/indra/newview/llfloatergltfasseteditor.h new file mode 100644 index 0000000000..30000506ae --- /dev/null +++ b/indra/newview/llfloatergltfasseteditor.h @@ -0,0 +1,114 @@ +/** + * @file llfloatergltfasseteditor.h + * @author Brad Payne + * @brief floater to exercise standard fonts + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLFLOATERGLTFASSETEDITOR_H +#define LL_LLFLOATERGLTFASSETEDITOR_H + +#include "llfloater.h" + +#include "llfolderviewmodel.h" +#include "llgltffolderviews.h" + +class LLGLTFViewModel; +class LLFolderViewFolder; +class LLFolderViewModelItem; + +class LLGLTFSort +{ +public: + LLGLTFSort() { } + bool operator()(const LLGLTFItem* const& a, const LLGLTFItem* const& b) const; +private: +}; + +class LLGLTFFilter : public LLFolderViewFilter +{ +public: + LLGLTFFilter() { mEmpty = ""; } + ~LLGLTFFilter() {} + + bool check(const LLFolderViewModelItem* item) { return true; } + bool checkFolder(const LLFolderViewModelItem* folder) const { return true; } + void setEmptyLookupMessage(const std::string& message) { } + std::string getEmptyLookupMessage(bool is_empty_folder = false) const { return mEmpty; } + bool showAllResults() const { return true; } + std::string::size_type getStringMatchOffset(LLFolderViewModelItem* item) const { return std::string::npos; } + std::string::size_type getFilterStringSize() const { return 0; } + + bool isActive() const { return false; } + bool isModified() const { return false; } + void clearModified() { } + const std::string& getName() const { return mEmpty; } + const std::string& getFilterText() { return mEmpty; } + void setModified(EFilterModified behavior = FILTER_RESTART) { } + + void resetTime(S32 timeout) { } + bool isTimedOut() { return false; } + + bool isDefault() const { return true; } + bool isNotDefault() const { return false; } + void markDefault() { } + void resetDefault() { } + + S32 getCurrentGeneration() const { return 0; } + S32 getFirstSuccessGeneration() const { return 0; } + S32 getFirstRequiredGeneration() const { return 0; } +private: + std::string mEmpty; +}; + +class LLGLTFViewModel + : public LLFolderViewModel +{ +public: + typedef LLFolderViewModel< LLGLTFSort, LLGLTFItem, LLGLTFItem, LLGLTFFilter> base_t; + LLGLTFViewModel(); + + void sort(LLFolderViewFolder* folder); + bool startDrag(std::vector& items) { return false; } + +private: +}; + +class LLFloaterGltfAssetEditor : public LLFloater +{ +public: + LLFloaterGltfAssetEditor(const LLSD& key); + ~LLFloaterGltfAssetEditor(); + + bool postBuild() override; + + LLGLTFViewModel& getRootViewModel() { return mGLTFViewModel; } + +private: + LLGLTFViewModel mGLTFViewModel; + + LLPanel* mItemListPanel = nullptr; + LLFolderView* mConversationsRoot = nullptr; +}; + +#endif LL_LLFLOATERGLTFASSETEDITOR_H diff --git a/indra/newview/llgltffolderviews.cpp b/indra/newview/llgltffolderviews.cpp new file mode 100644 index 0000000000..911b6262ca --- /dev/null +++ b/indra/newview/llgltffolderviews.cpp @@ -0,0 +1,143 @@ +/** + * @file llgltffolderviews.cpp + * @author Andrey Kleshchev + * @brief LLFloaterFontTest class implementation + * + * $LicenseInfo:firstyear=2008&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 "llviewerprecompiledheaders.h" + +#include "llgltffolderviews.h" +#include "llinventoryicon.h" + +/// LLGLTFItem + +LLGLTFItem::LLGLTFItem(std::string display_name, LLFolderViewModelInterface& root_view_model) + : LLFolderViewModelItemCommon(root_view_model) + , mName(display_name) +{ + init(); +} + +LLGLTFItem::LLGLTFItem(LLFolderViewModelInterface& root_view_model) + : LLFolderViewModelItemCommon(root_view_model) +{ + init(); +} + +LLGLTFItem::~LLGLTFItem() +{ + +} + +void LLGLTFItem::init() +{ + pIcon = LLInventoryIcon::getIcon(LLInventoryType::ICONNAME_OBJECT); +} + + +bool LLGLTFItem::filterChildItem(LLFolderViewModelItem* item, LLFolderViewFilter& filter) +{ + S32 filter_generation = filter.getCurrentGeneration(); + + bool continue_filtering = true; + if (item) + { + if (item->getLastFilterGeneration() < filter_generation) + { + // Recursive application of the filter for child items (CHUI-849) + continue_filtering = item->filter(filter); + } + + // Update latest generation to pass filter in parent and propagate up to root + if (item->passedFilter()) + { + LLGLTFItem* view_model = this; + + while (view_model && view_model->mMostFilteredDescendantGeneration < filter_generation) + { + view_model->mMostFilteredDescendantGeneration = filter_generation; + view_model = static_cast(view_model->mParent); + } + } + } + return continue_filtering; +} + +bool LLGLTFItem::filter(LLFolderViewFilter& filter) +{ + + const S32 filter_generation = filter.getCurrentGeneration(); + const S32 must_pass_generation = filter.getFirstRequiredGeneration(); + + if (getLastFilterGeneration() >= must_pass_generation + && getLastFolderFilterGeneration() >= must_pass_generation + && !passedFilter(must_pass_generation)) + { + // failed to pass an earlier filter that was a subset of the current one + // go ahead and flag this item as not pass + setPassedFilter(false, filter_generation); + setPassedFolderFilter(false, filter_generation); + return true; + } + + bool is_folder = true; + const bool passed_filter_folder = is_folder ? filter.checkFolder(this) : true; + setPassedFolderFilter(passed_filter_folder, filter_generation); + + bool continue_filtering = true; + + if (!mChildren.empty() + && (getLastFilterGeneration() < must_pass_generation // haven't checked descendants against minimum required generation to pass + || descendantsPassedFilter(must_pass_generation))) // or at least one descendant has passed the minimum requirement + { + // now query children + for (child_list_t::iterator iter = mChildren.begin(), end_iter = mChildren.end(); iter != end_iter; ++iter) + { + continue_filtering = filterChildItem((*iter), filter); + if (!continue_filtering) + { + break; + } + } + } + + // If we didn't use all the filter time that means we filtered all of our descendants so we can filter ourselves now + if (continue_filtering) + { + // This is where filter check on the item done (CHUI-849) + const bool passed_filter = filter.check(this); + if (passed_filter && mChildren.empty() && is_folder) // Update the latest filter generation for empty folders + { + LLGLTFItem* view_model = this; + while (view_model && view_model->mMostFilteredDescendantGeneration < filter_generation) + { + view_model->mMostFilteredDescendantGeneration = filter_generation; + view_model = static_cast(view_model->mParent); + } + } + setPassedFilter(passed_filter, filter_generation, filter.getStringMatchOffset(this), filter.getFilterStringSize()); + continue_filtering = !filter.isTimedOut(); + } + return continue_filtering; +} diff --git a/indra/newview/llgltffolderviews.h b/indra/newview/llgltffolderviews.h new file mode 100644 index 0000000000..294074fd9f --- /dev/null +++ b/indra/newview/llgltffolderviews.h @@ -0,0 +1,110 @@ +/** + * @file llgltffolderviews.h + * @author Andrey Kleshchev + * @brief floater to exercise standard fonts + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLFLOATERGLTFFOLDERVIEWS_H +#define LL_LLFLOATERGLTFFOLDERVIEWS_H + +#include "llfloater.h" + +#include "llfolderviewmodel.h" + +class LLGLTFItem : public LLFolderViewModelItemCommon +{ +public: + LLGLTFItem(std::string display_name, LLFolderViewModelInterface& root_view_model); + LLGLTFItem(LLFolderViewModelInterface& root_view_model); + virtual ~LLGLTFItem(); + + void init(); + + const std::string& getName() const override { return mName; } + const std::string& getDisplayName() const override { return mName; } + const std::string& getSearchableName() const override { return mName; } + + std::string getSearchableDescription() const override { return std::string(); } + std::string getSearchableCreatorName()const override { return std::string(); } + std::string getSearchableUUIDString() const override { return std::string(); } + + LLPointer getIcon() const override { return pIcon; } + LLPointer getIconOpen() const { return getIcon(); } + LLPointer getIconOverlay() const { return NULL; } + + LLFontGL::StyleFlags getLabelStyle() const override { return LLFontGL::NORMAL; } + std::string getLabelSuffix() const override { return std::string(); } + + void openItem(void) override {} + void closeItem(void) override {} + void selectItem(void) override {} + + void navigateToFolder(bool new_window = false, bool change_mode = false) override {} + + bool isItemWearable() const { return false; } + + bool isItemRenameable() const override { return false; } + bool renameItem(const std::string& new_name) override { return false; } + + bool isItemMovable(void) const override { return false; } // Can be moved to another folder + void move(LLFolderViewModelItem* parent_listener) override {} + + bool isItemRemovable(bool check_worn = true) const override { return false; } + bool removeItem() override { return false; } + void removeBatch(std::vector& batch) override {} + + bool isItemCopyable(bool can_copy_as_link = true) const override { return false; } + bool copyToClipboard() const override { return false; } + bool cutToClipboard() override { return false; } + bool isCutToClipboard() { return false; } + + bool isClipboardPasteable() const override { return false; } + void pasteFromClipboard() override {} + void pasteLinkFromClipboard() override {} + + void buildContextMenu(LLMenuGL& menu, U32 flags) override {}; + + bool potentiallyVisible() override { return true; }; // is the item definitely visible or we haven't made up our minds yet? + + bool hasChildren() const override { return mChildren.size() > 0; } + + bool dragOrDrop( + MASK mask, + bool drop, + EDragAndDropType cargo_type, + void* cargo_data, + std::string& tooltip_msg) override + { + return false; + } + + bool filterChildItem(LLFolderViewModelItem* item, LLFolderViewFilter& filter); + bool filter(LLFolderViewFilter& filter) override; + +private: + LLUIImagePtr pIcon; + std::string mName; +}; + +#endif LL_LLFLOATERGLTFFOLDERVIEWS_H diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index ceda2675d5..36fd1015f6 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -76,6 +76,7 @@ #include "llfloaterfonttest.h" #include "llfloaterforgetuser.h" #include "llfloatergesture.h" +#include "llfloatergltfasseteditor.h" #include "llfloatergodtools.h" #include "llfloatergridstatus.h" #include "llfloatergroups.h" @@ -372,6 +373,7 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("forget_username", "floater_forget_user.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("gestures", "floater_gesture.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("gltf_asset_editor", "floater_gltf_asset_editor.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("god_tools", "floater_god_tools.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("grid_status", "floater_grid_status.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("group_picker", "floater_choose_group.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 9a9a316adf..2687938b35 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -8139,6 +8139,15 @@ class LLAdvancedClickGLTFUpload: public view_listener_t } }; +class LLAdvancedClickGLTFEdit : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + LLFloaterReg::showInstance("gltf_asset_editor"); + return true; + } +}; + class LLAdvancedClickResizeWindow : public view_listener_t { bool handleEvent(const LLSD& userdata) @@ -9794,6 +9803,7 @@ void initialize_menus() view_listener_t::addMenu(new LLAdvancedClickGLTFOpen(), "Advanced.ClickGLTFOpen"); view_listener_t::addMenu(new LLAdvancedClickGLTFSaveAs(), "Advanced.ClickGLTFSaveAs"); view_listener_t::addMenu(new LLAdvancedClickGLTFUpload(), "Advanced.ClickGLTFUpload"); + view_listener_t::addMenu(new LLAdvancedClickGLTFEdit(), "Advanced.ClickGLTFEdit"); view_listener_t::addMenu(new LLAdvancedClickResizeWindow(), "Advanced.ClickResizeWindow"); view_listener_t::addMenu(new LLAdvancedPurgeShaderCache(), "Advanced.ClearShaderCache"); view_listener_t::addMenu(new LLAdvancedRebuildTerrain(), "Advanced.RebuildTerrain"); diff --git a/indra/newview/skins/default/xui/en/floater_gltf_asset_editor.xml b/indra/newview/skins/default/xui/en/floater_gltf_asset_editor.xml new file mode 100644 index 0000000000..9082486d84 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_gltf_asset_editor.xml @@ -0,0 +1,21 @@ + + + + diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index d5d2d00630..347638249b 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -2851,6 +2851,14 @@ function="World.EnvPreset" + + + + Date: Thu, 27 Jun 2024 18:03:30 +0300 Subject: [PATCH 25/30] viewer#1131 gltf model upload UI WIP #2 --- indra/newview/CMakeLists.txt | 6 +- indra/newview/llfloatergltfasseteditor.cpp | 251 ++++++++++++++---- indra/newview/llfloatergltfasseteditor.h | 91 ++----- ...tffolderviews.cpp => llgltffolderitem.cpp} | 51 ++-- ...llgltffolderviews.h => llgltffolderitem.h} | 36 ++- indra/newview/llgltffoldermodel.cpp | 73 +++++ indra/newview/llgltffoldermodel.h | 91 +++++++ indra/newview/llviewerfloaterreg.cpp | 2 +- .../xui/en/floater_gltf_asset_editor.xml | 15 +- 9 files changed, 462 insertions(+), 154 deletions(-) rename indra/newview/{llgltffolderviews.cpp => llgltffolderitem.cpp} (73%) rename indra/newview/{llgltffolderviews.h => llgltffolderitem.h} (80%) create mode 100644 indra/newview/llgltffoldermodel.cpp create mode 100644 indra/newview/llgltffoldermodel.h diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 67bcab86ff..cbcc85cc1c 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -314,7 +314,8 @@ set(viewer_SOURCE_FILES llgesturemgr.cpp llgiveinventory.cpp llglsandbox.cpp - llgltffolderviews.cpp + llgltffolderitem.cpp + llgltffoldermodel.cpp llgltfmateriallist.cpp llgltfmaterialpreviewmgr.cpp llgroupactions.cpp @@ -978,7 +979,8 @@ set(viewer_HEADER_FILES llgesturelistener.h llgesturemgr.h llgiveinventory.h - llgltffolderviews.h + llgltffolderitem.h + llgltffoldermodel.h llgltfmateriallist.h llgltfmaterialpreviewmgr.h llgroupactions.h diff --git a/indra/newview/llfloatergltfasseteditor.cpp b/indra/newview/llfloatergltfasseteditor.cpp index a2b5f573bb..62546c6ed9 100644 --- a/indra/newview/llfloatergltfasseteditor.cpp +++ b/indra/newview/llfloatergltfasseteditor.cpp @@ -1,7 +1,7 @@ /** * @file llfloatergltfasseteditor.cpp - * @author Brad Payne - * @brief LLFloaterFontTest class implementation + * @author Andrii Kleshchev + * @brief LLFloaterGltfAssetEditor class implementation * * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code @@ -29,72 +29,48 @@ #include "llfloatergltfasseteditor.h" -#include "llfolderviewitem.h" -#include "llgltffolderviews.h" +#include "gltf/asset.h" +#include "llcallbacklist.h" +#include "llselectmgr.h" +#include "llviewerobject.h" -bool LLGLTFSort::operator()(const LLGLTFItem* const& a, const LLGLTFItem* const& b) const -{ - // Comparison operator: returns "true" is a comes before b, "false" otherwise - S32 compare = LLStringUtil::compareDict(a->getName(), b->getName()); - return (compare < 0); -} +const LLColor4U DEFAULT_WHITE(255, 255, 255); -/// LLGLTFViewModel +/// LLFloaterGLTFAssetEditor -LLGLTFViewModel::LLGLTFViewModel() - : base_t(new LLGLTFSort(), new LLGLTFFilter()) -{} - -void LLGLTFViewModel::sort(LLFolderViewFolder* folder) -{ - base_t::sort(folder); -} - - /// LLGLTFNode -// LLUICtrlFactory::create(params); -class LLGLTFNode : public LLFolderViewItem -{ -public: - struct Params : public LLInitParam::Block - { - Params(); - }; - ~LLGLTFNode(); -protected: - LLGLTFNode(const Params& p); -}; - -LLGLTFNode::LLGLTFNode(const LLGLTFNode::Params& p) - : LLFolderViewItem(p) -{ -} - -LLGLTFNode::~LLGLTFNode() -{ -} - -LLFloaterGltfAssetEditor::LLFloaterGltfAssetEditor(const LLSD& key) +LLFloaterGLTFAssetEditor::LLFloaterGLTFAssetEditor(const LLSD& key) : LLFloater(key) + , mUIColor(LLUIColorTable::instance().getColor("MenuItemEnabledColor", DEFAULT_WHITE)) { setTitle("GLTF Asset Editor (WIP)"); } -/// LLFloaterGltfAssetEditor - -LLFloaterGltfAssetEditor::~LLFloaterGltfAssetEditor() +LLFloaterGLTFAssetEditor::~LLFloaterGLTFAssetEditor() { + gIdleCallbacks.deleteFunction(idle, this); } -bool LLFloaterGltfAssetEditor::postBuild() +bool LLFloaterGLTFAssetEditor::postBuild() { mItemListPanel = getChild("item_list_panel"); + LLRect scroller_view_rect = mItemListPanel->getRect(); + scroller_view_rect.translate(-scroller_view_rect.mLeft, -scroller_view_rect.mBottom); + LLScrollContainer::Params scroller_params(LLUICtrlFactory::getDefaultParams()); + scroller_params.rect(scroller_view_rect); + scroller_params.name("folder_scroller"); + mScroller = LLUICtrlFactory::create(scroller_params); + mScroller->setFollowsAll(); + + // Insert that scroller into the panel widgets hierarchy + mItemListPanel->addChild(mScroller); + // Create the root model and view for all conversation sessions - LLGLTFItem* base_item = new LLGLTFItem(mGLTFViewModel); + LLGLTFFolderItem* base_item = new LLGLTFFolderItem(mGLTFViewModel); LLFolderView::Params p(LLUICtrlFactory::getDefaultParams()); - p.name = getName(); - p.title = getLabel(); + p.name = "Root"; + p.title = "Root"; p.rect = LLRect(0, 0, getRect().getWidth(), 0); p.parent_panel = mItemListPanel; p.tool_tip = p.name; @@ -103,9 +79,176 @@ bool LLFloaterGltfAssetEditor::postBuild() p.root = NULL; p.use_ellipses = true; p.options_menu = "menu_gltf.xml"; // *TODO : create this or fix to be optional - mConversationsRoot = LLUICtrlFactory::create(p); - mConversationsRoot->setCallbackRegistrar(&mCommitCallbackRegistrar); - mConversationsRoot->setEnableRegistrar(&mEnableCallbackRegistrar); + mFolderRoot = LLUICtrlFactory::create(p); + mFolderRoot->setCallbackRegistrar(&mCommitCallbackRegistrar); + mFolderRoot->setEnableRegistrar(&mEnableCallbackRegistrar); + // Attach root to the scroller + mScroller->addChild(mFolderRoot); + mFolderRoot->setScrollContainer(mScroller); + mFolderRoot->setFollowsAll(); + mFolderRoot->setOpen(true); + mScroller->setVisible(true); + + gIdleCallbacks.addFunction(idle, this); return true; } + +void LLFloaterGLTFAssetEditor::onOpen(const LLSD& key) +{ + loadFromSelection(); +} + +void LLFloaterGLTFAssetEditor::idle(void* user_data) +{ + LLFloaterGLTFAssetEditor* floater = (LLFloaterGLTFAssetEditor*)user_data; + + if (floater->mFolderRoot) + { + floater->mFolderRoot->update(); + } +} + +void LLFloaterGLTFAssetEditor::loadItem(S32 id, const std::string& name, LLGLTFFolderItem::EType type, LLFolderViewFolder* parent) +{ + LLGLTFFolderItem* listener = new LLGLTFFolderItem(id, name, type, mGLTFViewModel); + + LLFolderViewItem::Params params; + params.name(name); + params.creation_date(0); + params.root(mFolderRoot); + params.listener(listener); + params.rect(LLRect()); + params.tool_tip = params.name; + params.font_color = mUIColor; + params.font_highlight_color = mUIColor; + LLFolderViewItem* view = LLUICtrlFactory::create(params); + + view->addToFolder(parent); + view->setVisible(true); +} + +void LLFloaterGLTFAssetEditor::loadFromNode(S32 node_id, LLFolderViewFolder* parent) +{ + if (mAsset->mNodes.size() <= node_id) + { + return; + } + + LL::GLTF::Node& node = mAsset->mNodes[node_id]; + + std::string name = node.mName; + if (node.mName.empty()) + { + name = getString("node_tittle"); + } + else + { + name = node.mName; + } + + LLGLTFFolderItem* listener = new LLGLTFFolderItem(node_id, name, LLGLTFFolderItem::TYPE_NODE, mGLTFViewModel); + + LLFolderViewFolder::Params p; + p.root = mFolderRoot; + p.listener = listener; + p.name = name; + p.tool_tip = name; + p.font_color = mUIColor; + p.font_highlight_color = mUIColor; + LLFolderViewFolder* view = LLUICtrlFactory::create(p); + + view->addToFolder(parent); + view->setVisible(true); + view->setOpen(true); + + for (S32& node_id : node.mChildren) + { + loadFromNode(node_id, view); + } + + if (node.mMesh != LL::GLTF::INVALID_INDEX && mAsset->mMeshes.size() > node.mMesh) + { + std::string name = mAsset->mMeshes[node.mMesh].mName; + if (name.empty()) + { + name = getString("mesh_tittle"); + } + loadItem(node.mMesh, name, LLGLTFFolderItem::TYPE_MESH, view); + } + + if (node.mSkin != LL::GLTF::INVALID_INDEX && mAsset->mSkins.size() > node.mSkin) + { + std::string name = mAsset->mSkins[node.mSkin].mName; + if (name.empty()) + { + name = getString("skin_tittle"); + } + loadItem(node.mSkin, name, LLGLTFFolderItem::TYPE_SKIN, view); + } + + view->setChildrenInited(true); +} + +void LLFloaterGLTFAssetEditor::loadFromSelection() +{ + if (!mFolderRoot || LLSelectMgr::getInstance()->getSelection()->getObjectCount() != 1) + { + return; + } + + LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); + if (!objectp) + { + return; + } + + mAsset = objectp->mGLTFAsset; + if (!mAsset) + { + return; + } + + LLUIColor item_color = LLUIColorTable::instance().getColor("MenuItemEnabledColor", DEFAULT_WHITE); + for (S32 i = 0; i < mAsset->mScenes.size(); i++) + { + LL::GLTF::Scene& scene = mAsset->mScenes[i]; + std::string name = scene.mName; + if (scene.mName.empty()) + { + name = getString("scene_tittle"); + } + else + { + name = scene.mName; + } + + LLGLTFFolderItem* listener = new LLGLTFFolderItem(i, name, LLGLTFFolderItem::TYPE_SCENE, mGLTFViewModel); + + + LLFolderViewFolder::Params p; + p.name = name; + p.root = mFolderRoot; + p.listener = listener; + p.tool_tip = name; + p.font_color = mUIColor; + p.font_highlight_color = mUIColor; + LLFolderViewFolder* view = LLUICtrlFactory::create(p); + + view->addToFolder(mFolderRoot); + view->setVisible(true); + view->setOpen(true); + + for (S32& node_id : scene.mNodes) + { + loadFromNode(node_id, view); + } + view->setChildrenInited(true); + } + + mGLTFViewModel.requestSortAll(); + mFolderRoot->setChildrenInited(true); + mFolderRoot->arrangeAll(); + mFolderRoot->update(); +} + diff --git a/indra/newview/llfloatergltfasseteditor.h b/indra/newview/llfloatergltfasseteditor.h index 30000506ae..49c5aa4ae7 100644 --- a/indra/newview/llfloatergltfasseteditor.h +++ b/indra/newview/llfloatergltfasseteditor.h @@ -1,7 +1,7 @@ /** * @file llfloatergltfasseteditor.h - * @author Brad Payne - * @brief floater to exercise standard fonts + * @author Andrii Kleshchev + * @brief LLFloaterGltfAssetEditor header file * * $LicenseInfo:firstyear=2024&license=viewerlgpl$ * Second Life Viewer Source Code @@ -30,85 +30,40 @@ #include "llfloater.h" -#include "llfolderviewmodel.h" -#include "llgltffolderviews.h" +#include "llgltffoldermodel.h" -class LLGLTFViewModel; -class LLFolderViewFolder; -class LLFolderViewModelItem; +namespace LL +{ + namespace GLTF + { + class Asset; + } +} -class LLGLTFSort +class LLFloaterGLTFAssetEditor : public LLFloater { public: - LLGLTFSort() { } - bool operator()(const LLGLTFItem* const& a, const LLGLTFItem* const& b) const; -private: -}; - -class LLGLTFFilter : public LLFolderViewFilter -{ -public: - LLGLTFFilter() { mEmpty = ""; } - ~LLGLTFFilter() {} - - bool check(const LLFolderViewModelItem* item) { return true; } - bool checkFolder(const LLFolderViewModelItem* folder) const { return true; } - void setEmptyLookupMessage(const std::string& message) { } - std::string getEmptyLookupMessage(bool is_empty_folder = false) const { return mEmpty; } - bool showAllResults() const { return true; } - std::string::size_type getStringMatchOffset(LLFolderViewModelItem* item) const { return std::string::npos; } - std::string::size_type getFilterStringSize() const { return 0; } - - bool isActive() const { return false; } - bool isModified() const { return false; } - void clearModified() { } - const std::string& getName() const { return mEmpty; } - const std::string& getFilterText() { return mEmpty; } - void setModified(EFilterModified behavior = FILTER_RESTART) { } - - void resetTime(S32 timeout) { } - bool isTimedOut() { return false; } - - bool isDefault() const { return true; } - bool isNotDefault() const { return false; } - void markDefault() { } - void resetDefault() { } - - S32 getCurrentGeneration() const { return 0; } - S32 getFirstSuccessGeneration() const { return 0; } - S32 getFirstRequiredGeneration() const { return 0; } -private: - std::string mEmpty; -}; - -class LLGLTFViewModel - : public LLFolderViewModel -{ -public: - typedef LLFolderViewModel< LLGLTFSort, LLGLTFItem, LLGLTFItem, LLGLTFFilter> base_t; - LLGLTFViewModel(); - - void sort(LLFolderViewFolder* folder); - bool startDrag(std::vector& items) { return false; } - -private: -}; - -class LLFloaterGltfAssetEditor : public LLFloater -{ -public: - LLFloaterGltfAssetEditor(const LLSD& key); - ~LLFloaterGltfAssetEditor(); + LLFloaterGLTFAssetEditor(const LLSD& key); + ~LLFloaterGLTFAssetEditor(); bool postBuild() override; + void onOpen(const LLSD& key) override; LLGLTFViewModel& getRootViewModel() { return mGLTFViewModel; } + static void idle(void* user_data); + void loadItem(S32 id, const std::string& name, LLGLTFFolderItem::EType type, LLFolderViewFolder* parent); + void loadFromNode(S32 node, LLFolderViewFolder* parent); + void loadFromSelection(); + private: LLGLTFViewModel mGLTFViewModel; + LLUIColor mUIColor; LLPanel* mItemListPanel = nullptr; - LLFolderView* mConversationsRoot = nullptr; + LLFolderView* mFolderRoot = nullptr; + LLScrollContainer* mScroller = nullptr; + std::shared_ptr mAsset; }; #endif LL_LLFLOATERGLTFASSETEDITOR_H diff --git a/indra/newview/llgltffolderviews.cpp b/indra/newview/llgltffolderitem.cpp similarity index 73% rename from indra/newview/llgltffolderviews.cpp rename to indra/newview/llgltffolderitem.cpp index 911b6262ca..c4fcb4f5ce 100644 --- a/indra/newview/llgltffolderviews.cpp +++ b/indra/newview/llgltffolderitem.cpp @@ -1,7 +1,7 @@ /** - * @file llgltffolderviews.cpp + * @file llgltffolderitem.cpp * @author Andrey Kleshchev - * @brief LLFloaterFontTest class implementation + * @brief LLGLTFFolderItem class implementation * * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code @@ -27,36 +27,58 @@ #include "llviewerprecompiledheaders.h" -#include "llgltffolderviews.h" +#include "llgltffolderitem.h" + #include "llinventoryicon.h" /// LLGLTFItem -LLGLTFItem::LLGLTFItem(std::string display_name, LLFolderViewModelInterface& root_view_model) +LLGLTFFolderItem::LLGLTFFolderItem(S32 id, const std::string &display_name, EType type, LLFolderViewModelInterface& root_view_model) : LLFolderViewModelItemCommon(root_view_model) , mName(display_name) + , mItemType(type) + , mItemId(id) { init(); } -LLGLTFItem::LLGLTFItem(LLFolderViewModelInterface& root_view_model) +LLGLTFFolderItem::LLGLTFFolderItem(LLFolderViewModelInterface& root_view_model) : LLFolderViewModelItemCommon(root_view_model) { init(); } -LLGLTFItem::~LLGLTFItem() +LLGLTFFolderItem::~LLGLTFFolderItem() { } -void LLGLTFItem::init() +void LLGLTFFolderItem::init() { - pIcon = LLInventoryIcon::getIcon(LLInventoryType::ICONNAME_OBJECT); + // using inventory icons as a placeholder. + // Todo: GLTF needs to have own icons + switch (mItemType) + { + case TYPE_SCENE: + pIcon = LLInventoryIcon::getIcon(LLInventoryType::ICONNAME_OBJECT_MULTI); + break; + case TYPE_NODE: + pIcon = LLInventoryIcon::getIcon(LLInventoryType::ICONNAME_OBJECT); + break; + case TYPE_MESH: + pIcon = LLInventoryIcon::getIcon(LLInventoryType::ICONNAME_MESH); + break; + case TYPE_SKIN: + pIcon = LLInventoryIcon::getIcon(LLInventoryType::ICONNAME_BODYPART_SKIN); + break; + default: + pIcon = LLInventoryIcon::getIcon(LLInventoryType::ICONNAME_OBJECT); + break; + } } -bool LLGLTFItem::filterChildItem(LLFolderViewModelItem* item, LLFolderViewFilter& filter) +bool LLGLTFFolderItem::filterChildItem(LLFolderViewModelItem* item, LLFolderViewFilter& filter) { S32 filter_generation = filter.getCurrentGeneration(); @@ -72,21 +94,20 @@ bool LLGLTFItem::filterChildItem(LLFolderViewModelItem* item, LLFolderViewFilter // Update latest generation to pass filter in parent and propagate up to root if (item->passedFilter()) { - LLGLTFItem* view_model = this; + LLGLTFFolderItem* view_model = this; while (view_model && view_model->mMostFilteredDescendantGeneration < filter_generation) { view_model->mMostFilteredDescendantGeneration = filter_generation; - view_model = static_cast(view_model->mParent); + view_model = static_cast(view_model->mParent); } } } return continue_filtering; } -bool LLGLTFItem::filter(LLFolderViewFilter& filter) +bool LLGLTFFolderItem::filter(LLFolderViewFilter& filter) { - const S32 filter_generation = filter.getCurrentGeneration(); const S32 must_pass_generation = filter.getFirstRequiredGeneration(); @@ -129,11 +150,11 @@ bool LLGLTFItem::filter(LLFolderViewFilter& filter) const bool passed_filter = filter.check(this); if (passed_filter && mChildren.empty() && is_folder) // Update the latest filter generation for empty folders { - LLGLTFItem* view_model = this; + LLGLTFFolderItem* view_model = this; while (view_model && view_model->mMostFilteredDescendantGeneration < filter_generation) { view_model->mMostFilteredDescendantGeneration = filter_generation; - view_model = static_cast(view_model->mParent); + view_model = static_cast(view_model->mParent); } } setPassedFilter(passed_filter, filter_generation, filter.getStringMatchOffset(this), filter.getFilterStringSize()); diff --git a/indra/newview/llgltffolderviews.h b/indra/newview/llgltffolderitem.h similarity index 80% rename from indra/newview/llgltffolderviews.h rename to indra/newview/llgltffolderitem.h index 294074fd9f..be6e264368 100644 --- a/indra/newview/llgltffolderviews.h +++ b/indra/newview/llgltffolderitem.h @@ -1,7 +1,7 @@ /** - * @file llgltffolderviews.h + * @file llgltffolderitem.h * @author Andrey Kleshchev - * @brief floater to exercise standard fonts + * @brief LLGLTFFolderItem header file * * $LicenseInfo:firstyear=2024&license=viewerlgpl$ * Second Life Viewer Source Code @@ -25,19 +25,28 @@ * $/LicenseInfo$ */ -#ifndef LL_LLFLOATERGLTFFOLDERVIEWS_H -#define LL_LLFLOATERGLTFFOLDERVIEWS_H +#ifndef LL_LLGLTFFOLDERITEM_H +#define LL_LLGLTFFOLDERITEM_H #include "llfloater.h" #include "llfolderviewmodel.h" -class LLGLTFItem : public LLFolderViewModelItemCommon +class LLGLTFFolderItem : public LLFolderViewModelItemCommon { public: - LLGLTFItem(std::string display_name, LLFolderViewModelInterface& root_view_model); - LLGLTFItem(LLFolderViewModelInterface& root_view_model); - virtual ~LLGLTFItem(); + enum EType + { + TYPE_ROOT, + TYPE_SCENE, + TYPE_NODE, + TYPE_MESH, + TYPE_SKIN, + }; + + LLGLTFFolderItem(S32 id, const std::string &display_name, EType type, LLFolderViewModelInterface& root_view_model); + LLGLTFFolderItem(LLFolderViewModelInterface& root_view_model); + virtual ~LLGLTFFolderItem(); void init(); @@ -102,9 +111,18 @@ public: bool filterChildItem(LLFolderViewModelItem* item, LLFolderViewFilter& filter); bool filter(LLFolderViewFilter& filter) override; + EType getType() const { return mItemType; } + S32 getId() const { return mItemId; } + private: LLUIImagePtr pIcon; std::string mName; + EType mItemType = TYPE_ROOT; + + // mItemId can be an id in a mesh vector, node vector or any other vector. + // mItemId is not nessesarily unique, ex: some nodes can reuse the same + // mesh or skin, so mesh-items can have the same id. + S32 mItemId = -1; }; -#endif LL_LLFLOATERGLTFFOLDERVIEWS_H +#endif LL_LLGLTFFOLDERITEM_H diff --git a/indra/newview/llgltffoldermodel.cpp b/indra/newview/llgltffoldermodel.cpp new file mode 100644 index 0000000000..5f22c8b710 --- /dev/null +++ b/indra/newview/llgltffoldermodel.cpp @@ -0,0 +1,73 @@ +/** + * @file llgltffoldermodel.cpp + * @author Andrey Kleshchev + * @brief gltf model's folder structure related classes + * + * $LicenseInfo:firstyear=2008&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 "llviewerprecompiledheaders.h" + +#include "llgltffoldermodel.h" + +#include "llfolderviewitem.h" + +bool LLGLTFSort::operator()(const LLGLTFFolderItem* const& a, const LLGLTFFolderItem* const& b) const +{ + // Comparison operator: returns "true" is a comes before b, "false" otherwise + S32 compare = LLStringUtil::compareDict(a->getName(), b->getName()); + return (compare < 0); +} + +/// LLGLTFViewModel + +LLGLTFViewModel::LLGLTFViewModel() + : base_t(new LLGLTFSort(), new LLGLTFFilter()) +{} + +void LLGLTFViewModel::sort(LLFolderViewFolder* folder) +{ + base_t::sort(folder); +} + + /// LLGLTFNode +// LLUICtrlFactory::create(params); +class LLGLTFNode : public LLFolderViewItem +{ +public: + struct Params : public LLInitParam::Block + { + Params(); + }; + ~LLGLTFNode(); +protected: + LLGLTFNode(const Params& p); +}; + +LLGLTFNode::LLGLTFNode(const LLGLTFNode::Params& p) + : LLFolderViewItem(p) +{ +} + +LLGLTFNode::~LLGLTFNode() +{ +} diff --git a/indra/newview/llgltffoldermodel.h b/indra/newview/llgltffoldermodel.h new file mode 100644 index 0000000000..26f05d1ecd --- /dev/null +++ b/indra/newview/llgltffoldermodel.h @@ -0,0 +1,91 @@ +/** + * @file llfloatergltfasseteditor.h + * @author Andrey Kleshchev + * @brief gltf model's folder structure related classes + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLGLTFFOLDERMODEL_H +#define LL_LLGLTFFOLDERMODEL_H + +#include "llfolderviewmodel.h" +#include "llgltffolderitem.h" + +class LLGLTFSort +{ +public: + LLGLTFSort() { } + bool operator()(const LLGLTFFolderItem* const& a, const LLGLTFFolderItem* const& b) const; +private: +}; + +class LLGLTFFilter : public LLFolderViewFilter +{ +public: + LLGLTFFilter() { mEmpty = ""; } + ~LLGLTFFilter() {} + + bool check(const LLFolderViewModelItem* item) { return true; } + bool checkFolder(const LLFolderViewModelItem* folder) const { return true; } + void setEmptyLookupMessage(const std::string& message) { } + std::string getEmptyLookupMessage(bool is_empty_folder = false) const { return mEmpty; } + bool showAllResults() const { return true; } + std::string::size_type getStringMatchOffset(LLFolderViewModelItem* item) const { return std::string::npos; } + std::string::size_type getFilterStringSize() const { return 0; } + + bool isActive() const { return false; } + bool isModified() const { return false; } + void clearModified() { } + const std::string& getName() const { return mEmpty; } + const std::string& getFilterText() { return mEmpty; } + void setModified(EFilterModified behavior = FILTER_RESTART) { } + + void resetTime(S32 timeout) { } + bool isTimedOut() { return false; } + + bool isDefault() const { return true; } + bool isNotDefault() const { return false; } + void markDefault() { } + void resetDefault() { } + + S32 getCurrentGeneration() const { return 0; } + S32 getFirstSuccessGeneration() const { return 0; } + S32 getFirstRequiredGeneration() const { return 0; } +private: + std::string mEmpty; +}; + +class LLGLTFViewModel + : public LLFolderViewModel +{ +public: + typedef LLFolderViewModel< LLGLTFSort, LLGLTFFolderItem, LLGLTFFolderItem, LLGLTFFilter> base_t; + LLGLTFViewModel(); + + void sort(LLFolderViewFolder* folder); + bool startDrag(std::vector& items) { return false; } + +private: +}; + +#endif LL_LLGLTFFOLDERMODEL_H diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 36fd1015f6..3e1705b8a1 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -373,7 +373,7 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("forget_username", "floater_forget_user.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("gestures", "floater_gesture.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("gltf_asset_editor", "floater_gltf_asset_editor.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("gltf_asset_editor", "floater_gltf_asset_editor.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("god_tools", "floater_god_tools.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("grid_status", "floater_grid_status.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("group_picker", "floater_choose_group.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); diff --git a/indra/newview/skins/default/xui/en/floater_gltf_asset_editor.xml b/indra/newview/skins/default/xui/en/floater_gltf_asset_editor.xml index 9082486d84..4dc0dffcfd 100644 --- a/indra/newview/skins/default/xui/en/floater_gltf_asset_editor.xml +++ b/indra/newview/skins/default/xui/en/floater_gltf_asset_editor.xml @@ -3,19 +3,24 @@ legacy_header_height="18" can_resize="true" default_tab_group="1" - height="891" + height="400" width="256" - min_height="500" - min_width="256" + min_height="200" + min_width="200" layout="topleft" name="gltf asset editor" title="[OBJECT_NAME]"> + + + + From 279ec534dd999420544b672cf84841b86d1306ae Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 1 Jul 2024 17:10:13 +0300 Subject: [PATCH 26/30] viewer#1131 gltf model upload UI WIP #3 --- indra/newview/llfloatergltfasseteditor.cpp | 269 ++++++++++++++++- indra/newview/llfloatergltfasseteditor.h | 40 ++- indra/newview/llgltffolderitem.h | 2 +- .../xui/en/floater_gltf_asset_editor.xml | 271 +++++++++++++++++- 4 files changed, 567 insertions(+), 15 deletions(-) diff --git a/indra/newview/llfloatergltfasseteditor.cpp b/indra/newview/llfloatergltfasseteditor.cpp index 62546c6ed9..ec9ccc1324 100644 --- a/indra/newview/llfloatergltfasseteditor.cpp +++ b/indra/newview/llfloatergltfasseteditor.cpp @@ -31,7 +31,9 @@ #include "gltf/asset.h" #include "llcallbacklist.h" +#include "llmenubutton.h" #include "llselectmgr.h" +#include "llspinctrl.h" #include "llviewerobject.h" const LLColor4U DEFAULT_WHITE(255, 255, 255); @@ -43,16 +45,69 @@ LLFloaterGLTFAssetEditor::LLFloaterGLTFAssetEditor(const LLSD& key) , mUIColor(LLUIColorTable::instance().getColor("MenuItemEnabledColor", DEFAULT_WHITE)) { setTitle("GLTF Asset Editor (WIP)"); + + mCommitCallbackRegistrar.add("PanelObject.menuDoToSelected", [this](LLUICtrl* ctrl, const LLSD& data) { onMenuDoToSelected(data); }); + mEnableCallbackRegistrar.add("PanelObject.menuEnable", [this](LLUICtrl* ctrl, const LLSD& data) { return onMenuEnableItem(data); }); } LLFloaterGLTFAssetEditor::~LLFloaterGLTFAssetEditor() { gIdleCallbacks.deleteFunction(idle, this); + + if (mScroller) + { + removeChild(mScroller); + delete mScroller; + mScroller = NULL; + } } bool LLFloaterGLTFAssetEditor::postBuild() { - mItemListPanel = getChild("item_list_panel"); + // Position + mMenuClipboardPos = getChild("clipboard_pos_btn"); + mCtrlPosX = getChild("Pos X", true); + mCtrlPosX->setCommitCallback([this](LLUICtrl* ctrl, const LLSD& param) { onCommitTransform(); }); + mCtrlPosY = getChild("Pos Y", true); + mCtrlPosY->setCommitCallback([this](LLUICtrl* ctrl, const LLSD& param) { onCommitTransform(); }); + mCtrlPosZ = getChild("Pos Z", true); + mCtrlPosZ->setCommitCallback([this](LLUICtrl* ctrl, const LLSD& param) { onCommitTransform(); }); + + // Scale + mMenuClipboardScale = getChild("clipboard_size_btn"); + mCtrlScaleX = getChild("Scale X", true); + mCtrlScaleX->setCommitCallback([this](LLUICtrl* ctrl, const LLSD& param) { onCommitTransform(); }); + mCtrlScaleY = getChild("Scale Y", true); + mCtrlScaleY->setCommitCallback([this](LLUICtrl* ctrl, const LLSD& param) { onCommitTransform(); }); + mCtrlScaleZ = getChild("Scale Z", true); + mCtrlScaleZ->setCommitCallback([this](LLUICtrl* ctrl, const LLSD& param) { onCommitTransform(); }); + + // Rotation + mMenuClipboardRot = getChild("clipboard_rot_btn"); + mCtrlRotX = getChild("Rot X", true); + mCtrlRotX->setCommitCallback([this](LLUICtrl* ctrl, const LLSD& param) { onCommitTransform(); }); + mCtrlRotY = getChild("Rot Y", true); + mCtrlRotY->setCommitCallback([this](LLUICtrl* ctrl, const LLSD& param) { onCommitTransform(); }); + mCtrlRotZ = getChild("Rot Z", true); + mCtrlPosZ->setCommitCallback([this](LLUICtrl* ctrl, const LLSD& param) { onCommitTransform(); }); + setTransformsEnabled(false); + // todo: do multiple panels based on selected element. + mTransformsPanel = getChild("transform_panel", true); + mTransformsPanel->setVisible(false); + + mItemListPanel = getChild("item_list_panel", true); + initFolderRoot(); + + return true; +} + +void LLFloaterGLTFAssetEditor::initFolderRoot() +{ + if (mScroller || mFolderRoot) + { + LL_ERRS() << "Folder root already initialized" << LL_ENDL; + return; + } LLRect scroller_view_rect = mItemListPanel->getRect(); scroller_view_rect.translate(-scroller_view_rect.mLeft, -scroller_view_rect.mBottom); @@ -87,11 +142,10 @@ bool LLFloaterGLTFAssetEditor::postBuild() mFolderRoot->setScrollContainer(mScroller); mFolderRoot->setFollowsAll(); mFolderRoot->setOpen(true); + mFolderRoot->setSelectCallback([this](const std::deque& items, bool user_action) { onFolderSelectionChanged(items, user_action); }); mScroller->setVisible(true); gIdleCallbacks.addFunction(idle, this); - - return true; } void LLFloaterGLTFAssetEditor::onOpen(const LLSD& key) @@ -252,3 +306,212 @@ void LLFloaterGLTFAssetEditor::loadFromSelection() mFolderRoot->update(); } +void LLFloaterGLTFAssetEditor::onFolderSelectionChanged(const std::deque& items, bool user_action) +{ + if (items.empty()) + { + setTransformsEnabled(false); + return; + } + + LLFolderViewItem* item = items.front(); + LLGLTFFolderItem* vmi = static_cast(item->getViewModelItem()); + + switch (vmi->getType()) + { + case LLGLTFFolderItem::TYPE_NODE: + { + setTransformsEnabled(true); + loadNodeTransforms(vmi->getItemId()); + break; + } + default: + { + setTransformsEnabled(false); + break; + } + } +} + +void LLFloaterGLTFAssetEditor::setTransformsEnabled(bool val) +{ + mMenuClipboardPos->setEnabled(val); + mCtrlPosX->setEnabled(val); + mCtrlPosY->setEnabled(val); + mCtrlPosZ->setEnabled(val); + mMenuClipboardScale->setEnabled(val); + mCtrlScaleX->setEnabled(val); + mCtrlScaleY->setEnabled(val); + mCtrlScaleZ->setEnabled(val); + mMenuClipboardRot->setEnabled(val); + mCtrlRotX->setEnabled(val); + mCtrlRotY->setEnabled(val); + mCtrlRotZ->setEnabled(val); +} + +void LLFloaterGLTFAssetEditor::loadNodeTransforms(S32 node_id) +{ + if (node_id < 0 || node_id >= mAsset->mNodes.size()) + { + LL_ERRS() << "Node id out of range: " << node_id << LL_ENDL; + return; + } + + LL::GLTF::Node& node = mAsset->mNodes[node_id]; + + mCtrlPosX->set(node.mTranslation[0]); + mCtrlPosY->set(node.mTranslation[1]); + mCtrlPosZ->set(node.mTranslation[2]); + + mCtrlScaleX->set(node.mScale[0]); + mCtrlScaleY->set(node.mScale[1]); + mCtrlScaleZ->set(node.mScale[2]); + + LLQuaternion object_rot = LLQuaternion(node.mRotation[0], node.mRotation[1], node.mRotation[2], node.mRotation[3]); + object_rot.getEulerAngles(&(mLastEulerDegrees.mV[VX]), &(mLastEulerDegrees.mV[VY]), &(mLastEulerDegrees.mV[VZ])); + mLastEulerDegrees *= RAD_TO_DEG; + mLastEulerDegrees.mV[VX] = fmod(ll_round(mLastEulerDegrees.mV[VX], OBJECT_ROTATION_PRECISION) + 360.f, 360.f); + mLastEulerDegrees.mV[VY] = fmod(ll_round(mLastEulerDegrees.mV[VY], OBJECT_ROTATION_PRECISION) + 360.f, 360.f); + mLastEulerDegrees.mV[VZ] = fmod(ll_round(mLastEulerDegrees.mV[VZ], OBJECT_ROTATION_PRECISION) + 360.f, 360.f); + + mCtrlRotX->set(mLastEulerDegrees.mV[VX]); + mCtrlRotY->set(mLastEulerDegrees.mV[VY]); + mCtrlRotZ->set(mLastEulerDegrees.mV[VZ]); +} + +void LLFloaterGLTFAssetEditor::onCommitTransform() +{ + if (!mFolderRoot) + { + LL_ERRS() << "Folder root not initialized" << LL_ENDL; + return; + } + + LLFolderViewItem* item = mFolderRoot->getCurSelectedItem(); + if (!item) + { + LL_ERRS() << "Nothing selected" << LL_ENDL; + return; + } + + LLGLTFFolderItem* vmi = static_cast(item->getViewModelItem()); + + if (!vmi || vmi->getType() != LLGLTFFolderItem::TYPE_NODE) + { + LL_ERRS() << "Only nodes implemented" << LL_ENDL; + return; + } + S32 node_id = vmi->getItemId(); + LL::GLTF::Node& node = mAsset->mNodes[node_id]; + + LL::GLTF::vec3 tr(mCtrlPosX->get(), mCtrlPosY->get(), mCtrlPosZ->get()); + node.setTranslation(tr); + + LL::GLTF::vec3 scale(mCtrlScaleX->get(), mCtrlScaleY->get(), mCtrlScaleZ->get()); + node.setScale(scale); + + LLVector3 new_rot(mCtrlRotX->get(), mCtrlRotY->get(), mCtrlRotZ->get()); + new_rot.mV[VX] = ll_round(new_rot.mV[VX], OBJECT_ROTATION_PRECISION); + new_rot.mV[VY] = ll_round(new_rot.mV[VY], OBJECT_ROTATION_PRECISION); + new_rot.mV[VZ] = ll_round(new_rot.mV[VZ], OBJECT_ROTATION_PRECISION); + + // Note: must compare before conversion to radians, some value can go 'around' 360 + LLVector3 delta = new_rot - mLastEulerDegrees; + + if (delta.magVec() >= 0.0005f) + { + mLastEulerDegrees = new_rot; + new_rot *= DEG_TO_RAD; + + LLQuaternion rotation; + rotation.setQuat(new_rot.mV[VX], new_rot.mV[VY], new_rot.mV[VZ]); + LL::GLTF::quat q; + q[0] = rotation.mQ[VX]; + q[1] = rotation.mQ[VY]; + q[2] = rotation.mQ[VZ]; + q[3] = rotation.mQ[VW]; + + node.setRotation(q); + } + + mAsset->updateTransforms(); +} + +void LLFloaterGLTFAssetEditor::onMenuDoToSelected(const LLSD& userdata) +{ + std::string command = userdata.asString(); + + if (command == "psr_paste") + { + // todo: implement + // onPastePos(); + // onPasteSize(); + // onPasteRot(); + } + else if (command == "pos_paste") + { + // todo: implement + } + else if (command == "size_paste") + { + // todo: implement + } + else if (command == "rot_paste") + { + // todo: implement + } + else if (command == "psr_copy") + { + // onCopyPos(); + // onCopySize(); + // onCopyRot(); + } + else if (command == "pos_copy") + { + // todo: implement + } + else if (command == "size_copy") + { + // todo: implement + } + else if (command == "rot_copy") + { + // todo: implement + } +} + +bool LLFloaterGLTFAssetEditor::onMenuEnableItem(const LLSD& userdata) +{ + if (!mFolderRoot) + { + return false; + } + + LLFolderViewItem* item = mFolderRoot->getCurSelectedItem(); + if (!item) + { + return false; + } + + LLGLTFFolderItem* vmi = static_cast(item->getViewModelItem()); + + if (!vmi || vmi->getType() != LLGLTFFolderItem::TYPE_NODE) + { + return false; + } + + std::string command = userdata.asString(); + if (command == "pos_paste" || command == "size_paste" || command == "rot_paste") + { + // todo: implement + return true; + } + if (command == "psr_copy") + { + // todo: implement + return true; + } + + return false; +} + diff --git a/indra/newview/llfloatergltfasseteditor.h b/indra/newview/llfloatergltfasseteditor.h index 49c5aa4ae7..8164928824 100644 --- a/indra/newview/llfloatergltfasseteditor.h +++ b/indra/newview/llfloatergltfasseteditor.h @@ -40,6 +40,9 @@ namespace LL } } +class LLSpinCtrl; +class LLMenuButton; + class LLFloaterGLTFAssetEditor : public LLFloater { public: @@ -48,6 +51,7 @@ public: bool postBuild() override; void onOpen(const LLSD& key) override; + void initFolderRoot(); LLGLTFViewModel& getRootViewModel() { return mGLTFViewModel; } @@ -56,14 +60,42 @@ public: void loadFromNode(S32 node, LLFolderViewFolder* parent); void loadFromSelection(); -private: - LLGLTFViewModel mGLTFViewModel; - LLUIColor mUIColor; +protected: + void onFolderSelectionChanged(const std::deque& items, bool user_action); + void onCommitTransform(); + void onMenuDoToSelected(const LLSD& userdata); + bool onMenuEnableItem(const LLSD& userdata); + void setTransformsEnabled(bool val); + void loadNodeTransforms(S32 id); + +private: + + std::shared_ptr mAsset; + + // Folder view related + LLUIColor mUIColor; + LLGLTFViewModel mGLTFViewModel; LLPanel* mItemListPanel = nullptr; LLFolderView* mFolderRoot = nullptr; LLScrollContainer* mScroller = nullptr; - std::shared_ptr mAsset; + + // Transforms panel + LLVector3 mLastEulerDegrees; + + LLPanel* mTransformsPanel = nullptr; + LLMenuButton* mMenuClipboardPos = nullptr; + LLSpinCtrl* mCtrlPosX = nullptr; + LLSpinCtrl* mCtrlPosY = nullptr; + LLSpinCtrl* mCtrlPosZ = nullptr; + LLMenuButton* mMenuClipboardScale = nullptr; + LLSpinCtrl* mCtrlScaleX = nullptr; + LLSpinCtrl* mCtrlScaleY = nullptr; + LLSpinCtrl* mCtrlScaleZ = nullptr; + LLMenuButton* mMenuClipboardRot = nullptr; + LLSpinCtrl* mCtrlRotX = nullptr; + LLSpinCtrl* mCtrlRotY = nullptr; + LLSpinCtrl* mCtrlRotZ = nullptr; }; #endif LL_LLFLOATERGLTFASSETEDITOR_H diff --git a/indra/newview/llgltffolderitem.h b/indra/newview/llgltffolderitem.h index be6e264368..83c6449f96 100644 --- a/indra/newview/llgltffolderitem.h +++ b/indra/newview/llgltffolderitem.h @@ -112,7 +112,7 @@ public: bool filter(LLFolderViewFilter& filter) override; EType getType() const { return mItemType; } - S32 getId() const { return mItemId; } + S32 getItemId() const { return mItemId; } private: LLUIImagePtr pIcon; diff --git a/indra/newview/skins/default/xui/en/floater_gltf_asset_editor.xml b/indra/newview/skins/default/xui/en/floater_gltf_asset_editor.xml index 4dc0dffcfd..82e0e325fb 100644 --- a/indra/newview/skins/default/xui/en/floater_gltf_asset_editor.xml +++ b/indra/newview/skins/default/xui/en/floater_gltf_asset_editor.xml @@ -3,9 +3,9 @@ legacy_header_height="18" can_resize="true" default_tab_group="1" - height="400" + height="530" width="256" - min_height="200" + min_height="400" min_width="200" layout="topleft" name="gltf asset editor" @@ -14,13 +14,270 @@ - + right="-1" + border_size="0"> + + + + + + + + + Position (m) + + + + + + + Size (m) + + + + + + + Rotation (°) + + + + + + + + + From b940fbc0d4b78534780de33dc9f7d41535de5ae3 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 1 Jul 2024 19:01:20 +0300 Subject: [PATCH 27/30] viewer#1131 MacOS build fixes and small adjustments --- indra/newview/llfloatergltfasseteditor.cpp | 16 +++++++++++++--- indra/newview/llfloatergltfasseteditor.h | 2 +- indra/newview/llgltffolderitem.cpp | 4 ++-- indra/newview/llgltffolderitem.h | 10 +++++----- indra/newview/llgltffoldermodel.cpp | 4 ++-- indra/newview/llgltffoldermodel.h | 2 +- .../default/xui/en/floater_gltf_asset_editor.xml | 7 ++++--- 7 files changed, 28 insertions(+), 17 deletions(-) diff --git a/indra/newview/llfloatergltfasseteditor.cpp b/indra/newview/llfloatergltfasseteditor.cpp index ec9ccc1324..f21b8032d0 100644 --- a/indra/newview/llfloatergltfasseteditor.cpp +++ b/indra/newview/llfloatergltfasseteditor.cpp @@ -3,9 +3,9 @@ * @author Andrii Kleshchev * @brief LLFloaterGltfAssetEditor class implementation * - * $LicenseInfo:firstyear=2008&license=viewerlgpl$ + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. + * Copyright (C) 2024, 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 @@ -251,7 +251,8 @@ void LLFloaterGLTFAssetEditor::loadFromSelection() return; } - LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode(NULL); + LLViewerObject* objectp = node->getObject(); if (!objectp) { return; @@ -263,6 +264,15 @@ void LLFloaterGLTFAssetEditor::loadFromSelection() return; } + if (node->mName.empty()) + { + setTitle(getString("floater_title")); + } + else + { + setTitle(node->mName); + } + LLUIColor item_color = LLUIColorTable::instance().getColor("MenuItemEnabledColor", DEFAULT_WHITE); for (S32 i = 0; i < mAsset->mScenes.size(); i++) { diff --git a/indra/newview/llfloatergltfasseteditor.h b/indra/newview/llfloatergltfasseteditor.h index 8164928824..e35ed30ed0 100644 --- a/indra/newview/llfloatergltfasseteditor.h +++ b/indra/newview/llfloatergltfasseteditor.h @@ -98,4 +98,4 @@ private: LLSpinCtrl* mCtrlRotZ = nullptr; }; -#endif LL_LLFLOATERGLTFASSETEDITOR_H +#endif diff --git a/indra/newview/llgltffolderitem.cpp b/indra/newview/llgltffolderitem.cpp index c4fcb4f5ce..77a19c060d 100644 --- a/indra/newview/llgltffolderitem.cpp +++ b/indra/newview/llgltffolderitem.cpp @@ -3,9 +3,9 @@ * @author Andrey Kleshchev * @brief LLGLTFFolderItem class implementation * - * $LicenseInfo:firstyear=2008&license=viewerlgpl$ + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. + * Copyright (C) 2024, 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 diff --git a/indra/newview/llgltffolderitem.h b/indra/newview/llgltffolderitem.h index 83c6449f96..89d90c81cc 100644 --- a/indra/newview/llgltffolderitem.h +++ b/indra/newview/llgltffolderitem.h @@ -59,8 +59,8 @@ public: std::string getSearchableUUIDString() const override { return std::string(); } LLPointer getIcon() const override { return pIcon; } - LLPointer getIconOpen() const { return getIcon(); } - LLPointer getIconOverlay() const { return NULL; } + LLPointer getIconOpen() const override { return getIcon(); } + LLPointer getIconOverlay() const override { return NULL; } LLFontGL::StyleFlags getLabelStyle() const override { return LLFontGL::NORMAL; } std::string getLabelSuffix() const override { return std::string(); } @@ -71,7 +71,7 @@ public: void navigateToFolder(bool new_window = false, bool change_mode = false) override {} - bool isItemWearable() const { return false; } + bool isItemWearable() const override { return false; } bool isItemRenameable() const override { return false; } bool renameItem(const std::string& new_name) override { return false; } @@ -86,7 +86,7 @@ public: bool isItemCopyable(bool can_copy_as_link = true) const override { return false; } bool copyToClipboard() const override { return false; } bool cutToClipboard() override { return false; } - bool isCutToClipboard() { return false; } + bool isCutToClipboard() override { return false; } bool isClipboardPasteable() const override { return false; } void pasteFromClipboard() override {} @@ -125,4 +125,4 @@ private: S32 mItemId = -1; }; -#endif LL_LLGLTFFOLDERITEM_H +#endif diff --git a/indra/newview/llgltffoldermodel.cpp b/indra/newview/llgltffoldermodel.cpp index 5f22c8b710..de2510dc4a 100644 --- a/indra/newview/llgltffoldermodel.cpp +++ b/indra/newview/llgltffoldermodel.cpp @@ -3,9 +3,9 @@ * @author Andrey Kleshchev * @brief gltf model's folder structure related classes * - * $LicenseInfo:firstyear=2008&license=viewerlgpl$ + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. + * Copyright (C) 2024, 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 diff --git a/indra/newview/llgltffoldermodel.h b/indra/newview/llgltffoldermodel.h index 26f05d1ecd..69b284aa31 100644 --- a/indra/newview/llgltffoldermodel.h +++ b/indra/newview/llgltffoldermodel.h @@ -88,4 +88,4 @@ public: private: }; -#endif LL_LLGLTFFOLDERMODEL_H +#endif diff --git a/indra/newview/skins/default/xui/en/floater_gltf_asset_editor.xml b/indra/newview/skins/default/xui/en/floater_gltf_asset_editor.xml index 82e0e325fb..b17d0aa5b6 100644 --- a/indra/newview/skins/default/xui/en/floater_gltf_asset_editor.xml +++ b/indra/newview/skins/default/xui/en/floater_gltf_asset_editor.xml @@ -10,6 +10,7 @@ layout="topleft" name="gltf asset editor" title="[OBJECT_NAME]"> + @@ -39,7 +40,7 @@ name="item_list_panel" visible="true" bottom="-1" - top="16" + top="1" left="5" right="-1"/> @@ -60,8 +61,8 @@ image_selected="ClipboardSmallMenu_Press" image_unselected="ClipboardSmallMenu_Off" layout="topleft" - left_delta="0" - top_pad="13" + left="4" + top="10" name="clipboard_pos_btn" tool_tip="Paste options" width="19"/> From 2ea5ac0c43e3e28d2b1774f5367d099271a1da32 Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Mon, 1 Jul 2024 13:34:50 +0200 Subject: [PATCH 28/30] #1111 Remove xmlrpc-epi --- autobuild.xml | 60 -- indra/cmake/CMakeLists.txt | 1 - indra/cmake/LLCommon.cmake | 2 - indra/cmake/XmlRpcEpi.cmake | 11 - indra/llcommon/llfile.cpp | 18 + indra/llcommon/llfile.h | 2 + indra/llcommon/llsd.cpp | 201 ++++- indra/llcommon/llsd.h | 20 +- indra/llcommon/llstring.cpp | 69 ++ indra/llcommon/llstring.h | 14 + indra/llmessage/CMakeLists.txt | 3 - indra/llmessage/llfiltersd2xmlrpc.cpp | 778 ------------------ indra/llmessage/llfiltersd2xmlrpc.h | 271 ------ indra/llxml/llxmlnode.cpp | 39 +- indra/llxml/llxmlnode.h | 12 +- indra/newview/llcurrencyuimanager.cpp | 137 ++- indra/newview/llfloaterbuyland.cpp | 203 ++--- indra/newview/lllogininstance.cpp | 5 +- indra/newview/llslurl.cpp | 6 +- indra/newview/llversioninfo.cpp | 22 +- indra/newview/llversioninfo.h | 26 +- indra/newview/llxmlrpclistener.cpp | 278 +------ indra/newview/llxmlrpclistener.h | 3 - indra/newview/llxmlrpctransaction.cpp | 377 +++------ indra/newview/llxmlrpctransaction.h | 92 +-- .../skins/default/xui/da/floater_about.xml | 1 - .../skins/default/xui/de/floater_about.xml | 1 - .../skins/default/xui/en/floater_about.xml | 1 - .../skins/default/xui/es/floater_about.xml | 1 - .../skins/default/xui/fr/floater_about.xml | 1 - .../skins/default/xui/it/floater_about.xml | 1 - .../skins/default/xui/ja/floater_about.xml | 1 - .../skins/default/xui/pt/floater_about.xml | 1 - .../skins/default/xui/ru/floater_about.xml | 1 - .../skins/default/xui/tr/floater_about.xml | 1 - .../skins/default/xui/zh/floater_about.xml | 1 - indra/viewer_components/login/lllogin.cpp | 41 +- 37 files changed, 732 insertions(+), 1970 deletions(-) delete mode 100644 indra/cmake/XmlRpcEpi.cmake delete mode 100644 indra/llmessage/llfiltersd2xmlrpc.cpp delete mode 100644 indra/llmessage/llfiltersd2xmlrpc.h diff --git a/autobuild.xml b/autobuild.xml index c47661df18..2e673f79ce 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -2670,66 +2670,6 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors name vlc-bin - xmlrpc-epi - - platforms - - darwin64 - - archive - - hash - aa12611374876196b3ebb6bda8d419a697217b8b - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-xmlrpc-epi/releases/download/v0.54.1.8a05acf/xmlrpc_epi-0.54.1.8a05acf-darwin64-8a05acf.tar.zst - - name - darwin64 - - linux64 - - archive - - hash - ad0c8b41ee4b4de216382bec46ee1c25962a3f12 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-xmlrpc-epi/releases/download/v0.54.1.8a05acf/xmlrpc_epi-0.54.1.8a05acf-linux64-8a05acf.tar.zst - - name - linux64 - - windows64 - - archive - - hash - e53fd38c14b8c47c7c84dead8a1b211bb8be170c - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-xmlrpc-epi/releases/download/v0.54.1.8a05acf/xmlrpc_epi-0.54.1.8a05acf-windows64-8a05acf.tar.zst - - name - windows64 - - - license - xmlrpc-epi - license_file - LICENSES/xmlrpc-epi.txt - copyright - Copyright: (C) 2000 Epinions, Inc. - version - 0.54.1.8a05acf - name - xmlrpc-epi - description - XMLRPC Library - vulkan_gltf platforms diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt index 0f338931c0..c067105f68 100644 --- a/indra/cmake/CMakeLists.txt +++ b/indra/cmake/CMakeLists.txt @@ -63,7 +63,6 @@ set(cmake_SOURCE_FILES VisualLeakDetector.cmake LibVLCPlugin.cmake WebRTC.cmake - XmlRpcEpi.cmake xxHash.cmake ZLIBNG.cmake ) diff --git a/indra/cmake/LLCommon.cmake b/indra/cmake/LLCommon.cmake index 9e3707ff17..dd43ca4916 100644 --- a/indra/cmake/LLCommon.cmake +++ b/indra/cmake/LLCommon.cmake @@ -6,5 +6,3 @@ include(EXPAT) include(Tracy) include(xxHash) include(ZLIBNG) - -include(XmlRpcEpi) diff --git a/indra/cmake/XmlRpcEpi.cmake b/indra/cmake/XmlRpcEpi.cmake deleted file mode 100644 index 6409f9d6e2..0000000000 --- a/indra/cmake/XmlRpcEpi.cmake +++ /dev/null @@ -1,11 +0,0 @@ -# -*- cmake -*- -include(Prebuilt) - -include_guard() -add_library( ll::xmlrpc-epi INTERFACE IMPORTED ) - -use_system_binary( xmlrpc-epi ) - -use_prebuilt_binary(xmlrpc-epi) -target_link_libraries(ll::xmlrpc-epi INTERFACE xmlrpc-epi ) -target_include_directories( ll::xmlrpc-epi SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include) diff --git a/indra/llcommon/llfile.cpp b/indra/llcommon/llfile.cpp index ddf239f306..9045324bf2 100644 --- a/indra/llcommon/llfile.cpp +++ b/indra/llcommon/llfile.cpp @@ -248,6 +248,24 @@ int LLFile::close(LLFILE * file) return ret_value; } +std::string LLFile::getContents(const std::string& filename) +{ + LLFILE* fp = fopen(filename, "rb"); /* Flawfinder: ignore */ + if (fp) + { + fseek(fp, 0, SEEK_END); + U32 length = ftell(fp); + fseek(fp, 0, SEEK_SET); + + std::vector buffer(length); + size_t nread = fread(buffer.data(), 1, length, fp); + fclose(fp); + + return std::string(buffer.data(), nread); + } + + return LLStringUtil::null; +} int LLFile::remove(const std::string& filename, int supress_error) { diff --git a/indra/llcommon/llfile.h b/indra/llcommon/llfile.h index 2564671b13..74110343fc 100644 --- a/indra/llcommon/llfile.h +++ b/indra/llcommon/llfile.h @@ -67,6 +67,8 @@ public: static int close(LLFILE * file); + static std::string getContents(const std::string& filename); + // perms is a permissions mask like 0777 or 0700. In most cases it will // be overridden by the user's umask. It is ignored on Windows. // mkdir() considers "directory already exists" to be SUCCESS. diff --git a/indra/llcommon/llsd.cpp b/indra/llcommon/llsd.cpp index 663ceac22b..b36ff7d263 100644 --- a/indra/llcommon/llsd.cpp +++ b/indra/llcommon/llsd.cpp @@ -30,6 +30,7 @@ #include "linden_common.h" #include "llsd.h" +#include "llbase64.h" #include "llerror.h" #include "../llmath/llmath.h" #include "llformat.h" @@ -142,6 +143,8 @@ public: virtual const String& asStringRef() const { static const std::string empty; return empty; } + virtual String asXMLRPCValue() const { return ""; } + virtual bool has(const String&) const { return false; } virtual LLSD get(const String&) const { return LLSD(); } virtual LLSD getKeys() const { return LLSD::emptyArray(); } @@ -222,6 +225,8 @@ namespace virtual LLSD::Integer asInteger() const { return mValue ? 1 : 0; } virtual LLSD::Real asReal() const { return mValue ? 1 : 0; } virtual LLSD::String asString() const; + + virtual LLSD::String asXMLRPCValue() const { return mValue ? "1" : "0"; } }; LLSD::String ImplBoolean::asString() const @@ -243,6 +248,8 @@ namespace virtual LLSD::Integer asInteger() const { return mValue; } virtual LLSD::Real asReal() const { return mValue; } virtual LLSD::String asString() const; + + virtual LLSD::String asXMLRPCValue() const { return "" + std::to_string(mValue) + ""; } }; LLSD::String ImplInteger::asString() const @@ -259,6 +266,8 @@ namespace virtual LLSD::Integer asInteger() const; virtual LLSD::Real asReal() const { return mValue; } virtual LLSD::String asString() const; + + virtual LLSD::String asXMLRPCValue() const { return "" + std::to_string(mValue) + ""; } }; LLSD::Boolean ImplReal::asBoolean() const @@ -286,9 +295,11 @@ namespace virtual LLSD::URI asURI() const { return LLURI(mValue); } virtual size_t size() const { return mValue.size(); } virtual const LLSD::String& asStringRef() const { return mValue; } + + virtual LLSD::String asXMLRPCValue() const { return "" + LLStringFn::xml_encode(mValue) + ""; } }; - LLSD::Integer ImplString::asInteger() const + LLSD::Integer ImplString::asInteger() const { // This must treat "1.23" not as an error, but as a number, which is // then truncated down to an integer. Hence, this code doesn't call @@ -298,7 +309,7 @@ namespace return (int)asReal(); } - LLSD::Real ImplString::asReal() const + LLSD::Real ImplString::asReal() const { F64 v = 0.0; std::istringstream i_stream(mValue); @@ -323,6 +334,8 @@ namespace virtual LLSD::String asString() const{ return mValue.asString(); } virtual LLSD::UUID asUUID() const { return mValue; } + + virtual LLSD::String asXMLRPCValue() const { return "" + mValue.asString() + ""; } }; @@ -344,6 +357,8 @@ namespace } virtual LLSD::String asString() const{ return mValue.asString(); } virtual LLSD::Date asDate() const { return mValue; } + + virtual LLSD::String asXMLRPCValue() const { return "" + mValue.toHTTPDateString("%FT%T") + ""; } }; @@ -355,6 +370,8 @@ namespace virtual LLSD::String asString() const{ return mValue.asString(); } virtual LLSD::URI asURI() const { return mValue; } + + virtual LLSD::String asXMLRPCValue() const { return "" + LLStringFn::xml_encode(mValue.asString()) + ""; } }; @@ -365,13 +382,15 @@ namespace ImplBinary(const LLSD::Binary& v) : Base(v) { } virtual const LLSD::Binary& asBinary() const{ return mValue; } + + virtual LLSD::String asXMLRPCValue() const { return "" + LLBase64::encode(mValue.data(), mValue.size()) + ""; } }; class ImplMap : public LLSD::Impl { private: - typedef std::map DataMap; + typedef std::map DataMap; DataMap mData; @@ -387,6 +406,19 @@ namespace virtual LLSD::Boolean asBoolean() const { return !mData.empty(); } + virtual LLSD::String asXMLRPCValue() const + { + std::ostringstream os; + os << ""; + for (const auto& it : mData) + { + os << "" << LLStringFn::xml_encode(it.first) << "" + << it.second.asXMLRPCValue() << ""; + } + os << ""; + return os.str(); + } + virtual bool has(const LLSD::String&) const; using LLSD::Impl::get; // Unhiding get(size_t) @@ -511,7 +543,7 @@ namespace class ImplArray : public LLSD::Impl { private: - typedef std::vector DataVector; + typedef std::vector DataVector; DataVector mData; @@ -527,6 +559,18 @@ namespace virtual LLSD::Boolean asBoolean() const { return !mData.empty(); } + virtual LLSD::String asXMLRPCValue() const + { + std::ostringstream os; + os << ""; + for (const auto& it : mData) + { + os << it.asXMLRPCValue(); + } + os << ""; + return os.str(); + } + using LLSD::Impl::get; // Unhiding get(LLSD::String) using LLSD::Impl::erase; // Unhiding erase(LLSD::String) using LLSD::Impl::ref; // Unhiding ref(LLSD::String) @@ -872,6 +916,155 @@ const LLSD::Binary& LLSD::asBinary() const { return safe(impl).asBinary(); } const LLSD::String& LLSD::asStringRef() const { return safe(impl).asStringRef(); } +LLSD::String LLSD::asXMLRPCValue() const { return "" + safe(impl).asXMLRPCValue() + ""; } + +static bool inline check(bool condition, const char* warning_message) +{ + if (!condition) + { + LL_WARNS() << warning_message << LL_ENDL; + } + + return condition; +} + +static bool parseXMLRPCArrayValue(LLSD& target, LLSD::TreeNode* node) +{ + LLSD::TreeNode* data = node->getFirstChild(); + if (!check(data, "No array inner XML element ( expected)") || + !check(data->hasName("data"), "Invalid array inner XML element ( expected)") || + !check(!data->getNextSibling(), "Multiple array inner XML elements (single expected)")) + return false; + + for (LLSD::TreeNode* item = data->getFirstChild(); item; item = item->getNextSibling()) + { + LLSD value; + if (!value.fromXMLRPCValue(item)) + return false; + + target.append(value); + } + + return true; +} + +static bool parseXMLRPCStructValue(LLSD& target, LLSD::TreeNode* node) +{ + for (LLSD::TreeNode* item = node->getFirstChild(); item; item = item->getNextSibling()) + { + if (!check(item->hasName("member"), "Invalid struct inner XML element ( expected)")) + return false; + + std::string name; + LLSD value; + for (LLSD::TreeNode* subitem = item->getFirstChild(); subitem; subitem = subitem->getNextSibling()) + { + if (subitem->hasName("name")) + { + name = LLStringFn::xml_decode(subitem->getTextContents()); + } + else if (!value.fromXMLRPCValue(subitem)) + { + return false; + } + } + if (!check(!name.empty(), "Empty struct member name")) + return false; + + target.insert(name, value); + } + + return true; +} + +bool LLSD::fromXMLRPCValue(TreeNode* node) +{ + clear(); + + llassert(node); + if (!node) + return false; + + if (!check(node->hasName("value"), "Invalid XML element ( expected)")) + return false; + + TreeNode* inner = node->getFirstChild(); + if (!inner) + { + check(false, "No inner XML element (value type expected)"); + // Value with no type qualifier is treated as string + assign(LLStringFn::xml_decode(node->getTextContents())); + return true; + } + + if (!check(!inner->getNextSibling(), "Multiple inner XML elements (single expected)")) + return false; + + if (inner->hasName("string")) + { + assign(LLStringFn::xml_decode(inner->getTextContents())); + return true; + } + + if (inner->hasName("int") || inner->hasName("i4")) + { + assign(std::stoi(inner->getTextContents())); + return true; + } + + if (inner->hasName("double")) + { + assign(std::stod(inner->getTextContents())); + return true; + } + + if (inner->hasName("boolean")) + { + assign(!!std::stoi(inner->getTextContents())); + return true; + } + + if (inner->hasName("dateTime.iso8601")) + { + assign(Date(inner->getTextContents())); + return true; + } + + if (inner->hasName("base64")) + { + std::string decoded = LLBase64::decodeAsString(inner->getTextContents()); + Binary binary(decoded.size()); + memcpy(binary.data(), decoded.data(), decoded.size()); + assign(binary); + return true; + } + + if (inner->hasName("array")) + { + if (!parseXMLRPCArrayValue(*this, inner)) + { + clear(); + return false; + } + return true; + } + + if (inner->hasName("struct")) + { + if (!parseXMLRPCStructValue(*this, inner)) + { + clear(); + return false; + } + return true; + } + + check(false, "Unknown inner XML element (known value type expected)"); + // Value with unknown type qualifier is treated as string + assign(LLStringFn::xml_decode(inner->getTextContents())); + return true; +} + // const char * helpers LLSD::LLSD(const char* v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); } void LLSD::assign(const char* v) diff --git a/indra/llcommon/llsd.h b/indra/llcommon/llsd.h index a5e735b561..5532decfc3 100644 --- a/indra/llcommon/llsd.h +++ b/indra/llcommon/llsd.h @@ -259,10 +259,24 @@ public: UUID asUUID() const; Date asDate() const; URI asURI() const; - const Binary& asBinary() const; + const Binary& asBinary() const; // asStringRef on any non-string type will return a ref to an empty string. - const String& asStringRef() const; + const String& asStringRef() const; + + // Return "<((type))>((scalar value or recursive calls))" + // See http://xmlrpc.com/spec.md + String asXMLRPCValue() const; + + struct TreeNode + { + virtual bool hasName(const String& name) const = 0; + virtual String getTextContents() const = 0; + virtual TreeNode* getFirstChild() const = 0; + virtual TreeNode* getNextSibling() const = 0; + }; + + bool fromXMLRPCValue(TreeNode* node); operator Boolean() const { return asBoolean(); } operator Integer() const { return asInteger(); } @@ -275,7 +289,7 @@ public: // This is needed because most platforms do not automatically // convert the boolean negation as a bool in an if statement. - bool operator!() const {return !asBoolean();} + bool operator!() const { return !asBoolean(); } //@} /** @name Character Pointer Helpers diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp index 514d73b24b..6f3d193d6b 100644 --- a/indra/llcommon/llstring.cpp +++ b/indra/llcommon/llstring.cpp @@ -1208,6 +1208,75 @@ namespace LLStringFn return output; } + using literals_t = std::map; + static const literals_t xml_elem_literals = + { + { '<', "<" }, + { '>', ">" }, + { '&', "&" } + }; + static const literals_t xml_attr_literals = + { + { '"', """ }, + { '\'', "'" } + }; + + static void literals_encode(std::string& text, const literals_t& literals) + { + for (const std::pair it : literals) + { + std::string::size_type pos = 0; + while ((pos = text.find(it.first, pos)) != std::string::npos) + { + text.replace(pos, 1, it.second); + pos += it.second.size(); + } + } + } + + static void literals_decode(std::string& text, const literals_t& literals) + { + for (const std::pair it : literals) + { + std::string::size_type pos = 0; + while ((pos = text.find(it.second, pos)) != std::string::npos) + { + text[pos++] = it.first; + text.erase(pos, it.second.size() - 1); + } + } + } + + /** + * @brief Replace all characters that are not allowed in XML 1.0 + * with corresponding literals: [ < > & ] => [ < > & ] + */ + std::string xml_encode(const std::string& input, bool for_attribute) + { + std::string result(input); + literals_encode(result, xml_elem_literals); + if (for_attribute) + { + literals_encode(result, xml_attr_literals); + } + return result; + } + + /** + * @brief Replace some of XML literals that are defined in XML 1.0 + * with corresponding characters: [ < > & ] => [ < > & ] + */ + std::string xml_decode(const std::string& input, bool for_attribute) + { + std::string result(input); + literals_decode(result, xml_elem_literals); + if (for_attribute) + { + literals_decode(result, xml_attr_literals); + } + return result; + } + /** * @brief Replace all control characters (c < 0x20) with replacement in * string. diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h index 123f4184b5..b69a068830 100644 --- a/indra/llcommon/llstring.h +++ b/indra/llcommon/llstring.h @@ -889,6 +889,20 @@ namespace LLStringFn LL_COMMON_API std::string strip_invalid_xml(const std::string& input); + /** + * @brief Replace all characters that are not allowed in XML 1.0 + * with corresponding literals: [ < > & ] => [ < > & ] + */ + LL_COMMON_API std::string xml_encode(const std::string& input, bool for_attribute = false); + + + /** + * @brief Replace some of XML literals that are defined in XML 1.0 + * with corresponding characters: [ < > & ] => [ < > & ] + */ + LL_COMMON_API std::string xml_decode(const std::string& input, bool for_attribute = false); + + /** * @brief Replace all control characters (0 <= c < 0x20) with replacement in * string. This is safe for utf-8 diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt index 5322139304..b2757a7306 100644 --- a/indra/llmessage/CMakeLists.txt +++ b/indra/llmessage/CMakeLists.txt @@ -27,7 +27,6 @@ set(llmessage_SOURCE_FILES lldatapacker.cpp lldispatcher.cpp llexperiencecache.cpp - llfiltersd2xmlrpc.cpp llgenericstreamingmessage.cpp llhost.cpp llhttpnode.cpp @@ -111,7 +110,6 @@ set(llmessage_HEADER_FILES lleventflags.h llexperiencecache.h llextendedstatus.h - llfiltersd2xmlrpc.h llfollowcamparams.h llgenericstreamingmessage.h llhost.h @@ -193,7 +191,6 @@ target_link_libraries( llfilesystem llmath llcorehttp - ll::xmlrpc-epi ) target_include_directories( llmessage INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/indra/llmessage/llfiltersd2xmlrpc.cpp b/indra/llmessage/llfiltersd2xmlrpc.cpp deleted file mode 100644 index 84b56d54bf..0000000000 --- a/indra/llmessage/llfiltersd2xmlrpc.cpp +++ /dev/null @@ -1,778 +0,0 @@ -/** - * @file llfiltersd2xmlrpc.cpp - * @author Phoenix - * @date 2005-04-26 - * - * $LicenseInfo:firstyear=2005&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$ - */ - -/** - * xml rpc request: - * - * - * examples.getStateName - * 41 - * - * - * - * xml rpc response: - * - * - * - * South Dakota - * - * - * - * xml rpc fault: - * - * - * - * - * faultCode4 - * faultString... - * - * - * - * - * llsd rpc request: - * - * { 'method':'...', 'parameter':...]} - * - * - * llsd rpc response: - * - * { 'response':... } - * - * - * llsd rpc fault: - * - * { 'fault': {'code':i..., 'description':'...'} } - * - * - */ - -#include "linden_common.h" -#include "llfiltersd2xmlrpc.h" - -#include -#include - -#ifdef LL_USESYSTEMLIBS -#include -#else -#include -#endif - -#include "apr_base64.h" - -#include "llbuffer.h" -#include "llbufferstream.h" -#include "llfasttimer.h" -#include "llmemorystream.h" -#include "llsd.h" -#include "llsdserialize.h" -#include "lluuid.h" - -// spammy mode -//#define LL_SPEW_STREAM_OUT_DEBUGGING 1 - -/** - * String constants - */ -static const char XML_HEADER[] = ""; -static const char XMLRPC_REQUEST_HEADER_1[] = ""; -static const char XMLRPC_REQUEST_HEADER_2[] = ""; -static const char XMLRPC_REQUEST_FOOTER[] = ""; -static const char XMLRPC_METHOD_RESPONSE_HEADER[] = ""; -static const char XMLRPC_METHOD_RESPONSE_FOOTER[] = ""; -static const char XMLRPC_RESPONSE_HEADER[] = ""; -static const char XMLRPC_RESPONSE_FOOTER[] = ""; -static const char XMLRPC_FAULT_1[] = "faultCode"; -static const char XMLRPC_FAULT_2[] = "faultString"; -static const char XMLRPC_FAULT_3[] = ""; -static const char LLSDRPC_RESPONSE_HEADER[] = "{'response':"; -static const char LLSDRPC_RESPONSE_FOOTER[] = "}"; -const char LLSDRPC_REQUEST_HEADER_1[] = "{'method':'"; -const char LLSDRPC_REQUEST_HEADER_2[] = "', 'parameter': "; -const char LLSDRPC_REQUEST_FOOTER[] = "}"; -static const char LLSDRPC_FAULT_HADER_1[] = "{ 'fault': {'code':i"; -static const char LLSDRPC_FAULT_HADER_2[] = ", 'description':"; -static const char LLSDRPC_FAULT_FOOTER[] = "} }"; -static const S32 DEFAULT_PRECISION = 20; - -/** - * LLFilterSD2XMLRPC - */ -LLFilterSD2XMLRPC::LLFilterSD2XMLRPC() -{ -} - -LLFilterSD2XMLRPC::~LLFilterSD2XMLRPC() -{ -} - -std::string xml_escape_string(const std::string& in) -{ - std::ostringstream out; - std::string::const_iterator it = in.begin(); - std::string::const_iterator end = in.end(); - for(; it != end; ++it) - { - switch((*it)) - { - case '<': - out << "<"; - break; - case '>': - out << ">"; - break; - case '&': - out << "&"; - break; - case '\'': - out << "'"; - break; - case '"': - out << """; - break; - default: - out << (*it); - break; - } - } - return out.str(); -} - -void LLFilterSD2XMLRPC::streamOut(std::ostream& ostr, const LLSD& sd) -{ - ostr << ""; - switch(sd.type()) - { - case LLSD::TypeMap: - { -#if LL_SPEW_STREAM_OUT_DEBUGGING - LL_INFOS() << "streamOut(map) BEGIN" << LL_ENDL; -#endif - ostr << ""; - if(ostr.fail()) - { - LL_INFOS() << "STREAM FAILURE writing struct" << LL_ENDL; - } - LLSD::map_const_iterator it = sd.beginMap(); - LLSD::map_const_iterator end = sd.endMap(); - for(; it != end; ++it) - { - ostr << "" << xml_escape_string((*it).first) - << ""; - streamOut(ostr, (*it).second); - if(ostr.fail()) - { - LL_INFOS() << "STREAM FAILURE writing '" << (*it).first - << "' with sd type " << (*it).second.type() << LL_ENDL; - } - ostr << ""; - } - ostr << ""; -#if LL_SPEW_STREAM_OUT_DEBUGGING - LL_INFOS() << "streamOut(map) END" << LL_ENDL; -#endif - break; - } - case LLSD::TypeArray: - { -#if LL_SPEW_STREAM_OUT_DEBUGGING - LL_INFOS() << "streamOut(array) BEGIN" << LL_ENDL; -#endif - ostr << ""; - LLSD::array_const_iterator it = sd.beginArray(); - LLSD::array_const_iterator end = sd.endArray(); - for(; it != end; ++it) - { - streamOut(ostr, *it); - if(ostr.fail()) - { - LL_INFOS() << "STREAM FAILURE writing array element sd type " - << (*it).type() << LL_ENDL; - } - } -#if LL_SPEW_STREAM_OUT_DEBUGGING - LL_INFOS() << "streamOut(array) END" << LL_ENDL; -#endif - ostr << ""; - break; - } - case LLSD::TypeUndefined: - // treat undefined as a bool with a false value. - case LLSD::TypeBoolean: -#if LL_SPEW_STREAM_OUT_DEBUGGING - LL_INFOS() << "streamOut(bool)" << LL_ENDL; -#endif - ostr << "" << (sd.asBoolean() ? "1" : "0") << ""; - break; - case LLSD::TypeInteger: -#if LL_SPEW_STREAM_OUT_DEBUGGING - LL_INFOS() << "streamOut(int)" << LL_ENDL; -#endif - ostr << "" << sd.asInteger() << ""; - break; - case LLSD::TypeReal: -#if LL_SPEW_STREAM_OUT_DEBUGGING - LL_INFOS() << "streamOut(real)" << LL_ENDL; -#endif - ostr << "" << sd.asReal() << ""; - break; - case LLSD::TypeString: -#if LL_SPEW_STREAM_OUT_DEBUGGING - LL_INFOS() << "streamOut(string)" << LL_ENDL; -#endif - ostr << "" << xml_escape_string(sd.asString()) << ""; - break; - case LLSD::TypeUUID: -#if LL_SPEW_STREAM_OUT_DEBUGGING - LL_INFOS() << "streamOut(uuid)" << LL_ENDL; -#endif - // serialize it as a string - ostr << "" << sd.asString() << ""; - break; - case LLSD::TypeURI: - { -#if LL_SPEW_STREAM_OUT_DEBUGGING - LL_INFOS() << "streamOut(uri)" << LL_ENDL; -#endif - // serialize it as a string - ostr << "" << xml_escape_string(sd.asString()) << ""; - break; - } - case LLSD::TypeBinary: - { -#if LL_SPEW_STREAM_OUT_DEBUGGING - LL_INFOS() << "streamOut(binary)" << LL_ENDL; -#endif - // this is pretty inefficient, but we'll deal with that - // problem when it becomes one. - ostr << ""; - LLSD::Binary buffer = sd.asBinary(); - if(!buffer.empty()) - { - // *TODO: convert to LLBase64 - int b64_buffer_length = apr_base64_encode_len(static_cast(buffer.size())); - char* b64_buffer = new char[b64_buffer_length]; - b64_buffer_length = apr_base64_encode_binary( - b64_buffer, - &buffer[0], - static_cast(buffer.size())); - ostr.write(b64_buffer, b64_buffer_length - 1); - delete[] b64_buffer; - } - ostr << ""; - break; - } - case LLSD::TypeDate: -#if LL_SPEW_STREAM_OUT_DEBUGGING - LL_INFOS() << "streamOut(date)" << LL_ENDL; -#endif - // no need to escape this since it will be alpha-numeric. - ostr << "" << sd.asString() << ""; - break; - default: - // unhandled type - LL_WARNS() << "Unhandled structured data type: " << sd.type() - << LL_ENDL; - break; - } - ostr << ""; -} - -/** - * LLFilterSD2XMLRPCResponse - */ - -LLFilterSD2XMLRPCResponse::LLFilterSD2XMLRPCResponse() -{ -} - -LLFilterSD2XMLRPCResponse::~LLFilterSD2XMLRPCResponse() -{ -} - - -// virtual -LLIOPipe::EStatus LLFilterSD2XMLRPCResponse::process_impl( - const LLChannelDescriptors& channels, - buffer_ptr_t& buffer, - bool& eos, - LLSD& context, - LLPumpIO* pump) -{ - LL_PROFILE_ZONE_SCOPED; - - PUMP_DEBUG; - // This pipe does not work if it does not have everyting. This - // could be addressed by making a stream parser for llsd which - // handled partial information. - if(!eos) - { - return STATUS_BREAK; - } - - PUMP_DEBUG; - // we have everyting in the buffer, so turn the structure data rpc - // response into an xml rpc response. - LLBufferStream stream(channels, buffer.get()); - stream << XML_HEADER << XMLRPC_METHOD_RESPONSE_HEADER; - LLSD sd; - LLSDSerialize::fromNotation(sd, stream, buffer->count(channels.in())); - - PUMP_DEBUG; - LLIOPipe::EStatus rv = STATUS_ERROR; - if(sd.has("response")) - { - PUMP_DEBUG; - // it is a normal response. pack it up and ship it out. - stream.precision(DEFAULT_PRECISION); - stream << XMLRPC_RESPONSE_HEADER; - streamOut(stream, sd["response"]); - stream << XMLRPC_RESPONSE_FOOTER << XMLRPC_METHOD_RESPONSE_FOOTER; - rv = STATUS_DONE; - } - else if(sd.has("fault")) - { - PUMP_DEBUG; - // it is a fault. - stream << XMLRPC_FAULT_1 << sd["fault"]["code"].asInteger() - << XMLRPC_FAULT_2 - << xml_escape_string(sd["fault"]["description"].asString()) - << XMLRPC_FAULT_3 << XMLRPC_METHOD_RESPONSE_FOOTER; - rv = STATUS_DONE; - } - else - { - LL_WARNS() << "Unable to determine the type of LLSD response." << LL_ENDL; - } - PUMP_DEBUG; - return rv; -} - -/** - * LLFilterSD2XMLRPCRequest - */ -LLFilterSD2XMLRPCRequest::LLFilterSD2XMLRPCRequest() -{ -} - -LLFilterSD2XMLRPCRequest::LLFilterSD2XMLRPCRequest(const char* method) -{ - if(method) - { - mMethod.assign(method); - } -} - -LLFilterSD2XMLRPCRequest::~LLFilterSD2XMLRPCRequest() -{ -} - -// virtual -LLIOPipe::EStatus LLFilterSD2XMLRPCRequest::process_impl( - const LLChannelDescriptors& channels, - buffer_ptr_t& buffer, - bool& eos, - LLSD& context, - LLPumpIO* pump) -{ - LL_PROFILE_ZONE_SCOPED; - // This pipe does not work if it does not have everyting. This - // could be addressed by making a stream parser for llsd which - // handled partial information. - PUMP_DEBUG; - if(!eos) - { - LL_INFOS() << "!eos" << LL_ENDL; - return STATUS_BREAK; - } - - // See if we can parse it - LLBufferStream stream(channels, buffer.get()); - LLSD sd; - LLSDSerialize::fromNotation(sd, stream, buffer->count(channels.in())); - if(stream.fail()) - { - LL_INFOS() << "STREAM FAILURE reading structure data." << LL_ENDL; - } - - PUMP_DEBUG; - // We can get the method and parameters from either the member - // function or passed in via the buffer. We prefer the buffer if - // we found a parameter and a method, or fall back to using - // mMethod and putting everyting in the buffer into the parameter. - std::string method; - LLSD param_sd; - if(sd.has("method") && sd.has("parameter")) - { - method = sd["method"].asString(); - param_sd = sd["parameter"]; - } - else - { - method = mMethod; - param_sd = sd; - } - if(method.empty()) - { - LL_WARNS() << "SD -> XML Request no method found." << LL_ENDL; - return STATUS_ERROR; - } - - PUMP_DEBUG; - // We have a method, and some kind of parameter, so package it up - // and send it out. - LLBufferStream ostream(channels, buffer.get()); - ostream.precision(DEFAULT_PRECISION); - if(ostream.fail()) - { - LL_INFOS() << "STREAM FAILURE setting precision" << LL_ENDL; - } - ostream << XML_HEADER << XMLRPC_REQUEST_HEADER_1 - << xml_escape_string(method) << XMLRPC_REQUEST_HEADER_2; - if(ostream.fail()) - { - LL_INFOS() << "STREAM FAILURE writing method headers" << LL_ENDL; - } - switch(param_sd.type()) - { - case LLSD::TypeMap: - // If the params are a map, then we do not want to iterate - // through them since the iterators returned will be map - // ordered un-named values, which will lose the names, and - // only stream the values, turning it into an array. - ostream << ""; - streamOut(ostream, param_sd); - ostream << ""; - break; - case LLSD::TypeArray: - { - - LLSD::array_iterator it = param_sd.beginArray(); - LLSD::array_iterator end = param_sd.endArray(); - for(; it != end; ++it) - { - ostream << ""; - streamOut(ostream, *it); - ostream << ""; - } - break; - } - default: - ostream << ""; - streamOut(ostream, param_sd); - ostream << ""; - break; - } - - stream << XMLRPC_REQUEST_FOOTER; - return STATUS_DONE; -} - -/** - * LLFilterXMLRPCResponse2LLSD - */ -// this is a c function here since it's really an implementation -// detail that requires a header file just get the definition of the -// parameters. -LLIOPipe::EStatus stream_out(std::ostream& ostr, XMLRPC_VALUE value) -{ - XMLRPC_VALUE_TYPE_EASY type = XMLRPC_GetValueTypeEasy(value); - LLIOPipe::EStatus status = LLIOPipe::STATUS_OK; - switch(type) - { - case xmlrpc_type_base64: - { - S32 len = XMLRPC_GetValueStringLen(value); - const char* buf = XMLRPC_GetValueBase64(value); - ostr << " b("; - if((len > 0) && buf) - { - ostr << len << ")\""; - ostr.write(buf, len); - ostr << "\""; - } - else - { - ostr << "0)\"\""; - } - break; - } - case xmlrpc_type_boolean: - //LL_DEBUGS() << "stream_out() bool" << LL_ENDL; - ostr << " " << (XMLRPC_GetValueBoolean(value) ? "true" : "false"); - break; - case xmlrpc_type_datetime: - ostr << " d\"" << XMLRPC_GetValueDateTime_ISO8601(value) << "\""; - break; - case xmlrpc_type_double: - ostr << " r" << XMLRPC_GetValueDouble(value); - //LL_DEBUGS() << "stream_out() double" << XMLRPC_GetValueDouble(value) - // << LL_ENDL; - break; - case xmlrpc_type_int: - ostr << " i" << XMLRPC_GetValueInt(value); - //LL_DEBUGS() << "stream_out() integer:" << XMLRPC_GetValueInt(value) - // << LL_ENDL; - break; - case xmlrpc_type_string: - //LL_DEBUGS() << "stream_out() string: " << str << LL_ENDL; - ostr << " s(" << XMLRPC_GetValueStringLen(value) << ")'" - << XMLRPC_GetValueString(value) << "'"; - break; - case xmlrpc_type_array: // vector - case xmlrpc_type_mixed: // vector - { - //LL_DEBUGS() << "stream_out() array" << LL_ENDL; - ostr << " ["; - U32 needs_comma = 0; - XMLRPC_VALUE current = XMLRPC_VectorRewind(value); - while(current && (LLIOPipe::STATUS_OK == status)) - { - if(needs_comma++) ostr << ","; - status = stream_out(ostr, current); - current = XMLRPC_VectorNext(value); - } - ostr << "]"; - break; - } - case xmlrpc_type_struct: // still vector - { - //LL_DEBUGS() << "stream_out() struct" << LL_ENDL; - ostr << " {"; - std::string name; - U32 needs_comma = 0; - XMLRPC_VALUE current = XMLRPC_VectorRewind(value); - while(current && (LLIOPipe::STATUS_OK == status)) - { - if(needs_comma++) ostr << ","; - name.assign(XMLRPC_GetValueID(current)); - ostr << "'" << LLSDNotationFormatter::escapeString(name) << "':"; - status = stream_out(ostr, current); - current = XMLRPC_VectorNext(value); - } - ostr << "}"; - break; - } - case xmlrpc_type_empty: - case xmlrpc_type_none: - default: - status = LLIOPipe::STATUS_ERROR; - LL_WARNS() << "Found an empty xmlrpc type.." << LL_ENDL; - // not much we can do here... - break; - }; - return status; -} - -LLFilterXMLRPCResponse2LLSD::LLFilterXMLRPCResponse2LLSD() -{ -} - -LLFilterXMLRPCResponse2LLSD::~LLFilterXMLRPCResponse2LLSD() -{ -} - -LLIOPipe::EStatus LLFilterXMLRPCResponse2LLSD::process_impl( - const LLChannelDescriptors& channels, - buffer_ptr_t& buffer, - bool& eos, - LLSD& context, - LLPumpIO* pump) -{ - LL_PROFILE_ZONE_SCOPED; - - PUMP_DEBUG; - if(!eos) return STATUS_BREAK; - if(!buffer) return STATUS_ERROR; - - PUMP_DEBUG; - // *FIX: This technique for reading data is far from optimal. We - // need to have some kind of istream interface into the xml - // parser... - S32 bytes = buffer->countAfter(channels.in(), NULL); - if(!bytes) return STATUS_ERROR; - char* buf = new char[bytes + 1]; - buf[bytes] = '\0'; - buffer->readAfter(channels.in(), NULL, (U8*)buf, bytes); - - //LL_DEBUGS() << "xmlrpc response: " << buf << LL_ENDL; - - PUMP_DEBUG; - XMLRPC_REQUEST response = XMLRPC_REQUEST_FromXML( - buf, - bytes, - NULL); - if(!response) - { - LL_WARNS() << "XML -> SD Response unable to parse xml." << LL_ENDL; - delete[] buf; - return STATUS_ERROR; - } - - PUMP_DEBUG; - LLBufferStream stream(channels, buffer.get()); - stream.precision(DEFAULT_PRECISION); - if(XMLRPC_ResponseIsFault(response)) - { - PUMP_DEBUG; - stream << LLSDRPC_FAULT_HADER_1 - << XMLRPC_GetResponseFaultCode(response) - << LLSDRPC_FAULT_HADER_2; - const char* fault_str = XMLRPC_GetResponseFaultString(response); - std::string fault_string; - if(fault_str) - { - fault_string.assign(fault_str); - } - stream << "'" << LLSDNotationFormatter::escapeString(fault_string) - << "'" <countAfter(channels.in(), NULL); - if(!bytes) return STATUS_ERROR; - char* buf = new char[bytes + 1]; - buf[bytes] = '\0'; - buffer->readAfter(channels.in(), NULL, (U8*)buf, bytes); - - //LL_DEBUGS() << "xmlrpc request: " << buf << LL_ENDL; - - // Check the value in the buffer. XMLRPC_REQUEST_FromXML will report a error code 4 if - // values that are less than 0x20 are passed to it, except - // 0x09: Horizontal tab; 0x0a: New Line; 0x0d: Carriage - U8* cur_pBuf = (U8*)buf; - U8 cur_char; - for (S32 i=0; i SD Request process parse error." << LL_ENDL; - delete[] buf; - return STATUS_ERROR; - } - - PUMP_DEBUG; - LLBufferStream stream(channels, buffer.get()); - stream.precision(DEFAULT_PRECISION); - const char* name = XMLRPC_RequestGetMethodName(request); - stream << LLSDRPC_REQUEST_HEADER_1 << (name ? name : "") - << LLSDRPC_REQUEST_HEADER_2; - XMLRPC_VALUE param = XMLRPC_RequestGetData(request); - if(param) - { - PUMP_DEBUG; - S32 size = XMLRPC_VectorSize(param); - if(size > 1) - { - // if there are multiple parameters, stuff the values into - // an array so that the next step in the chain can read them. - stream << "["; - } - XMLRPC_VALUE current = XMLRPC_VectorRewind(param); - bool needs_comma = false; - while(current) - { - if(needs_comma) - { - stream << ","; - } - needs_comma = true; - stream_out(stream, current); - current = XMLRPC_VectorNext(param); - } - if(size > 1) - { - // close the array - stream << "]"; - } - } - stream << LLSDRPC_REQUEST_FOOTER; - XMLRPC_RequestFree(request, 1); - delete[] buf; - PUMP_DEBUG; - return STATUS_DONE; -} - diff --git a/indra/llmessage/llfiltersd2xmlrpc.h b/indra/llmessage/llfiltersd2xmlrpc.h deleted file mode 100644 index 55938d3e2b..0000000000 --- a/indra/llmessage/llfiltersd2xmlrpc.h +++ /dev/null @@ -1,271 +0,0 @@ -/** - * @file llfiltersd2xmlrpc.h - * @author Phoenix - * @date 2005-04-26 - * - * $LicenseInfo:firstyear=2005&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$ - */ - -#ifndef LL_LLFILTERSD2XMLRPC_H -#define LL_LLFILTERSD2XMLRPC_H - -/** - * These classes implement the necessary pipes for translating between - * xmlrpc and llsd rpc. The llsd rpcs mechanism was developed as an - * extensible and easy to parse serialization grammer which maintains - * a time efficient in-memory representation. - */ - -#include -#include "lliopipe.h" - -/** - * @class LLFilterSD2XMLRPC - * @brief Filter from serialized LLSD to an XMLRPC method call - * - * This clas provides common functionality for the LLFilterSD2XMLRPRC - * request and response classes. - */ -class LLFilterSD2XMLRPC : public LLIOPipe -{ -public: - LLFilterSD2XMLRPC(); - virtual ~LLFilterSD2XMLRPC(); - -protected: - /** - * @brief helper method - */ - void streamOut(std::ostream& ostr, const LLSD& sd); -}; - -/** - * @class LLFilterSD2XMLRPCResponse - * @brief Filter from serialized LLSD to an XMLRPC response - * - * This class filters a serialized LLSD object to an xmlrpc - * repsonse. Since resonses are limited to a single param, the xmlrprc - * response only serializes it as one object. - * This class correctly handles normal llsd responses as well as llsd - * rpc faults. - * - * For example, if given: - * {'response':[ i200, r3.4, {"foo":"bar"} ]} - * Would generate: - * - * - * - * 200 - * 3.4 - * - * foobar - * - * - * - */ -class LLFilterSD2XMLRPCResponse : public LLFilterSD2XMLRPC -{ -public: - // constructor - LLFilterSD2XMLRPCResponse(); - - // destructor - virtual ~LLFilterSD2XMLRPCResponse(); - - /* @name LLIOPipe virtual implementations - */ - //@{ -protected: - /** - * @brief Process the data in buffer. - */ - virtual EStatus process_impl( - const LLChannelDescriptors& channels, - buffer_ptr_t& buffer, - bool& eos, - LLSD& context, - LLPumpIO* pump); - //@} -}; - -/** - * @class LLFilterSD2XMLRPCRequest - * @brief Filter from serialized LLSD to an XMLRPC method call - * - * This class will accept any kind of serialized LLSD object, but you - * probably want to have an array on the outer boundary since this - * object will interpret each element in the top level LLSD as a - * parameter into the xmlrpc spec. - * - * For example, you would represent 3 params as: - * - * {'method'='foo', 'parameter':[i200, r3.4, {"foo":"bar"}]} - * - * To generate: - * - * - * - * 200 - * 3.4 - * - * foobar - * - * - * - * This class will accept 2 different kinds of encodings. The first - * just an array of params as long as you specify the method in the - * constructor. It will also accept a structured data in the form: - * {'method':'$method_name', 'parameter':[...] } In the latter form, the - * encoded 'method' will be used regardless of the construction of the - * object, and the 'parameter' will be used as parameter to the call. - */ -class LLFilterSD2XMLRPCRequest : public LLFilterSD2XMLRPC -{ -public: - // constructor - LLFilterSD2XMLRPCRequest(); - - // constructor - LLFilterSD2XMLRPCRequest(const char* method); - - // destructor - virtual ~LLFilterSD2XMLRPCRequest(); - - /* @name LLIOPipe virtual implementations - */ - //@{ -protected: - /** - * @brief Process the data in buffer. - */ - virtual EStatus process_impl( - const LLChannelDescriptors& channels, - buffer_ptr_t& buffer, - bool& eos, - LLSD& context, - LLPumpIO* pump); - //@} - -protected: - // The method name of this request. - std::string mMethod; -}; - -/** - * @class LLFilterXMLRPCResponse2LLSD - * @brief Filter from serialized XMLRPC method response to LLSD - * - * The xmlrpc spec states that responses can only have one element - * which can be of any supported type. - * This takes in xml of the form: - * - * - * ok - * - * And processes it into: - * 'ok' - * - */ -class LLFilterXMLRPCResponse2LLSD : public LLIOPipe -{ -public: - // constructor - LLFilterXMLRPCResponse2LLSD(); - - // destructor - virtual ~LLFilterXMLRPCResponse2LLSD(); - - /* @name LLIOPipe virtual implementations - */ - //@{ -protected: - /** - * @brief Process the data in buffer. - */ - virtual EStatus process_impl( - const LLChannelDescriptors& channels, - buffer_ptr_t& buffer, - bool& eos, - LLSD& context, - LLPumpIO* pump); - //@} - -protected: -}; - -/** - * @class LLFilterXMLRPCRequest2LLSD - * @brief Filter from serialized XMLRPC method call to LLSD - * - * This takes in xml of the form: - * - * - * repeat - * - * 4 - * ok - * - * - * And processes it into: - * { 'method':'repeat', 'params':[i4, 'ok'] } - */ -class LLFilterXMLRPCRequest2LLSD : public LLIOPipe -{ -public: - // constructor - LLFilterXMLRPCRequest2LLSD(); - - // destructor - virtual ~LLFilterXMLRPCRequest2LLSD(); - - /* @name LLIOPipe virtual implementations - */ - //@{ -protected: - /** - * @brief Process the data in buffer. - */ - virtual EStatus process_impl( - const LLChannelDescriptors& channels, - buffer_ptr_t& buffer, - bool& eos, - LLSD& context, - LLPumpIO* pump); - //@} - -protected: -}; - -/** - * @brief This function takes string, and escapes it appropritately - * for inclusion as xml data. - */ -std::string xml_escape_string(const std::string& in); - -/** - * @brief Externally available constants - */ -extern const char LLSDRPC_REQUEST_HEADER_1[]; -extern const char LLSDRPC_REQUEST_HEADER_2[]; -extern const char LLSDRPC_REQUEST_FOOTER[]; - -#endif // LL_LLFILTERSD2XMLRPC_H diff --git a/indra/llxml/llxmlnode.cpp b/indra/llxml/llxmlnode.cpp index 0fd4516844..7f6b8093fc 100644 --- a/indra/llxml/llxmlnode.cpp +++ b/indra/llxml/llxmlnode.cpp @@ -653,32 +653,24 @@ bool LLXMLNode::updateNode( // static bool LLXMLNode::parseFile(const std::string& filename, LLXMLNodePtr& node, LLXMLNode* defaults_tree) { - // Read file - LL_DEBUGS("XMLNode") << "parsing XML file: " << filename << LL_ENDL; - LLFILE* fp = LLFile::fopen(filename, "rb"); /* Flawfinder: ignore */ - if (fp == NULL) + std::string xml = LLFile::getContents(filename); + if (xml.empty()) { - node = NULL ; - return false; + LL_WARNS("XMLNode") << "no XML file: " << filename << LL_ENDL; + } + else if (parseBuffer(xml.data(), xml.size(), node, defaults_tree)) + { + return true; } - fseek(fp, 0, SEEK_END); - U32 length = ftell(fp); - fseek(fp, 0, SEEK_SET); - U8* buffer = new U8[length+1]; - size_t nread = fread(buffer, 1, length, fp); - buffer[nread] = 0; - fclose(fp); - - bool rv = parseBuffer(buffer, static_cast(nread), node, defaults_tree); - delete [] buffer; - return rv; + node = nullptr; + return false; } // static bool LLXMLNode::parseBuffer( - U8* buffer, - U32 length, + const char* buffer, + U64 length, LLXMLNodePtr& node, LLXMLNode* defaults) { @@ -693,20 +685,25 @@ bool LLXMLNode::parseBuffer( file_node->mParser = &my_parser; - XML_SetUserData(my_parser, (void *)file_node_ptr); + XML_SetUserData(my_parser, file_node_ptr); // Do the parsing - if (XML_Parse(my_parser, (const char *)buffer, length, true) != XML_STATUS_OK) + bool success = XML_STATUS_OK == XML_Parse(my_parser, buffer, (int)length, true); + if (!success) { LL_WARNS() << "Error parsing xml error code: " << XML_ErrorString(XML_GetErrorCode(my_parser)) << " on line " << XML_GetCurrentLineNumber(my_parser) + << ", column " << XML_GetCurrentColumnNumber(my_parser) << LL_ENDL; } // Deinit XML_ParserFree(my_parser); + if (!success) + return false; + if (!file_node->mChildren || file_node->mChildren->map.size() != 1) { LL_WARNS() << "Parse failure - wrong number of top-level nodes xml." diff --git a/indra/llxml/llxmlnode.h b/indra/llxml/llxmlnode.h index b8e29bbfef..b8f9e1ff69 100644 --- a/indra/llxml/llxmlnode.h +++ b/indra/llxml/llxmlnode.h @@ -129,20 +129,20 @@ public: void addChild(LLXMLNodePtr& new_child); void setParent(LLXMLNodePtr& new_parent); // reparent if necessary - // Serialization + // Deserialization static bool parseFile( const std::string& filename, LLXMLNodePtr& node, - LLXMLNode* defaults_tree); + LLXMLNode* defaults = nullptr); static bool parseBuffer( - U8* buffer, - U32 length, + const char* buffer, + U64 length, LLXMLNodePtr& node, - LLXMLNode* defaults); + LLXMLNode* defaults = nullptr); static bool parseStream( std::istream& str, LLXMLNodePtr& node, - LLXMLNode* defaults); + LLXMLNode* defaults = nullptr); static bool updateNode( LLXMLNodePtr& node, LLXMLNodePtr& update_node); diff --git a/indra/newview/llcurrencyuimanager.cpp b/indra/newview/llcurrencyuimanager.cpp index 06c87343e2..8a4ab091a3 100644 --- a/indra/newview/llcurrencyuimanager.cpp +++ b/indra/newview/llcurrencyuimanager.cpp @@ -111,16 +111,17 @@ public: bool hasEstimate() const; std::string getLocalEstimate() const; - void startTransaction(TransactionType type, - const char* method, LLXMLRPCValue params); + void startTransaction(TransactionType type, const char* method, const LLSD& params); + + // return true if update needed bool checkTransaction(); - // return true if update needed void setError(const std::string& message, const std::string& uri); void clearError(); + // return true if update needed bool considerUpdateCurrency(); - // return true if update needed + void currencyKey(S32); static void onCurrencyKey(LLLineEditor* caller, void* data); @@ -160,32 +161,29 @@ void LLCurrencyUIManager::Impl::updateCurrencyInfo() return; } - LLXMLRPCValue keywordArgs = LLXMLRPCValue::createStruct(); - keywordArgs.appendString("agentId", gAgent.getID().asString()); - keywordArgs.appendString( - "secureSessionId", - gAgent.getSecureSessionID().asString()); - keywordArgs.appendString("language", LLUI::getLanguage()); - keywordArgs.appendInt("currencyBuy", mUserCurrencyBuy); - keywordArgs.appendString("viewerChannel", LLVersionInfo::instance().getChannel()); - keywordArgs.appendInt("viewerMajorVersion", LLVersionInfo::instance().getMajor()); - keywordArgs.appendInt("viewerMinorVersion", LLVersionInfo::instance().getMinor()); - keywordArgs.appendInt("viewerPatchVersion", LLVersionInfo::instance().getPatch()); - // With GitHub builds, the build number is too big to fit in a 32-bit int, - // and XMLRPC_VALUE doesn't deal with integers wider than int. Use string. - keywordArgs.appendString("viewerBuildVersion", stringize(LLVersionInfo::instance().getBuild())); + const LLVersionInfo& vi(LLVersionInfo::instance()); - LLXMLRPCValue params = LLXMLRPCValue::createArray(); - params.append(keywordArgs); + LLSD params = LLSD::emptyMap(); + params["agentId"] = gAgent.getID().asString(); + params["secureSessionId"] = gAgent.getSecureSessionID().asString(); + params["language"] = LLUI::getLanguage(); + params["currencyBuy"] = mUserCurrencyBuy; + params["viewerChannel"] = vi.getChannel(); + params["viewerMajorVersion"] = vi.getMajor(); + params["viewerMinorVersion"] = vi.getMinor(); + params["viewerPatchVersion"] = vi.getPatch(); + // With GitHub builds, the build number is too big to fit in a 32-bit int, + // and XMLRPC value doesn't deal with integers wider than int. Use string. + params["viewerBuildVersion"] = std::to_string(vi.getBuild()); startTransaction(TransactionCurrency, "getCurrencyQuote", params); } void LLCurrencyUIManager::Impl::finishCurrencyInfo() { - LLXMLRPCValue result = mTransaction->responseValue(); + const LLSD& result = mTransaction->response(); - bool success = result["success"].asBool(); + bool success = result["success"].asBoolean(); if (!success) { setError( @@ -195,24 +193,24 @@ void LLCurrencyUIManager::Impl::finishCurrencyInfo() return; } - LLXMLRPCValue currency = result["currency"]; + const LLSD& currency = result["currency"]; // old XML-RPC server: estimatedCost = value in US cents - mUSDCurrencyEstimated = currency["estimatedCost"].isValid(); + mUSDCurrencyEstimated = currency.has("estimatedCost"); if (mUSDCurrencyEstimated) { - mUSDCurrencyEstimatedCost = currency["estimatedCost"].asInt(); + mUSDCurrencyEstimatedCost = currency["estimatedCost"].asInteger(); } // newer XML-RPC server: estimatedLocalCost = local currency string - mLocalCurrencyEstimated = currency["estimatedLocalCost"].isValid(); + mLocalCurrencyEstimated = currency.has("estimatedLocalCost"); if (mLocalCurrencyEstimated) { mLocalCurrencyEstimatedCost = currency["estimatedLocalCost"].asString(); mSupportsInternationalBilling = true; } - S32 newCurrencyBuy = currency["currencyBuy"].asInt(); + S32 newCurrencyBuy = currency["currencyBuy"].asInteger(); if (newCurrencyBuy != mUserCurrencyBuy) { mUserCurrencyBuy = newCurrencyBuy; @@ -224,36 +222,36 @@ void LLCurrencyUIManager::Impl::finishCurrencyInfo() void LLCurrencyUIManager::Impl::startCurrencyBuy(const std::string& password) { - LLXMLRPCValue keywordArgs = LLXMLRPCValue::createStruct(); - keywordArgs.appendString("agentId", gAgent.getID().asString()); - keywordArgs.appendString( - "secureSessionId", - gAgent.getSecureSessionID().asString()); - keywordArgs.appendString("language", LLUI::getLanguage()); - keywordArgs.appendInt("currencyBuy", mUserCurrencyBuy); + const LLVersionInfo& vi(LLVersionInfo::instance()); + + LLSD params = LLSD::emptyMap(); + params["agentId"] = gAgent.getID().asString(); + params["secureSessionId"] = gAgent.getSecureSessionID().asString(); + params["language"] = LLUI::getLanguage(); + params["currencyBuy"] = mUserCurrencyBuy; + params["confirm"] = mSiteConfirm; + params["viewerChannel"] = vi.getChannel(); + params["viewerMajorVersion"] = vi.getMajor(); + params["viewerMinorVersion"] = vi.getMinor(); + params["viewerPatchVersion"] = vi.getPatch(); + // With GitHub builds, the build number is too big to fit in a 32-bit int, + // and XMLRPC value doesn't deal with integers wider than int. Use string. + params["viewerBuildVersion"] = std::to_string(vi.getBuild()); + if (mUSDCurrencyEstimated) { - keywordArgs.appendInt("estimatedCost", mUSDCurrencyEstimatedCost); + params["estimatedCost"] = mUSDCurrencyEstimatedCost; } + if (mLocalCurrencyEstimated) { - keywordArgs.appendString("estimatedLocalCost", mLocalCurrencyEstimatedCost); + params["estimatedLocalCost"] = mLocalCurrencyEstimatedCost; } - keywordArgs.appendString("confirm", mSiteConfirm); + if (!password.empty()) { - keywordArgs.appendString("password", password); + params["password"] = password; } - keywordArgs.appendString("viewerChannel", LLVersionInfo::instance().getChannel()); - keywordArgs.appendInt("viewerMajorVersion", LLVersionInfo::instance().getMajor()); - keywordArgs.appendInt("viewerMinorVersion", LLVersionInfo::instance().getMinor()); - keywordArgs.appendInt("viewerPatchVersion", LLVersionInfo::instance().getPatch()); - // With GitHub builds, the build number is too big to fit in a 32-bit int, - // and XMLRPC_VALUE doesn't deal with integers wider than int. Use string. - keywordArgs.appendString("viewerBuildVersion", stringize(LLVersionInfo::instance().getBuild())); - - LLXMLRPCValue params = LLXMLRPCValue::createArray(); - params.append(keywordArgs); startTransaction(TransactionBuy, "buyCurrency", params); @@ -263,9 +261,9 @@ void LLCurrencyUIManager::Impl::startCurrencyBuy(const std::string& password) void LLCurrencyUIManager::Impl::finishCurrencyBuy() { - LLXMLRPCValue result = mTransaction->responseValue(); + const LLSD& result = mTransaction->response(); - bool success = result["success"].asBool(); + bool success = result["success"].asBoolean(); if (!success) { setError( @@ -282,7 +280,7 @@ void LLCurrencyUIManager::Impl::finishCurrencyBuy() } void LLCurrencyUIManager::Impl::startTransaction(TransactionType type, - const char* method, LLXMLRPCValue params) + const char* method, const LLSD& params) { static std::string transactionURI; if (transactionURI.empty()) @@ -293,12 +291,7 @@ void LLCurrencyUIManager::Impl::startTransaction(TransactionType type, delete mTransaction; mTransactionType = type; - mTransaction = new LLXMLRPCTransaction( - transactionURI, - method, - params, - false /* don't use gzip */ - ); + mTransaction = new LLXMLRPCTransaction(transactionURI, method, params); clearError(); } @@ -352,12 +345,17 @@ bool LLCurrencyUIManager::Impl::checkTransaction() { setError(mTransaction->statusMessage(), mTransaction->statusURI()); } - else { + else + { switch (mTransactionType) { - case TransactionCurrency: finishCurrencyInfo(); break; - case TransactionBuy: finishCurrencyBuy(); break; - default: ; + case TransactionCurrency: + finishCurrencyInfo(); + break; + case TransactionBuy: + finishCurrencyBuy(); + break; + default:; } } @@ -385,9 +383,8 @@ void LLCurrencyUIManager::Impl::clearError() bool LLCurrencyUIManager::Impl::considerUpdateCurrency() { - if (mCurrencyChanged - && !mTransaction - && mCurrencyKeyTimer.getElapsedTimeF32() >= CURRENCY_ESTIMATE_FREQUENCY) + if (mCurrencyChanged && !mTransaction && + mCurrencyKeyTimer.getElapsedTimeF32() >= CURRENCY_ESTIMATE_FREQUENCY) { updateCurrencyInfo(); return true; @@ -408,7 +405,8 @@ void LLCurrencyUIManager::Impl::currencyKey(S32 value) mUserCurrencyBuy = value; - if (hasEstimate()) { + if (hasEstimate()) + { clearEstimate(); //cannot just simply refresh the whole UI, as the edit field will // get reset and the cursor will change... @@ -421,8 +419,7 @@ void LLCurrencyUIManager::Impl::currencyKey(S32 value) } // static -void LLCurrencyUIManager::Impl::onCurrencyKey( - LLLineEditor* caller, void* data) +void LLCurrencyUIManager::Impl::onCurrencyKey(LLLineEditor* caller, void* data) { S32 value = atoi(caller->getText().c_str()); LLCurrencyUIManager::Impl* self = (LLCurrencyUIManager::Impl*)data; @@ -589,14 +586,12 @@ bool LLCurrencyUIManager::inProcess() bool LLCurrencyUIManager::canCancel() { - return impl.mTransactionType != Impl::TransactionBuy; + return !buying(); } bool LLCurrencyUIManager::canBuy() { - return impl.mTransactionType == Impl::TransactionNone - && impl.hasEstimate() - && impl.mUserCurrencyBuy > 0; + return !inProcess() && impl.hasEstimate() && impl.mUserCurrencyBuy > 0; } bool LLCurrencyUIManager::buying() diff --git a/indra/newview/llfloaterbuyland.cpp b/indra/newview/llfloaterbuyland.cpp index 570a223908..11505e3047 100644 --- a/indra/newview/llfloaterbuyland.cpp +++ b/indra/newview/llfloaterbuyland.cpp @@ -182,7 +182,7 @@ public: void refreshUI(); - void startTransaction(TransactionType type, const LLXMLRPCValue& params); + void startTransaction(TransactionType type, const LLSD& params); bool checkTransaction(); void tellUserError(const std::string& message, const std::string& uri); @@ -396,11 +396,10 @@ void LLFloaterBuyLandUI::updateParcelInfo() // Can't have more than region max tasks, regardless of parcel // object bonus factor. LLViewerRegion* region = LLViewerParcelMgr::getInstance()->getSelectionRegion(); - if(region) + if (region) { S32 max_tasks_per_region = (S32)region->getMaxTasks(); - mParcelSupportedObjects = llmin( - mParcelSupportedObjects, max_tasks_per_region); + mParcelSupportedObjects = llmin(mParcelSupportedObjects, max_tasks_per_region); } mParcelSoldWithObjects = parcel->getSellWithObjects(); @@ -423,7 +422,7 @@ void LLFloaterBuyLandUI::updateParcelInfo() // checks that we can buy the land - if(mIsForGroup && !gAgent.hasPowerInActiveGroup(GP_LAND_DEED)) + if (mIsForGroup && !gAgent.hasPowerInActiveGroup(GP_LAND_DEED)) { mCannotBuyReason = getString("cant_buy_for_group"); return; @@ -492,85 +491,56 @@ void LLFloaterBuyLandUI::updateParcelInfo() void LLFloaterBuyLandUI::updateCovenantInfo() { LLViewerRegion* region = LLViewerParcelMgr::getInstance()->getSelectionRegion(); - if(!region) return; + if (!region) + return; U8 sim_access = region->getSimAccess(); std::string rating = LLViewerRegion::accessToString(sim_access); LLTextBox* region_name = getChild("region_name_text"); - if (region_name) + std::string region_name_txt = region->getName() + " ("+rating +")"; + region_name->setText(region_name_txt); + + LLIconCtrl* rating_icon = getChild("rating_icon"); + LLRect rect = rating_icon->getRect(); + S32 region_name_width = llmin(region_name->getRect().getWidth(), region_name->getTextBoundingRect().getWidth()); + S32 icon_left_pad = region_name->getRect().mLeft + region_name_width + ICON_PAD; + region_name->setToolTip(region_name->getText()); + rating_icon->setRect(rect.setOriginAndSize(icon_left_pad, rect.mBottom, rect.getWidth(), rect.getHeight())); + + switch (sim_access) { - std::string region_name_txt = region->getName() + " ("+rating +")"; - region_name->setText(region_name_txt); + case SIM_ACCESS_PG: + rating_icon->setValue(getString("icon_PG")); + break; - LLIconCtrl* rating_icon = getChild("rating_icon"); - LLRect rect = rating_icon->getRect(); - S32 region_name_width = llmin(region_name->getRect().getWidth(), region_name->getTextBoundingRect().getWidth()); - S32 icon_left_pad = region_name->getRect().mLeft + region_name_width + ICON_PAD; - region_name->setToolTip(region_name->getText()); - rating_icon->setRect(rect.setOriginAndSize(icon_left_pad, rect.mBottom, rect.getWidth(), rect.getHeight())); + case SIM_ACCESS_ADULT: + rating_icon->setValue(getString("icon_R")); + break; - switch(sim_access) - { - case SIM_ACCESS_PG: - rating_icon->setValue(getString("icon_PG")); - break; - - case SIM_ACCESS_ADULT: - rating_icon->setValue(getString("icon_R")); - break; - - default: - rating_icon->setValue(getString("icon_M")); - } + default: + rating_icon->setValue(getString("icon_M")); } LLTextBox* region_type = getChild("region_type_text"); - if (region_type) - { - region_type->setText(region->getLocalizedSimProductName()); - region_type->setToolTip(region->getLocalizedSimProductName()); - } + region_type->setText(region->getLocalizedSimProductName()); + region_type->setToolTip(region->getLocalizedSimProductName()); LLTextBox* resellable_clause = getChild("resellable_clause"); - if (resellable_clause) - { - if (region->getRegionFlag(REGION_FLAGS_BLOCK_LAND_RESELL)) - { - resellable_clause->setText(getString("can_not_resell")); - } - else - { - resellable_clause->setText(getString("can_resell")); - } - } + const char* can_resell = region->getRegionFlag(REGION_FLAGS_BLOCK_LAND_RESELL) ? "can_not_resell" : "can_resell"; + resellable_clause->setText(getString(can_resell)); LLTextBox* changeable_clause = getChild("changeable_clause"); - if (changeable_clause) - { - if (region->getRegionFlag(REGION_FLAGS_ALLOW_PARCEL_CHANGES)) - { - changeable_clause->setText(getString("can_change")); - } - else - { - changeable_clause->setText(getString("can_not_change")); - } - } + const char* can_change = region->getRegionFlag(REGION_FLAGS_ALLOW_PARCEL_CHANGES) ? "can_change" : "can_not_change"; + changeable_clause->setText(getString(can_change)); LLCheckBoxCtrl* check = getChild("agree_covenant"); - if(check) - { - check->set(false); - check->setEnabled(true); - check->setCommitCallback(onChangeAgreeCovenant, this); - } + check->set(false); + check->setEnabled(true); + check->setCommitCallback(onChangeAgreeCovenant, this); LLTextBox* box = getChild("covenant_text"); - if(box) - { - box->setVisible(false); - } + box->setVisible(false); // send EstateCovenantInfo message LLMessageSystem *msg = gMessageSystem; @@ -584,10 +554,9 @@ void LLFloaterBuyLandUI::updateCovenantInfo() // static void LLFloaterBuyLandUI::onChangeAgreeCovenant(LLUICtrl* ctrl, void* user_data) { - LLFloaterBuyLandUI* self = (LLFloaterBuyLandUI*)user_data; - if(self) + if (user_data) { - self->refreshUI(); + ((LLFloaterBuyLandUI*)user_data)->refreshUI(); } } @@ -626,13 +595,13 @@ void LLFloaterBuyLandUI::updateFloaterEstateName(const std::string& name) void LLFloaterBuyLandUI::updateFloaterLastModified(const std::string& text) { LLTextBox* editor = getChild("covenant_timestamp_text"); - if (editor) editor->setText(text); + editor->setText(text); } void LLFloaterBuyLandUI::updateFloaterEstateOwnerName(const std::string& name) { LLTextBox* box = getChild("estate_owner_text"); - if (box) box->setText(name); + box->setText(name); } void LLFloaterBuyLandUI::updateWebSiteInfo() @@ -640,9 +609,10 @@ void LLFloaterBuyLandUI::updateWebSiteInfo() S32 askBillableArea = mIsForGroup ? 0 : mParcelBillableArea; S32 askCurrencyBuy = mCurrency.getAmount(); - if (mTransaction && mTransactionType == TransactionPreflight - && mPreflightAskBillableArea == askBillableArea - && mPreflightAskCurrencyBuy == askCurrencyBuy) + if (mTransaction && + mTransactionType == TransactionPreflight && + mPreflightAskBillableArea == askBillableArea && + mPreflightAskCurrencyBuy == askCurrencyBuy) { return; } @@ -664,27 +634,21 @@ void LLFloaterBuyLandUI::updateWebSiteInfo() mSiteCurrencyEstimatedCost = 0; #endif - LLXMLRPCValue keywordArgs = LLXMLRPCValue::createStruct(); - keywordArgs.appendString("agentId", gAgent.getID().asString()); - keywordArgs.appendString( - "secureSessionId", - gAgent.getSecureSessionID().asString()); - keywordArgs.appendString("language", LLUI::getLanguage()); - keywordArgs.appendInt("billableArea", mPreflightAskBillableArea); - keywordArgs.appendInt("currencyBuy", mPreflightAskCurrencyBuy); - - LLXMLRPCValue params = LLXMLRPCValue::createArray(); - params.append(keywordArgs); + LLSD params = LLSD::emptyMap(); + params["agentId"] = gAgent.getID().asString(); + params["secureSessionId"] = gAgent.getSecureSessionID().asString(); + params["language"] = LLUI::getLanguage(); + params["billableArea"] = mPreflightAskBillableArea; + params["currencyBuy"] = mPreflightAskCurrencyBuy; startTransaction(TransactionPreflight, params); } void LLFloaterBuyLandUI::finishWebSiteInfo() { + const LLSD& result = mTransaction->response(); - LLXMLRPCValue result = mTransaction->responseValue(); - - mSiteValid = result["success"].asBool(); + mSiteValid = result["success"].asBoolean(); if (!mSiteValid) { tellUserError( @@ -694,31 +658,30 @@ void LLFloaterBuyLandUI::finishWebSiteInfo() return; } - LLXMLRPCValue membership = result["membership"]; - mSiteMembershipUpgrade = membership["upgrade"].asBool(); + const LLSD& membership = result["membership"]; + mSiteMembershipUpgrade = membership["upgrade"].asBoolean(); mSiteMembershipAction = membership["action"].asString(); mSiteMembershipPlanIDs.clear(); mSiteMembershipPlanNames.clear(); - LLXMLRPCValue levels = membership["levels"]; - for (LLXMLRPCValue level = levels.rewind(); - level.isValid(); - level = levels.next()) + const LLSD& levels = membership["levels"]; + for (auto it = levels.beginArray(); it != levels.endArray(); ++it) { + const LLSD& level = *it; mSiteMembershipPlanIDs.push_back(level["id"].asString()); mSiteMembershipPlanNames.push_back(level["description"].asString()); } mUserPlanChoice = 0; - LLXMLRPCValue landUse = result["landUse"]; - mSiteLandUseUpgrade = landUse["upgrade"].asBool(); + const LLSD& landUse = result["landUse"]; + mSiteLandUseUpgrade = landUse["upgrade"].asBoolean(); mSiteLandUseAction = landUse["action"].asString(); - LLXMLRPCValue currency = result["currency"]; - if (currency["estimatedCost"].isValid()) + const LLSD& currency = result["currency"]; + if (currency.has("estimatedCost")) { - mCurrency.setUSDEstimate(currency["estimatedCost"].asInt()); + mCurrency.setUSDEstimate(currency["estimatedCost"].asInteger()); } - if (currency["estimatedLocalCost"].isValid()) + if (currency.has("estimatedLocalCost")) { mCurrency.setLocalEstimate(currency["estimatedLocalCost"].asString()); } @@ -760,35 +723,30 @@ void LLFloaterBuyLandUI::runWebSitePrep(const std::string& password) } } - LLXMLRPCValue keywordArgs = LLXMLRPCValue::createStruct(); - keywordArgs.appendString("agentId", gAgent.getID().asString()); - keywordArgs.appendString( - "secureSessionId", - gAgent.getSecureSessionID().asString()); - keywordArgs.appendString("language", LLUI::getLanguage()); - keywordArgs.appendString("levelId", newLevel); - keywordArgs.appendInt("billableArea", - mIsForGroup ? 0 : mParcelBillableArea); - keywordArgs.appendInt("currencyBuy", mCurrency.getAmount()); - keywordArgs.appendInt("estimatedCost", mCurrency.getUSDEstimate()); - keywordArgs.appendString("estimatedLocalCost", mCurrency.getLocalEstimate()); - keywordArgs.appendString("confirm", mSiteConfirm); + LLSD params = LLSD::emptyMap(); + params["agentId"] = gAgent.getID().asString(); + params["secureSessionId"] = gAgent.getSecureSessionID().asString(); + params["language"] = LLUI::getLanguage(); + params["levelId"] = newLevel; + params["billableArea"] = mIsForGroup ? 0 : mParcelBillableArea; + params["currencyBuy"] = mCurrency.getAmount(); + params["estimatedCost"] = mCurrency.getUSDEstimate(); + params["estimatedLocalCost"] = mCurrency.getLocalEstimate(); + params["confirm"] = mSiteConfirm; + if (!password.empty()) { - keywordArgs.appendString("password", password); + params["password"] = password; } - LLXMLRPCValue params = LLXMLRPCValue::createArray(); - params.append(keywordArgs); - startTransaction(TransactionBuy, params); } void LLFloaterBuyLandUI::finishWebSitePrep() { - LLXMLRPCValue result = mTransaction->responseValue(); + const LLSD& result = mTransaction->response(); - bool success = result["success"].asBool(); + bool success = result["success"].asBoolean(); if (!success) { tellUserError( @@ -850,7 +808,7 @@ void LLFloaterBuyLandUI::updateGroupName(const LLUUID& id, } } -void LLFloaterBuyLandUI::startTransaction(TransactionType type, const LLXMLRPCValue& params) +void LLFloaterBuyLandUI::startTransaction(TransactionType type, const LLSD& params) { delete mTransaction; mTransaction = NULL; @@ -878,12 +836,7 @@ void LLFloaterBuyLandUI::startTransaction(TransactionType type, const LLXMLRPCVa return; } - mTransaction = new LLXMLRPCTransaction( - transaction_uri, - method, - params, - false /* don't use gzip */ - ); + mTransaction = new LLXMLRPCTransaction(transaction_uri, method, params); } bool LLFloaterBuyLandUI::checkTransaction() diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp index 282a273be6..d015c0ed95 100644 --- a/indra/newview/lllogininstance.cpp +++ b/indra/newview/lllogininstance.cpp @@ -33,9 +33,6 @@ #include "stringize.h" #include "llsdserialize.h" -// llmessage (!) -#include "llfiltersd2xmlrpc.h" // for xml_escape_string() - // login #include "lllogin.h" @@ -612,7 +609,7 @@ std::string construct_start_string() << position[VX] << "&" << position[VY] << "&" << position[VZ]); - start = xml_escape_string(unescaped_start); + start = LLStringFn::xml_encode(unescaped_start, true); break; } case LLSLURL::HOME_LOCATION: diff --git a/indra/newview/llslurl.cpp b/indra/newview/llslurl.cpp index 432ec3899a..d80cf2e80e 100644 --- a/indra/newview/llslurl.cpp +++ b/indra/newview/llslurl.cpp @@ -32,13 +32,15 @@ #include "llpanellogin.h" #include "llviewercontrol.h" #include "llviewernetwork.h" -#include "llfiltersd2xmlrpc.h" + #include "curl/curl.h" + const char* LLSLURL::SLURL_HTTP_SCHEME = "http"; const char* LLSLURL::SLURL_HTTPS_SCHEME = "https"; const char* LLSLURL::SLURL_SECONDLIFE_SCHEME = "secondlife"; const char* LLSLURL::SLURL_SECONDLIFE_PATH = "secondlife"; const char* LLSLURL::SLURL_COM = "slurl.com"; + // For DnD - even though www.slurl.com redirects to slurl.com in a browser, you can copy and drag // text with www.slurl.com or a link explicitly pointing at www.slurl.com so testing for this // version is required also. @@ -437,7 +439,7 @@ std::string LLSLURL::getLoginString() const LL_WARNS("AppInit") << "Unexpected SLURL type (" << (int)mType << ")for login string" << LL_ENDL; break; } - return xml_escape_string(unescaped_start.str()); + return LLStringFn::xml_encode(unescaped_start.str(), true); } bool LLSLURL::operator ==(const LLSLURL& rhs) diff --git a/indra/newview/llversioninfo.cpp b/indra/newview/llversioninfo.cpp index a571b5544b..4e8320b72a 100644 --- a/indra/newview/llversioninfo.cpp +++ b/indra/newview/llversioninfo.cpp @@ -76,37 +76,37 @@ LLVersionInfo::~LLVersionInfo() { } -S32 LLVersionInfo::getMajor() +S32 LLVersionInfo::getMajor() const { return LL_VIEWER_VERSION_MAJOR; } -S32 LLVersionInfo::getMinor() +S32 LLVersionInfo::getMinor() const { return LL_VIEWER_VERSION_MINOR; } -S32 LLVersionInfo::getPatch() +S32 LLVersionInfo::getPatch() const { return LL_VIEWER_VERSION_PATCH; } -U64 LLVersionInfo::getBuild() +U64 LLVersionInfo::getBuild() const { return LL_VIEWER_VERSION_BUILD; } -std::string LLVersionInfo::getVersion() +std::string LLVersionInfo::getVersion() const { return version; } -std::string LLVersionInfo::getShortVersion() +std::string LLVersionInfo::getShortVersion() const { return short_version; } -std::string LLVersionInfo::getChannelAndVersion() +std::string LLVersionInfo::getChannelAndVersion() const { if (mVersionChannel.empty()) { @@ -117,7 +117,7 @@ std::string LLVersionInfo::getChannelAndVersion() return mVersionChannel; } -std::string LLVersionInfo::getChannel() +std::string LLVersionInfo::getChannel() const { return mWorkingChannelName; } @@ -128,7 +128,7 @@ void LLVersionInfo::resetChannel(const std::string& channel) mVersionChannel.clear(); // Reset version and channel string til next use. } -LLVersionInfo::ViewerMaturity LLVersionInfo::getViewerMaturity() +LLVersionInfo::ViewerMaturity LLVersionInfo::getViewerMaturity() const { ViewerMaturity maturity; @@ -166,12 +166,12 @@ LLVersionInfo::ViewerMaturity LLVersionInfo::getViewerMaturity() } -std::string LLVersionInfo::getBuildConfig() +std::string LLVersionInfo::getBuildConfig() const { return build_configuration; } -std::string LLVersionInfo::getReleaseNotes() +std::string LLVersionInfo::getReleaseNotes() const { return mReleaseNotes; } diff --git a/indra/newview/llversioninfo.h b/indra/newview/llversioninfo.h index aed43263a6..237b37a084 100644 --- a/indra/newview/llversioninfo.h +++ b/indra/newview/llversioninfo.h @@ -52,38 +52,38 @@ public: ~LLVersionInfo(); /// return the major version number as an integer - S32 getMajor(); + S32 getMajor() const; /// return the minor version number as an integer - S32 getMinor(); + S32 getMinor() const; /// return the patch version number as an integer - S32 getPatch(); + S32 getPatch() const; /// return the build number as an integer - U64 getBuild(); + U64 getBuild() const; /// return the full viewer version as a string like "2.0.0.200030" - std::string getVersion(); + std::string getVersion() const; /// return the viewer version as a string like "2.0.0" - std::string getShortVersion(); + std::string getShortVersion() const; /// return the viewer version and channel as a string /// like "Second Life Release 2.0.0.200030" - std::string getChannelAndVersion(); + std::string getChannelAndVersion() const; /// return the channel name, e.g. "Second Life" - std::string getChannel(); + std::string getChannel() const; /// return the CMake build type - std::string getBuildConfig(); + std::string getBuildConfig() const; /// reset the channel name used by the viewer. void resetChannel(const std::string& channel); /// return the bit width of an address - S32 getAddressSize() { return ADDRESS_SIZE; } + S32 getAddressSize() const { return ADDRESS_SIZE; } typedef enum { @@ -92,11 +92,11 @@ public: BETA_VIEWER, RELEASE_VIEWER } ViewerMaturity; - ViewerMaturity getViewerMaturity(); + ViewerMaturity getViewerMaturity() const; /// get the release-notes URL, once it becomes available -- until then, /// return empty string - std::string getReleaseNotes(); + std::string getReleaseNotes() const; private: std::string version; @@ -107,7 +107,7 @@ private: std::string mWorkingChannelName; // Storage for the "version and channel" string. // This will get reset too. - std::string mVersionChannel; + mutable std::string mVersionChannel; std::string build_configuration; std::string mReleaseNotes; // Store unique_ptrs to the next couple things so we don't have to explain diff --git a/indra/newview/llxmlrpclistener.cpp b/indra/newview/llxmlrpclistener.cpp index 1148e81fd5..7c7bd98bcd 100644 --- a/indra/newview/llxmlrpclistener.cpp +++ b/indra/newview/llxmlrpclistener.cpp @@ -39,12 +39,6 @@ #include #include // boost::begin(), boost::end() -#ifdef LL_USESYSTEMLIBS -#include -#else -#include -#endif - #include "curl/curl.h" // other Linden headers @@ -178,13 +172,6 @@ public: static const CURLcodeMapper sCURLcodeMapper; -LLXMLRPCListener::LLXMLRPCListener(const std::string& pumpname): - mBoundListener(LLEventPumps::instance(). - obtain(pumpname). - listen("LLXMLRPCListener", boost::bind(&LLXMLRPCListener::process, this, _1))) -{ -} - /** * Capture an outstanding LLXMLRPCTransaction and poll it periodically until * done. @@ -213,38 +200,20 @@ public: mMethod(command["method"]), mReplyPump(command["reply"]) { - // LL_ERRS if any of these are missing - const char* required[] = { "uri", "method", "reply" }; - // optional: "options" (array of string) - // Validate the request - std::set missing; - for (const char** ri = boost::begin(required); ri != boost::end(required); ++ri) + // LL_ERRS if any of these keys are missing or empty + if (mUri.empty() || mMethod.empty() || mReplyPump.empty()) { - // If the command does not contain this required entry, add it to 'missing'. - if (! command.has(*ri)) - { - missing.insert(*ri); - } - } - if (! missing.empty()) - { - LL_ERRS("LLXMLRPCListener") << mMethod << " request missing params: "; - const char* separator = ""; - for (std::set::const_iterator mi(missing.begin()), mend(missing.end()); - mi != mend; ++mi) - { - LL_CONT << separator << *mi; - separator = ", "; - } - LL_CONT << LL_ENDL; + LL_ERRS("LLXMLRPCListener") + << "Some params are missing: " + << "reply: '" << mReplyPump << "', " + << "method: '" << mMethod << "', " + << "uri: '" << mUri << "'" + << LL_ENDL; } - // Build the XMLRPC request. - XMLRPC_REQUEST request = XMLRPC_RequestNew(); - XMLRPC_RequestSetMethodName(request, mMethod.c_str()); - XMLRPC_RequestSetRequestType(request, xmlrpc_request_call); - XMLRPC_VALUE xparams = XMLRPC_CreateVector(NULL, xmlrpc_vector_struct); - LLSD params(command["params"]); + LLSD request_params = LLSD::emptyMap(); + + LLSD params = command.get("params"); if (params.isMap()) { for (LLSD::map_const_iterator pi(params.beginMap()), pend(params.endMap()); @@ -252,44 +221,33 @@ public: { std::string name(pi->first); LLSD param(pi->second); - if (param.isString()) + switch (param.type()) { - XMLRPC_VectorAppendString(xparams, name.c_str(), param.asString().c_str(), 0); - } - else if (param.isInteger() || param.isBoolean()) - { - XMLRPC_VectorAppendInt(xparams, name.c_str(), param.asInteger()); - } - else if (param.isReal()) - { - XMLRPC_VectorAppendDouble(xparams, name.c_str(), param.asReal()); - } - else - { - LL_ERRS("LLXMLRPCListener") << mMethod << " request param " - << name << " has unknown type: " << param << LL_ENDL; + case LLSD::TypeString: + case LLSD::TypeInteger: + case LLSD::TypeReal: + request_params.insert(name, param); + break; + case LLSD::TypeBoolean: + request_params.insert(name, param.asInteger()); + break; + default: + LL_ERRS("LLXMLRPCListener") << mMethod + << " request param '" << name << "' has unknown type: " << param << LL_ENDL; } } } - LLSD options(command["options"]); + + LLSD options = command.get("options"); if (options.isArray()) { - XMLRPC_VALUE xoptions = XMLRPC_CreateVector("options", xmlrpc_vector_array); - for (LLSD::array_const_iterator oi(options.beginArray()), oend(options.endArray()); - oi != oend; ++oi) - { - XMLRPC_VectorAppendString(xoptions, NULL, oi->asString().c_str(), 0); - } - XMLRPC_AddValueToVector(xparams, xoptions); + request_params.insert("options", options); } - XMLRPC_RequestSetData(request, xparams); - mTransaction.reset(new LLXMLRPCTransaction(mUri, request, true, command.has("http_params")? LLSD(command["http_params"]) : LLSD())); + LLSD http_params = command.get("http_params"); + mTransaction.reset(new LLXMLRPCTransaction(mUri, mMethod, request_params, http_params)); mPreviousStatus = mTransaction->status(NULL); - // Free the XMLRPC_REQUEST object and the attached data values. - XMLRPC_RequestFree(request, 1); - // Now ensure that we get regular callbacks to poll for completion. mBoundListener = LLEventPumps::instance(). @@ -323,7 +281,7 @@ public: data["error"] = ""; data["transfer_rate"] = 0.0; LLEventPump& replyPump(LLEventPumps::instance().obtain(mReplyPump)); - if (! done) + if (!done) { // Not done yet, carry on. if (status == LLXMLRPCTransaction::StatusDownloading @@ -367,10 +325,8 @@ public: // Given 'message', need we care? if (status == LLXMLRPCTransaction::StatusComplete) { - // Success! Parse data. - std::string status_string(data["status"]); - data["responses"] = parseResponse(status_string); - data["status"] = status_string; + // Success! Retrieve response data. + data["responses"] = mTransaction->response(); } // whether successful or not, send reply on requested LLEventPump @@ -388,159 +344,6 @@ public: } private: - /// Derived from LLUserAuth::parseResponse() and parseOptionInto() - LLSD parseResponse(std::string& status_string) - { - // Extract every member into data["responses"] (a map of string - // values). - XMLRPC_REQUEST response = mTransaction->response(); - if (! response) - { - LL_DEBUGS("LLXMLRPCListener") << "No response" << LL_ENDL; - return LLSD(); - } - - XMLRPC_VALUE param = XMLRPC_RequestGetData(response); - if (! param) - { - LL_DEBUGS("LLXMLRPCListener") << "Response contains no data" << LL_ENDL; - return LLSD(); - } - - // Now, parse everything - return parseValues(status_string, "", param); - } - - LLSD parseValue(std::string& status_string, const std::string& key, const std::string& key_pfx, XMLRPC_VALUE param) - { - LLSD response; - - XMLRPC_VALUE_TYPE_EASY type = XMLRPC_GetValueTypeEasy(param); - switch (type) - { - case xmlrpc_type_empty: - LL_INFOS("LLXMLRPCListener") << "Empty result for key " << key_pfx << key << LL_ENDL; - break; - case xmlrpc_type_base64: - { - S32 len = XMLRPC_GetValueStringLen(param); - const char* buf = XMLRPC_GetValueBase64(param); - if ((len > 0) && buf) - { - // During implementation this code was not tested - // If you encounter this, please make sure this is correct, - // then remove llassert - llassert(0); - - LLSD::Binary data; - data.resize(len); - memcpy((void*)&data[0], (void*)buf, len); - response = data; - } - else - { - LL_WARNS("LLXMLRPCListener") << "Potentially malformed xmlrpc_type_base64 for key " - << key_pfx << key << LL_ENDL; - } - break; - } - case xmlrpc_type_boolean: - { - response = LLSD::Boolean(XMLRPC_GetValueBoolean(param)); - LL_DEBUGS("LLXMLRPCListener") << "val: " << response << LL_ENDL; - break; - } - case xmlrpc_type_datetime: - { - std::string iso8601_date(XMLRPC_GetValueDateTime_ISO8601(param)); - LL_DEBUGS("LLXMLRPCListener") << "val: " << iso8601_date << LL_ENDL; - response = LLSD::Date(iso8601_date); - break; - } - case xmlrpc_type_double: - { - response = LLSD::Real(XMLRPC_GetValueDouble(param)); - LL_DEBUGS("LLXMLRPCListener") << "val: " << response << LL_ENDL; - break; - } - case xmlrpc_type_int: - { - response = LLSD::Integer(XMLRPC_GetValueInt(param)); - LL_DEBUGS("LLXMLRPCListener") << "val: " << response << LL_ENDL; - break; - } - case xmlrpc_type_string: - { - response = LLSD::String(XMLRPC_GetValueString(param)); - LL_DEBUGS("LLXMLRPCListener") << "val: " << response << LL_ENDL; - break; - } - case xmlrpc_type_mixed: - case xmlrpc_type_array: - { - // We expect this to be an array of submaps. Walk the array, - // recursively parsing each submap and collecting them. - LLSD array; - int i = 0; // for descriptive purposes - for (XMLRPC_VALUE row = XMLRPC_VectorRewind(param); row; - row = XMLRPC_VectorNext(param), ++i) - { - // Recursive call. For the lower-level key_pfx, if 'key' - // is "foo", pass "foo[0]:", then "foo[1]:", etc. In the - // nested call, a subkey "bar" will then be logged as - // "foo[0]:bar", and so forth. - // Parse the scalar subkey/value pairs from this array - // entry into a temp submap. Collect such submaps in 'array'. - - array.append(parseValue(status_string, "", - STRINGIZE(key_pfx << key << '[' << i << "]:"), - row)); - } - // Having collected an 'array' of 'submap's, insert that whole - // 'array' as the value of this 'key'. - response = array; - break; - } - case xmlrpc_type_struct: - { - response = parseValues(status_string, - STRINGIZE(key_pfx << key << ':'), - param); - break; - } - case xmlrpc_type_none: // Not expected - default: - // whoops - unrecognized type - LL_WARNS("LLXMLRPCListener") << "Unhandled xmlrpc type " << type << " for key " - << key_pfx << key << LL_ENDL; - response = STRINGIZE("'); - status_string = "BadType"; - } - return response; - } - - /** - * Parse key/value pairs from a given XMLRPC_VALUE into an LLSD map. - * @param key_pfx Used to describe a given key in log messages. At top - * level, pass "". When parsing an options array, pass the top-level key - * name of the array plus the index of the array entry; to this we'll - * append the subkey of interest. - * @param param XMLRPC_VALUE iterator. At top level, pass - * XMLRPC_RequestGetData(XMLRPC_REQUEST). - */ - LLSD parseValues(std::string& status_string, const std::string& key_pfx, XMLRPC_VALUE param) - { - LLSD responses; - for (XMLRPC_VALUE current = XMLRPC_VectorRewind(param); current; - current = XMLRPC_VectorNext(param)) - { - std::string key(XMLRPC_GetValueID(current)); - LL_DEBUGS("LLXMLRPCListener") << "key: " << key_pfx << key << LL_ENDL; - responses.insert(key, parseValue(status_string, key, key_pfx, current)); - } - return responses; - } - const LLReqID mReqID; const std::string mUri; const std::string mMethod; @@ -550,11 +353,18 @@ private: LLXMLRPCTransaction::EStatus mPreviousStatus; // To detect state changes. }; -bool LLXMLRPCListener::process(const LLSD& command) +LLXMLRPCListener::LLXMLRPCListener(const std::string& pumpname) +: mBoundListener(LLEventPumps::instance().obtain(pumpname).listen +( + "LLXMLRPCListener", + [&](const LLSD& command) -> bool + { + // Allocate a new heap Poller, but do not save a pointer to it. Poller + // will check its own status and free itself on completion of the request. + (new Poller(command)); + // Conventional event listener return + return false; + } +)) { - // Allocate a new heap Poller, but do not save a pointer to it. Poller - // will check its own status and free itself on completion of the request. - (new Poller(command)); - // conventional event listener return - return false; } diff --git a/indra/newview/llxmlrpclistener.h b/indra/newview/llxmlrpclistener.h index aaed98eec5..fd75acb8b1 100644 --- a/indra/newview/llxmlrpclistener.h +++ b/indra/newview/llxmlrpclistener.h @@ -42,9 +42,6 @@ public: /// Specify the pump name on which to listen LLXMLRPCListener(const std::string& pumpname); - /// Handle request events on the event pump specified at construction time - bool process(const LLSD& command); - private: LLTempBoundListener mBoundListener; }; diff --git a/indra/newview/llxmlrpctransaction.cpp b/indra/newview/llxmlrpctransaction.cpp index ec6e22cd7a..55622fb6b7 100644 --- a/indra/newview/llxmlrpctransaction.cpp +++ b/indra/newview/llxmlrpctransaction.cpp @@ -42,22 +42,11 @@ #include "bufferarray.h" #include "llversioninfo.h" #include "llviewercontrol.h" +#include "llxmlnode.h" #include "stringize.h" // Have to include these last to avoid queue redefinition! -#ifdef LL_USESYSTEMLIBS -#include -#else -#include -#endif -// contains a harmful #define queue xmlrpc_queue. This -// breaks any use of std::queue. Ditch that #define: if any of our code wants -// to reference xmlrpc_queue, let it reference it directly. -#if defined(queue) -#undef queue -#endif - #include "llappviewer.h" #include "lltrans.h" @@ -75,111 +64,6 @@ namespace boost // nothing. static LLXMLRPCListener listener("LLXMLRPCTransaction"); -LLXMLRPCValue LLXMLRPCValue::operator[](const char* id) const -{ - return LLXMLRPCValue(XMLRPC_VectorGetValueWithID(mV, id)); -} - -std::string LLXMLRPCValue::asString() const -{ - const char* s = XMLRPC_GetValueString(mV); - return s ? s : ""; -} - -int LLXMLRPCValue::asInt() const { return XMLRPC_GetValueInt(mV); } -bool LLXMLRPCValue::asBool() const { return XMLRPC_GetValueBoolean(mV) != 0; } -double LLXMLRPCValue::asDouble() const { return XMLRPC_GetValueDouble(mV); } - -LLXMLRPCValue LLXMLRPCValue::rewind() -{ - return LLXMLRPCValue(XMLRPC_VectorRewind(mV)); -} - -LLXMLRPCValue LLXMLRPCValue::next() -{ - return LLXMLRPCValue(XMLRPC_VectorNext(mV)); -} - -bool LLXMLRPCValue::isValid() const -{ - return mV != NULL; -} - -LLXMLRPCValue LLXMLRPCValue::createArray() -{ - return LLXMLRPCValue(XMLRPC_CreateVector(NULL, xmlrpc_vector_array)); -} - -LLXMLRPCValue LLXMLRPCValue::createStruct() -{ - return LLXMLRPCValue(XMLRPC_CreateVector(NULL, xmlrpc_vector_struct)); -} - - -void LLXMLRPCValue::append(LLXMLRPCValue& v) -{ - XMLRPC_AddValueToVector(mV, v.mV); -} - -void LLXMLRPCValue::appendString(const std::string& v) -{ - XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueString(NULL, v.c_str(), 0)); -} - -void LLXMLRPCValue::appendInt(int v) -{ - XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueInt(NULL, v)); -} - -void LLXMLRPCValue::appendBool(bool v) -{ - XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueBoolean(NULL, v)); -} - -void LLXMLRPCValue::appendDouble(double v) -{ - XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueDouble(NULL, v)); -} - - -void LLXMLRPCValue::append(const char* id, LLXMLRPCValue& v) -{ - XMLRPC_SetValueID(v.mV, id, 0); - XMLRPC_AddValueToVector(mV, v.mV); -} - -void LLXMLRPCValue::appendString(const char* id, const std::string& v) -{ - XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueString(id, v.c_str(), 0)); -} - -void LLXMLRPCValue::appendInt(const char* id, int v) -{ - XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueInt(id, v)); -} - -void LLXMLRPCValue::appendBool(const char* id, bool v) -{ - XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueBoolean(id, v)); -} - -void LLXMLRPCValue::appendDouble(const char* id, double v) -{ - XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueDouble(id, v)); -} - -void LLXMLRPCValue::cleanup() -{ - XMLRPC_CleanupValue(mV); - mV = NULL; -} - -XMLRPC_VALUE LLXMLRPCValue::getValue() const -{ - return mV; -} - - class LLXMLRPCTransaction::Handler : public LLCore::HttpHandler { public: @@ -192,6 +76,9 @@ public: private: + bool parseResponse(LLXMLNodePtr root); + bool parseValue(LLSD& target, LLXMLNodePtr source); + LLXMLRPCTransaction::Impl *mImpl; LLCore::HttpRequest::ptr_t mRequest; }; @@ -213,26 +100,26 @@ public: LLCore::HttpHandle mPostH; std::string mURI; - std::string mProxyAddress; std::string mResponseText; - XMLRPC_REQUEST mResponse; - std::string mCertStore; - LLSD mErrorCertData; + LLSD mResponseData; - Impl(const std::string& uri, XMLRPC_REQUEST request, bool useGzip, const LLSD& httpParams); - Impl(const std::string& uri, - const std::string& method, LLXMLRPCValue params, bool useGzip); - ~Impl(); + std::string mCertStore; + LLSD mErrorCertData; + + Impl + ( + const std::string& uri, + const std::string& method, + const LLSD& params, + const LLSD& httpParams + ); bool process(); void setStatus(EStatus code, const std::string& message = "", const std::string& uri = ""); void setHttpStatus(const LLCore::HttpStatus &status); - -private: - void init(XMLRPC_REQUEST request, bool useGzip, const LLSD& httpParams); }; LLXMLRPCTransaction::Handler::Handler(LLCore::HttpRequest::ptr_t &request, @@ -275,89 +162,113 @@ void LLXMLRPCTransaction::Handler::onCompleted(LLCore::HttpHandle handle, mImpl->setStatus(LLXMLRPCTransaction::StatusComplete); mImpl->mTransferStats = response->getTransferStats(); - // the contents of a buffer array are potentially noncontiguous, so we + // The contents of a buffer array are potentially noncontiguous, so we // will need to copy them into an contiguous block of memory for XMLRPC. LLCore::BufferArray *body = response->getBody(); - char * bodydata = new char[body->size()]; + mImpl->mResponseText.resize(body->size()); - body->read(0, bodydata, body->size()); + body->read(0, mImpl->mResponseText.data(), body->size()); - mImpl->mResponse = XMLRPC_REQUEST_FromXML(bodydata, static_cast(body->size()), 0); - - delete[] bodydata; - - bool hasError = false; - bool hasFault = false; - int faultCode = 0; - std::string faultString; - - LLXMLRPCValue error(XMLRPC_RequestGetError(mImpl->mResponse)); - if (error.isValid()) + LLXMLNodePtr root; + if (!LLXMLNode::parseBuffer(mImpl->mResponseText.data(), body->size(), root, nullptr)) { - hasError = true; - faultCode = error["faultCode"].asInt(); - faultString = error["faultString"].asString(); - } - else if (XMLRPC_ResponseIsFault(mImpl->mResponse)) - { - hasFault = true; - faultCode = XMLRPC_GetResponseFaultCode(mImpl->mResponse); - faultString = XMLRPC_GetResponseFaultString(mImpl->mResponse); + LL_WARNS() << "Failed parsing XML response; request URI: " << mImpl->mURI << LL_ENDL; + return; } - if (hasError || hasFault) - { - mImpl->setStatus(LLXMLRPCTransaction::StatusXMLRPCError); + if (!parseResponse(root)) + return; - LL_WARNS() << "LLXMLRPCTransaction XMLRPC " - << (hasError ? "error " : "fault ") - << faultCode << ": " - << faultString << LL_ENDL; - LL_WARNS() << "LLXMLRPCTransaction request URI: " - << mImpl->mURI << LL_ENDL; + LL_INFOS() << "XML response parsed successfully; request URI: " << mImpl->mURI << LL_ENDL; +} + +struct XMLTreeNode final : public LLSD::TreeNode +{ + XMLTreeNode(const LLXMLNodePtr impl) + : mImpl(impl) + , mFirstChild(impl ? create(impl->getFirstChild()) : nullptr) + , mNextSibling(impl ? create(impl->getNextSibling()) : nullptr) + { } + static XMLTreeNode* create(LLXMLNodePtr node) { return node ? new XMLTreeNode(node) : nullptr; } + + virtual bool hasName(const LLSD::String& name) const override { return mImpl && mImpl->hasName(name); } + virtual LLSD::String getTextContents() const override { return mImpl ? mImpl->getTextContents() : LLStringUtil::null; } + virtual TreeNode* getFirstChild() const override { return mFirstChild.get(); } + virtual TreeNode* getNextSibling() const override { return mNextSibling.get(); } + +private: + const LLXMLNodePtr mImpl; + const std::shared_ptr mFirstChild; + const std::shared_ptr mNextSibling; +}; + +bool LLXMLRPCTransaction::Handler::parseResponse(LLXMLNodePtr root) +{ + // We have alreasy checked in LLXMLNode::parseBuffer() + // that root contains exactly one child + if (!root->hasName("methodResponse")) + { + LL_WARNS() << "Invalid root element in XML response; request URI: " << mImpl->mURI << LL_ENDL; + return false; + } + + LLXMLNodePtr first = root->getFirstChild(); + LLXMLNodePtr second = first->getFirstChild(); + if (!first->getNextSibling() && second && !second->getNextSibling()) + { + if (first->hasName("fault")) + { + LLSD fault; + if (parseValue(fault, second) && + fault.isMap() && fault.has("faultCode") && fault.has("faultString")) + { + LL_WARNS() << "Request failed;" + << " faultCode: '" << fault.get("faultCode").asString() << "'," + << " faultString: '" << fault.get("faultString").asString() << "'," + << " request URI: " << mImpl->mURI << LL_ENDL; + return false; + } + } + else if (first->hasName("params") && + second->hasName("param") && !second->getNextSibling()) + { + LLXMLNodePtr third = second->getFirstChild(); + if (third && !third->getNextSibling() && parseValue(mImpl->mResponseData, third)) + { + return true; + } + } + } + + LL_WARNS() << "Invalid response format; request URI: " << mImpl->mURI << LL_ENDL; + + return false; +} + +bool LLXMLRPCTransaction::Handler::parseValue(LLSD& target, LLXMLNodePtr source) +{ + XMLTreeNode tn(source); + return target.fromXMLRPCValue(&tn); } //========================================================================= -LLXMLRPCTransaction::Impl::Impl(const std::string& uri, - XMLRPC_REQUEST request, bool useGzip, const LLSD& httpParams) - : mHttpRequest(), - mStatus(LLXMLRPCTransaction::StatusNotStarted), - mURI(uri), - mResponse(0) -{ - init(request, useGzip, httpParams); -} - - -LLXMLRPCTransaction::Impl::Impl(const std::string& uri, - const std::string& method, LLXMLRPCValue params, bool useGzip) - : mHttpRequest(), - mStatus(LLXMLRPCTransaction::StatusNotStarted), - mURI(uri), - mResponse(0) -{ - XMLRPC_REQUEST request = XMLRPC_RequestNew(); - XMLRPC_RequestSetMethodName(request, method.c_str()); - XMLRPC_RequestSetRequestType(request, xmlrpc_request_call); - XMLRPC_RequestSetData(request, params.getValue()); - - init(request, useGzip, LLSD()); - // DEV-28398: without this XMLRPC_RequestFree() call, it looks as though - // the 'request' object is simply leaked. It's less clear to me whether we - // should also ask to free request value data (second param 1), since the - // data come from 'params'. - XMLRPC_RequestFree(request, 1); -} - -void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip, const LLSD& httpParams) +LLXMLRPCTransaction::Impl::Impl +( + const std::string& uri, + const std::string& method, + const LLSD& params, + const LLSD& http_params +) + : mHttpRequest() + , mStatus(LLXMLRPCTransaction::StatusNotStarted) + , mURI(uri) { LLCore::HttpOptions::ptr_t httpOpts; LLCore::HttpHeaders::ptr_t httpHeaders; - if (!mHttpRequest) { mHttpRequest = LLCore::HttpRequest::ptr_t(new LLCore::HttpRequest); @@ -366,37 +277,34 @@ void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip, const // LLRefCounted starts with a 1 ref, so don't add a ref in the smart pointer httpOpts = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()); - // delay between repeats will start from 5 sec and grow to 20 sec with each repeat + // Delay between repeats will start from 5 sec and grow to 20 sec with each repeat httpOpts->setMinBackoff(5E6L); httpOpts->setMaxBackoff(20E6L); - httpOpts->setTimeout(httpParams.has("timeout") ? httpParams["timeout"].asInteger() : 40L); - if (httpParams.has("retries")) + httpOpts->setTimeout(http_params.has("timeout") ? http_params["timeout"].asInteger() : 40L); + if (http_params.has("retries")) { - httpOpts->setRetries(httpParams["retries"].asInteger()); + httpOpts->setRetries(http_params["retries"].asInteger()); } - if (httpParams.has("DNSCacheTimeout")) + if (http_params.has("DNSCacheTimeout")) { - httpOpts->setDNSCacheTimeout(httpParams["DNSCacheTimeout"].asInteger()); + httpOpts->setDNSCacheTimeout(http_params["DNSCacheTimeout"].asInteger()); } bool vefifySSLCert = !gSavedSettings.getBOOL("NoVerifySSLCert"); mCertStore = gSavedSettings.getString("CertStore"); - httpOpts->setSSLVerifyPeer( vefifySSLCert ); - httpOpts->setSSLVerifyHost( vefifySSLCert ? 2 : 0); + httpOpts->setSSLVerifyPeer(vefifySSLCert); + httpOpts->setSSLVerifyHost(vefifySSLCert ? 2 : 0); // LLRefCounted starts with a 1 ref, so don't add a ref in the smart pointer httpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()); httpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_TEXT_XML); - std::string user_agent = stringize( - LLVersionInfo::instance().getChannel(), ' ', - LLVersionInfo::instance().getMajor(), '.', - LLVersionInfo::instance().getMinor(), '.', - LLVersionInfo::instance().getPatch(), " (", - LLVersionInfo::instance().getBuild(), ')'); + const LLVersionInfo& vi(LLVersionInfo::instance()); + std::string user_agent = vi.getChannel() + llformat(" %d.%d.%d (%llu)", + vi.getMajor(), vi.getMinor(), vi.getPatch(), vi.getBuild()); httpHeaders->append(HTTP_OUT_HEADER_USER_AGENT, user_agent); @@ -404,31 +312,19 @@ void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip, const //This might help with bug #503 */ //httpOpts->setDNSCacheTimeout(-1); + std::string request = + "" + method + + "" + params.asXMLRPCValue() + + ""; + LLCore::BufferArray::ptr_t body = LLCore::BufferArray::ptr_t(new LLCore::BufferArray()); - // TODO: See if there is a way to serialize to a preallocated buffer I'm - // not fond of the copy here. - int requestSize(0); - char * requestText = XMLRPC_REQUEST_ToXML(request, &requestSize); + body->append(request.c_str(), request.size()); - body->append(requestText, requestSize); - - XMLRPC_Free(requestText); - - mHandler = LLXMLRPCTransaction::Handler::ptr_t(new Handler( mHttpRequest, this )); + mHandler = LLXMLRPCTransaction::Handler::ptr_t(new Handler(mHttpRequest, this)); mPostH = mHttpRequest->requestPost(LLCore::HttpRequest::DEFAULT_POLICY_ID, mURI, body.get(), httpOpts, httpHeaders, mHandler); - -} - - -LLXMLRPCTransaction::Impl::~Impl() -{ - if (mResponse) - { - XMLRPC_RequestFree(mResponse, 1); - } } bool LLXMLRPCTransaction::Impl::process() @@ -539,18 +435,16 @@ void LLXMLRPCTransaction::Impl::setHttpStatus(const LLCore::HttpStatus &status) } - -LLXMLRPCTransaction::LLXMLRPCTransaction( - const std::string& uri, XMLRPC_REQUEST request, bool useGzip, const LLSD& httpParams) -: impl(* new Impl(uri, request, useGzip, httpParams)) -{ } - - -LLXMLRPCTransaction::LLXMLRPCTransaction( +LLXMLRPCTransaction::LLXMLRPCTransaction +( const std::string& uri, - const std::string& method, LLXMLRPCValue params, bool useGzip) -: impl(* new Impl(uri, method, params, useGzip)) -{ } + const std::string& method, + const LLSD& params, + const LLSD& http_params +) +: impl(*new Impl(uri, method, params, http_params)) +{ +} LLXMLRPCTransaction::~LLXMLRPCTransaction() { @@ -590,14 +484,9 @@ std::string LLXMLRPCTransaction::statusURI() return impl.mStatusURI; } -XMLRPC_REQUEST LLXMLRPCTransaction::response() +const LLSD& LLXMLRPCTransaction::response() { - return impl.mResponse; -} - -LLXMLRPCValue LLXMLRPCTransaction::responseValue() -{ - return LLXMLRPCValue(XMLRPC_RequestGetData(impl.mResponse)); + return impl.mResponseData; } diff --git a/indra/newview/llxmlrpctransaction.h b/indra/newview/llxmlrpctransaction.h index 4c8796f936..f7a38f5f90 100644 --- a/indra/newview/llxmlrpctransaction.h +++ b/indra/newview/llxmlrpctransaction.h @@ -29,73 +29,22 @@ #include -typedef struct _xmlrpc_request* XMLRPC_REQUEST; -typedef struct _xmlrpc_value* XMLRPC_VALUE; - // foward decl of types from xmlrpc.h (this usage is type safe) -class LLCertificate; - -class LLXMLRPCValue - // a c++ wrapper around XMLRPC_VALUE -{ -public: - LLXMLRPCValue() : mV(NULL) { } - LLXMLRPCValue(XMLRPC_VALUE value) : mV(value) { } - - bool isValid() const; - - std::string asString() const; - int asInt() const; - bool asBool() const; - double asDouble() const; - - LLXMLRPCValue operator[](const char*) const; - - LLXMLRPCValue rewind(); - LLXMLRPCValue next(); - - static LLXMLRPCValue createArray(); - static LLXMLRPCValue createStruct(); - - void append(LLXMLRPCValue&); - void appendString(const std::string&); - void appendInt(int); - void appendBool(bool); - void appendDouble(double); - void appendValue(LLXMLRPCValue&); - - void append(const char*, LLXMLRPCValue&); - void appendString(const char*, const std::string&); - void appendInt(const char*, int); - void appendBool(const char*, bool); - void appendDouble(const char*, double); - void appendValue(const char*, LLXMLRPCValue&); - - void cleanup(); - // only call this on the top level created value - - XMLRPC_VALUE getValue() const; - -private: - XMLRPC_VALUE mV; -}; - - +/// An asynchronous request and responses via XML-RPC class LLXMLRPCTransaction - // an asynchronous request and responses via XML-RPC { public: - LLXMLRPCTransaction(const std::string& uri, - XMLRPC_REQUEST request, bool useGzip = true, const LLSD& httpParams = LLSD()); - // does not take ownership of the request object - // request can be freed as soon as the transaction is constructed - - LLXMLRPCTransaction(const std::string& uri, - const std::string& method, LLXMLRPCValue params, bool useGzip = true); - // *does* take control of the request value, you must not free it + LLXMLRPCTransaction + ( + const std::string& uri, + const std::string& method, + const LLSD& params, + const LLSD& http_params = LLSD() + ); ~LLXMLRPCTransaction(); - typedef enum e_status { + typedef enum e_status + { StatusNotStarted, StatusStarted, StatusDownloading, @@ -105,26 +54,25 @@ public: StatusOtherError } EStatus; + /// Run the request a little, returns true when done bool process(); - // run the request a little, returns true when done + /// Return a status, and extended CURL code, if code isn't null EStatus status(int* curlCode); - // return status, and extended CURL code, if code isn't null LLSD getErrorCertData(); + + /// Return a message string, suitable for showing the user std::string statusMessage(); - // return a message string, suitable for showing the user + + /// Return a URI for the user with more information (can be empty) std::string statusURI(); - // return a URI for the user with more information - // can be empty - XMLRPC_REQUEST response(); - LLXMLRPCValue responseValue(); - // only valid if StatusComplete, otherwise NULL - // retains ownership of the result object, don't free it + /// Only non-empty if StatusComplete, otherwise Undefined + const LLSD& response(); + /// Only valid if StsatusComplete, otherwise 0.0 F64 transferRate(); - // only valid if StsatusComplete, otherwise 0.0 private: class Handler; @@ -133,6 +81,4 @@ private: Impl& impl; }; - - #endif // LLXMLRPCTRANSACTION_H diff --git a/indra/newview/skins/default/xui/da/floater_about.xml b/indra/newview/skins/default/xui/da/floater_about.xml index 7bcae69779..604eb7c58f 100644 --- a/indra/newview/skins/default/xui/da/floater_about.xml +++ b/indra/newview/skins/default/xui/da/floater_about.xml @@ -69,7 +69,6 @@ OpenSSL Copyright (C) 1998-2002 The OpenSSL Project. PCRE Copyright (c) 1997-2008 University of Cambridge SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) -xmlrpc-epi Copyright (C) 2000 Epinions, Inc. xxHash Copyright (C) 2012-2020 Yann Collet. zlib Copyright (C) 1995-2002 Jean-loup Gailly and Mark Adler. google-perftools Copyright (c) 2005, Google Inc. diff --git a/indra/newview/skins/default/xui/de/floater_about.xml b/indra/newview/skins/default/xui/de/floater_about.xml index 10ccf0d5da..320db7f654 100644 --- a/indra/newview/skins/default/xui/de/floater_about.xml +++ b/indra/newview/skins/default/xui/de/floater_about.xml @@ -28,7 +28,6 @@ mit Open-Source-Beiträgen von: PCRE Copyright (c) 1997-2012 University of Cambridge. SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga. SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com). - xmlrpc-epi Copyright (C) 2000 Epinions, Inc. xxHash Copyright (C) 2012-2020 Yann Collet. zlib Copyright (C) 1995-2012 Jean-loup Gailly und Mark Adler. diff --git a/indra/newview/skins/default/xui/en/floater_about.xml b/indra/newview/skins/default/xui/en/floater_about.xml index ff2fa93cbb..126cd84d56 100644 --- a/indra/newview/skins/default/xui/en/floater_about.xml +++ b/indra/newview/skins/default/xui/en/floater_about.xml @@ -111,7 +111,6 @@ Dummy Name replaced at run time PCRE Copyright (c) 1997-2012 University of Cambridge SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) - xmlrpc-epi Copyright (C) 2000 Epinions, Inc. xxHash Copyright (C) 2012-2020 Yann Collet. zlib Copyright (C) 1995-2012 Jean-loup Gailly and Mark Adler. diff --git a/indra/newview/skins/default/xui/es/floater_about.xml b/indra/newview/skins/default/xui/es/floater_about.xml index e14ba32f69..8103a95376 100644 --- a/indra/newview/skins/default/xui/es/floater_about.xml +++ b/indra/newview/skins/default/xui/es/floater_about.xml @@ -28,7 +28,6 @@ con contribuciones de código abierto de: PCRE Copyright (c) 1997-2012 University of Cambridge SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) - xmlrpc-epi Copyright (C) 2000 Epinions, Inc. xxHash Copyright (C) 2012-2020 Yann Collet. zlib Copyright (C) 1995-2012 Jean-loup Gailly y Mark Adler. diff --git a/indra/newview/skins/default/xui/fr/floater_about.xml b/indra/newview/skins/default/xui/fr/floater_about.xml index 09da1fb5fd..b6ea621177 100644 --- a/indra/newview/skins/default/xui/fr/floater_about.xml +++ b/indra/newview/skins/default/xui/fr/floater_about.xml @@ -28,7 +28,6 @@ avec les contributions Open Source de : PCRE Copyright (c) 1997-2012 University of Cambridge SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) - xmlrpc-epi Copyright (C) 2000 Epinions, Inc. xxHash Copyright (C) 2012-2020 Yann Collet. zlib Copyright (C) 1995-2012 Jean-Loup Gailly et Mark Adler. diff --git a/indra/newview/skins/default/xui/it/floater_about.xml b/indra/newview/skins/default/xui/it/floater_about.xml index 7e195d3ca9..77be47d749 100644 --- a/indra/newview/skins/default/xui/it/floater_about.xml +++ b/indra/newview/skins/default/xui/it/floater_about.xml @@ -28,7 +28,6 @@ con contributi open source da: PCRE Copyright (c) 1997-2012 University of Cambridge SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) - xmlrpc-epi Copyright (C) 2000 Epinions, Inc. xxHash Copyright (C) 2012-2020 Yann Collet. zlib Copyright (C) 1995-2012 Jean-loup Gailly e Mark Adler. diff --git a/indra/newview/skins/default/xui/ja/floater_about.xml b/indra/newview/skins/default/xui/ja/floater_about.xml index 12d763be37..6cd22f6a31 100644 --- a/indra/newview/skins/default/xui/ja/floater_about.xml +++ b/indra/newview/skins/default/xui/ja/floater_about.xml @@ -33,7 +33,6 @@ OpenSSL Copyright (C) 1998-2008 The OpenSSL Project. PCRE Copyright (c) 1997-2012 University of Cambridge SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) -xmlrpc-epi Copyright (C) 2000 Epinions, Inc. xxHash Copyright (C) 2012-2020 Yann Collet. zlib Copyright (C) 1995-2012 Jean-loup Gailly and Mark Adler. diff --git a/indra/newview/skins/default/xui/pt/floater_about.xml b/indra/newview/skins/default/xui/pt/floater_about.xml index aaed728f84..0e95c53109 100644 --- a/indra/newview/skins/default/xui/pt/floater_about.xml +++ b/indra/newview/skins/default/xui/pt/floater_about.xml @@ -28,7 +28,6 @@ com contribuições de código aberto de: PCRE Copyright (c) 1997-2012 University of Cambridge SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) - xmlrpc-epi Copyright (C) 2000 Epinions, Inc. xxHash Copyright (C) 2012-2020 Yann Collet. zlib Copyright (C) 1995-2012 Jean-loup Gailly and Mark Adler. diff --git a/indra/newview/skins/default/xui/ru/floater_about.xml b/indra/newview/skins/default/xui/ru/floater_about.xml index a65a979ccd..22827bc397 100644 --- a/indra/newview/skins/default/xui/ru/floater_about.xml +++ b/indra/newview/skins/default/xui/ru/floater_about.xml @@ -28,7 +28,6 @@ PCRE (c) 1997-2012, Кембриджский университет SDL (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga SSLeay (C) 1995-1998 Eric Young (eay@cryptsoft.com) - xmlrpc-epi (C) 2000 Epinions, Inc. xxHash Copyright (C) 2012-2020 Yann Collet. zlib (C) 1995-2012 Jean-loup Gailly и Mark Adler. diff --git a/indra/newview/skins/default/xui/tr/floater_about.xml b/indra/newview/skins/default/xui/tr/floater_about.xml index 40ca3707c3..ca21bee464 100644 --- a/indra/newview/skins/default/xui/tr/floater_about.xml +++ b/indra/newview/skins/default/xui/tr/floater_about.xml @@ -28,7 +28,6 @@ açık kaynak kod katkısında bulunanlar şunlardır: PCRE Telif Hakkı (c) 1997-2012 University of Cambridge SDL Telif Hakkı (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga SSLeay Telif Hakkı (C) 1995-1998 Eric Young (eay@cryptsoft.com) - xmlrpc-epi Telif Hakkı (C) 2000 Epinions, Inc. xxHash Copyright (C) 2012-2020 Yann Collet. zlib Telif Hakkı (C) 1995-2012 Jean-loup Gailly ve Mark Adler. diff --git a/indra/newview/skins/default/xui/zh/floater_about.xml b/indra/newview/skins/default/xui/zh/floater_about.xml index a56ae753d1..727f598894 100644 --- a/indra/newview/skins/default/xui/zh/floater_about.xml +++ b/indra/newview/skins/default/xui/zh/floater_about.xml @@ -28,7 +28,6 @@ PCRE Copyright (c) 1997-2012 University of Cambridge SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) - xmlrpc-epi Copyright (C) 2000 Epinions, Inc. xxHash Copyright (C) 2012-2020 Yann Collet. zlib Copyright (C) 1995-2012 Jean-loup Gailly and Mark Adler. diff --git a/indra/viewer_components/login/lllogin.cpp b/indra/viewer_components/login/lllogin.cpp index 2a0468f3ad..48fecb4f22 100644 --- a/indra/viewer_components/login/lllogin.cpp +++ b/indra/viewer_components/login/lllogin.cpp @@ -66,6 +66,16 @@ public: LLEventPump& getEventPump() { return mPump; } private: + LLSD hidePasswd(const LLSD& data) + { + LLSD result(data); + if (result.has("params") && result["params"].has("passwd")) + { + result["params"]["passwd"] = "*******"; + } + return result; + } + LLSD getProgressEventLLSD(const std::string& state, const std::string& change, const LLSD& data = LLSD()) { @@ -74,15 +84,16 @@ private: status_data["change"] = change; status_data["progress"] = 0.0f; - if(mAuthResponse.has("transfer_rate")) + if (mAuthResponse.has("transfer_rate")) { status_data["transfer_rate"] = mAuthResponse["transfer_rate"]; } - if(data.isDefined()) + if (data.isDefined()) { status_data["data"] = data; } + return status_data; } @@ -119,17 +130,18 @@ private: void LLLogin::Impl::connect(const std::string& uri, const LLSD& login_params) { - LL_DEBUGS("LLLogin") << " connect with uri '" << uri << "', login_params " << login_params << LL_ENDL; + LL_DEBUGS("LLLogin") << " connect with uri '" << uri << "', login_params " << login_params << LL_ENDL; // Launch a coroutine with our login_() method. Run the coroutine until // its first wait; at that point, return here. std::string coroname = - LLCoros::instance().launch("LLLogin::Impl::login_", - boost::bind(&Impl::loginCoro, this, uri, login_params)); - LL_DEBUGS("LLLogin") << " connected with uri '" << uri << "', login_params " << login_params << LL_ENDL; + LLCoros::instance().launch("LLLogin::Impl::login_", [&]() { loginCoro(uri, login_params); }); + + LL_DEBUGS("LLLogin") << " connected with uri '" << uri << "', login_params " << login_params << LL_ENDL; } -namespace { +namespace +{ // Instantiate this rendezvous point at namespace scope so it's already // present no matter how early the updater might post to it. // Use an LLEventMailDrop, which has future-like semantics: regardless of the @@ -140,12 +152,8 @@ static LLEventMailDrop sSyncPoint("LoginSync"); void LLLogin::Impl::loginCoro(std::string uri, LLSD login_params) { - LLSD printable_params = login_params; - if (printable_params.has("params") - && printable_params["params"].has("passwd")) - { - printable_params["params"]["passwd"] = "*******"; - } + LLSD printable_params = hidePasswd(login_params); + try { LL_DEBUGS("LLLogin") << "Entering coroutine " << LLCoros::getName() @@ -171,12 +179,7 @@ void LLLogin::Impl::loginCoro(std::string uri, LLSD login_params) ++attempts; LLSD progress_data; progress_data["attempt"] = attempts; - progress_data["request"] = request; - if (progress_data["request"].has("params") - && progress_data["request"]["params"].has("passwd")) - { - progress_data["request"]["params"]["passwd"] = "*******"; - } + progress_data["request"] = hidePasswd(request); sendProgressEvent("offline", "authenticating", progress_data); // We expect zero or more "Downloading" status events, followed by From 5a60b7811fb666f2ef59abc57a3204297f6aaa1a Mon Sep 17 00:00:00 2001 From: Cosmic Linden Date: Fri, 28 Jun 2024 14:54:53 -0700 Subject: [PATCH 29/30] secondlife/viewer#1847: Fix wrong lighting for negative texture scale on PBR materials and PBR terrain --- .../shaders/class1/deferred/pbralphaV.glsl | 7 +- .../shaders/class1/deferred/pbropaqueV.glsl | 7 +- .../shaders/class1/deferred/pbrterrainF.glsl | 29 ++++++-- .../class1/deferred/pbrterrainUtilF.glsl | 12 ++- .../shaders/class1/deferred/pbrterrainV.glsl | 23 ++++-- .../shaders/class1/deferred/textureUtilV.glsl | 74 +++++++++++++------ 6 files changed, 105 insertions(+), 47 deletions(-) diff --git a/indra/newview/app_settings/shaders/class1/deferred/pbralphaV.glsl b/indra/newview/app_settings/shaders/class1/deferred/pbralphaV.glsl index ae179d3f37..66adf50fa9 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/pbralphaV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/pbralphaV.glsl @@ -69,7 +69,7 @@ flat out float vary_sign; out vec3 vary_normal; vec2 texture_transform(vec2 vertex_texcoord, vec4[2] khr_gltf_transform, mat4 sl_animation_transform); -vec3 tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] khr_gltf_transform, mat4 sl_animation_transform); +vec4 tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] khr_gltf_transform, mat4 sl_animation_transform); void main() @@ -103,8 +103,9 @@ void main() n = normalize(n); - vary_tangent = normalize(tangent_space_transform(vec4(t, tangent.w), n, texture_normal_transform, texture_matrix0)); - vary_sign = tangent.w; + vec4 transformed_tangent = tangent_space_transform(vec4(t, tangent.w), n, texture_normal_transform, texture_matrix0); + vary_tangent = normalize(transformed_tangent.xyz); + vary_sign = transformed_tangent.w; vary_normal = n; vertex_color = diffuse_color; diff --git a/indra/newview/app_settings/shaders/class1/deferred/pbropaqueV.glsl b/indra/newview/app_settings/shaders/class1/deferred/pbropaqueV.glsl index fd020afd57..0ad9bf5e4b 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/pbropaqueV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/pbropaqueV.glsl @@ -63,7 +63,7 @@ out vec3 vary_normal; out vec3 vary_position; vec2 texture_transform(vec2 vertex_texcoord, vec4[2] khr_gltf_transform, mat4 sl_animation_transform); -vec3 tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] khr_gltf_transform, mat4 sl_animation_transform); +vec4 tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] khr_gltf_transform, mat4 sl_animation_transform); void main() { @@ -97,8 +97,9 @@ void main() n = normalize(n); - vary_tangent = normalize(tangent_space_transform(vec4(t, tangent.w), n, texture_normal_transform, texture_matrix0)); - vary_sign = tangent.w; + vec4 transformed_tangent = tangent_space_transform(vec4(t, tangent.w), n, texture_normal_transform, texture_matrix0); + vary_tangent = normalize(transformed_tangent.xyz); + vary_sign = transformed_tangent.w; vary_normal = n; vertex_color = diffuse_color; diff --git a/indra/newview/app_settings/shaders/class1/deferred/pbrterrainF.glsl b/indra/newview/app_settings/shaders/class1/deferred/pbrterrainF.glsl index 2cb7ff196b..6ca35419f2 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/pbrterrainF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/pbrterrainF.glsl @@ -75,6 +75,9 @@ PBRMix terrain_sample_and_multiply_pbr( #endif #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) , sampler2D tex_vNt +#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3 + , float transform_sign +#endif #endif #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) , sampler2D tex_emissive @@ -139,7 +142,7 @@ in vec3 vary_position; in vec3 vary_normal; #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) in vec3 vary_tangents[4]; -flat in float vary_sign; +flat in float vary_signs[4]; #endif in vec4 vary_texcoord0; in vec4 vary_texcoord1; @@ -150,11 +153,11 @@ float terrain_mix(TerrainMix tm, vec4 tms4); #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) // from mikktspace.com -vec3 mikktspace(vec3 vNt, vec3 vT) +vec3 mikktspace(vec3 vNt, vec3 vT, float sign) { vec3 vN = vary_normal; - vec3 vB = vary_sign * cross(vN, vT); + vec3 vB = sign * cross(vN, vT); vec3 tnorm = normalize( vNt.x * vT + vNt.y * vB + vNt.z * vN ); tnorm *= gl_FrontFacing ? 1.0 : -1.0; @@ -216,6 +219,9 @@ void main() #endif #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) , detail_0_normal +#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3 + , vary_signs[0] +#endif #endif #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) , detail_0_emissive @@ -231,7 +237,7 @@ void main() #endif ); #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) - mix2.vNt = mikktspace(mix2.vNt, vary_tangents[0]); + mix2.vNt = mikktspace(mix2.vNt, vary_tangents[0], vary_signs[0]); #endif pbr_mix = mix_pbr(pbr_mix, mix2, tm.weight.x); break; @@ -258,6 +264,9 @@ void main() #endif #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) , detail_1_normal +#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3 + , vary_signs[1] +#endif #endif #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) , detail_1_emissive @@ -273,7 +282,7 @@ void main() #endif ); #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) - mix2.vNt = mikktspace(mix2.vNt, vary_tangents[1]); + mix2.vNt = mikktspace(mix2.vNt, vary_tangents[1], vary_signs[1]); #endif pbr_mix = mix_pbr(pbr_mix, mix2, tm.weight.y); break; @@ -300,6 +309,9 @@ void main() #endif #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) , detail_2_normal +#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3 + , vary_signs[2] +#endif #endif #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) , detail_2_emissive @@ -315,7 +327,7 @@ void main() #endif ); #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) - mix2.vNt = mikktspace(mix2.vNt, vary_tangents[2]); + mix2.vNt = mikktspace(mix2.vNt, vary_tangents[2], vary_signs[2]); #endif pbr_mix = mix_pbr(pbr_mix, mix2, tm.weight.z); break; @@ -342,6 +354,9 @@ void main() #endif #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) , detail_3_normal +#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3 + , vary_signs[3] +#endif #endif #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) , detail_3_emissive @@ -357,7 +372,7 @@ void main() #endif ); #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) - mix2.vNt = mikktspace(mix2.vNt, vary_tangents[3]); + mix2.vNt = mikktspace(mix2.vNt, vary_tangents[3], vary_signs[3]); #endif pbr_mix = mix_pbr(pbr_mix, mix2, tm.weight.w); break; diff --git a/indra/newview/app_settings/shaders/class1/deferred/pbrterrainUtilF.glsl b/indra/newview/app_settings/shaders/class1/deferred/pbrterrainUtilF.glsl index 1ae9efe544..5098de717e 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/pbrterrainUtilF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/pbrterrainUtilF.glsl @@ -256,11 +256,12 @@ vec3 _t_normal_post_1(vec3 vNt0, float sign_or_zero) } // Triplanar-specific normal texture fixes -vec3 _t_normal_post_x(vec3 vNt0) +vec3 _t_normal_post_x(vec3 vNt0, float tangent_sign) { vec3 vNt_x = _t_normal_post_1(vNt0, sign(vary_vertex_normal.x)); // *HACK: Transform normals according to orientation of the UVs vNt_x.xy = vec2(-vNt_x.y, vNt_x.x); + vNt_x.xy *= tangent_sign; return vNt_x; } vec3 _t_normal_post_y(vec3 vNt0) @@ -285,6 +286,7 @@ PBRMix terrain_sample_pbr( #endif #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) , sampler2D tex_vNt + , float tangent_sign #endif #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) , sampler2D tex_emissive @@ -314,7 +316,7 @@ PBRMix terrain_sample_pbr( ); #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) // Triplanar-specific normal texture fix - mix_x.vNt = _t_normal_post_x(mix_x.vNt); + mix_x.vNt = _t_normal_post_x(mix_x.vNt, tangent_sign); #endif mix = mix_pbr(mix, mix_x, tw.weight.x); break; @@ -420,6 +422,9 @@ PBRMix terrain_sample_and_multiply_pbr( #endif #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) , sampler2D tex_vNt +#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3 + , float tangent_sign +#endif #endif #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) , sampler2D tex_emissive @@ -446,6 +451,9 @@ PBRMix terrain_sample_and_multiply_pbr( #endif #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) , tex_vNt +#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3 + , tangent_sign +#endif #endif #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) , tex_emissive diff --git a/indra/newview/app_settings/shaders/class1/deferred/pbrterrainV.glsl b/indra/newview/app_settings/shaders/class1/deferred/pbrterrainV.glsl index f8e826bbdb..c90b2b5926 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/pbrterrainV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/pbrterrainV.glsl @@ -43,7 +43,7 @@ out vec3 vary_vertex_normal; // Used by pbrterrainUtilF.glsl out vec3 vary_normal; #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) out vec3 vary_tangents[4]; -flat out float vary_sign; +flat out float vary_signs[4]; #endif out vec4 vary_texcoord0; out vec4 vary_texcoord1; @@ -60,7 +60,7 @@ out vec3 vary_position; uniform vec4[5] terrain_texture_transforms; vec2 terrain_texture_transform(vec2 vertex_texcoord, vec4[2] khr_gltf_transform); -vec3 terrain_tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] khr_gltf_transform); +vec4 terrain_tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] khr_gltf_transform); void main() { @@ -75,28 +75,35 @@ void main() #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) { vec4[2] ttt; + vec4 transformed_tangent; // material 1 ttt[0].xyz = terrain_texture_transforms[0].xyz; ttt[1].x = terrain_texture_transforms[0].w; ttt[1].y = terrain_texture_transforms[1].x; - vary_tangents[0] = normalize(terrain_tangent_space_transform(vec4(t, tangent.w), n, ttt)); + transformed_tangent = terrain_tangent_space_transform(vec4(t, tangent.w), n, ttt); + vary_tangents[0] = normalize(transformed_tangent.xyz); + vary_signs[0] = transformed_tangent.w; // material 2 ttt[0].xyz = terrain_texture_transforms[1].yzw; ttt[1].xy = terrain_texture_transforms[2].xy; - vary_tangents[1] = normalize(terrain_tangent_space_transform(vec4(t, tangent.w), n, ttt)); + transformed_tangent = terrain_tangent_space_transform(vec4(t, tangent.w), n, ttt); + vary_tangents[1] = normalize(transformed_tangent.xyz); + vary_signs[1] = transformed_tangent.w; // material 3 ttt[0].xy = terrain_texture_transforms[2].zw; ttt[0].z = terrain_texture_transforms[3].x; ttt[1].xy = terrain_texture_transforms[3].yz; - vary_tangents[2] = normalize(terrain_tangent_space_transform(vec4(t, tangent.w), n, ttt)); + transformed_tangent = terrain_tangent_space_transform(vec4(t, tangent.w), n, ttt); + vary_tangents[2] = normalize(transformed_tangent.xyz); + vary_signs[2] = transformed_tangent.w; // material 4 ttt[0].x = terrain_texture_transforms[3].w; ttt[0].yz = terrain_texture_transforms[4].xy; ttt[1].xy = terrain_texture_transforms[4].zw; - vary_tangents[3] = normalize(terrain_tangent_space_transform(vec4(t, tangent.w), n, ttt)); + transformed_tangent = terrain_tangent_space_transform(vec4(t, tangent.w), n, ttt); + vary_tangents[3] = normalize(transformed_tangent.xyz); + vary_signs[3] = transformed_tangent.w; } - - vary_sign = tangent.w; #endif vary_normal = normalize(n); diff --git a/indra/newview/app_settings/shaders/class1/deferred/textureUtilV.glsl b/indra/newview/app_settings/shaders/class1/deferred/textureUtilV.glsl index 767416d564..c75a0e0d5d 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/textureUtilV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/textureUtilV.glsl @@ -94,36 +94,48 @@ vec2 terrain_texture_transform(vec2 vertex_texcoord, vec4[2] khr_gltf_transform) // Take the rotation only from both transforms and apply to the tangent. This // accounts for the change of the topology of the normal texture when a texture // rotation is applied to it. +// In practice, this applies the inverse of the texture transform to the tangent. +// It is effectively an inverse of the rotation // *HACK: Assume the imported GLTF model did not have both normal texture // transforms and tangent vertices. The use of this function is inconsistent // with the GLTF sample viewer when that is the case. See getNormalInfo in // https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Viewer/47a191931461a6f2e14de48d6da0f0eb6ec2d147/source/Renderer/shaders/material_info.glsl // We may want to account for this case during GLTF model import. // -Cosmic,2023-06-06 -vec3 tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] khr_gltf_transform, mat4 sl_animation_transform) +vec4 tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] khr_gltf_transform, mat4 sl_animation_transform) { - vec2 weights = vec2(0, 1); + // Immediately convert to left-handed coordinate system, but it has no + // effect here because y is 0 ((1,0) -> (1,0)) + vec2 weights = vec2(1, 0); - // Apply texture animation first to avoid shearing and other artifacts (rotation only) - mat2 sl_rot_scale; - sl_rot_scale[0][0] = sl_animation_transform[0][0]; - sl_rot_scale[0][1] = sl_animation_transform[0][1]; - sl_rot_scale[1][0] = sl_animation_transform[1][0]; - sl_rot_scale[1][1] = sl_animation_transform[1][1]; - weights = sl_rot_scale * weights; - // Remove scale - weights = normalize(weights); - - // Convert to left-handed coordinate system - weights.y = -weights.y; - - // Apply KHR_texture_transform (rotation only) - float khr_rotation = khr_gltf_transform[0].z; + // Apply inverse KHR_texture_transform (rotation and scale sign only) + float khr_rotation = -khr_gltf_transform[0].z; mat2 khr_rotation_mat = mat2( cos(khr_rotation),-sin(khr_rotation), sin(khr_rotation), cos(khr_rotation) ); weights = khr_rotation_mat * weights; + vec2 khr_scale_sign = sign(khr_gltf_transform[0].xy); + weights *= khr_scale_sign.xy; + + // *NOTE: Delay conversion to right-handed coordinate system here, to + // remove the need for computing the inverse of the SL texture animation + // matrix. + + // Apply texture animation last to avoid shearing and other artifacts (rotation only) + mat2 inv_sl_rot_scale; + inv_sl_rot_scale[0][0] = sl_animation_transform[0][0]; + inv_sl_rot_scale[0][1] = sl_animation_transform[0][1]; + inv_sl_rot_scale[1][0] = sl_animation_transform[1][0]; + inv_sl_rot_scale[1][1] = sl_animation_transform[1][1]; + weights = inv_sl_rot_scale * weights; + // *NOTE: Scale to be removed later + + // Set weights to default if 0 for some reason + weights.x += 1.0 - abs(sign(sign(weights.x) + (0.5 * sign(weights.y)))); + + // Remove scale from SL texture animation transform + weights = normalize(weights); // Convert back to right-handed coordinate system weights.y = -weights.y; @@ -132,27 +144,41 @@ vec3 tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] kh // from the normal and tangent, as seen in the fragment shader vec3 vertex_binormal = vertex_tangent.w * cross(vertex_normal, vertex_tangent.xyz); - return (weights.x * vertex_binormal.xyz) + (weights.y * vertex_tangent.xyz); + // An additional sign flip prevents the binormal from being flipped as a + // result of a propagation of the tangent sign during the cross product. + float sign_flip = khr_scale_sign.x * khr_scale_sign.y; + return vec4((weights.x * vertex_tangent.xyz) + (weights.y * vertex_binormal.xyz), vertex_tangent.w * sign_flip); } // Similar to tangent_space_transform but no texture animation support. -vec3 terrain_tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] khr_gltf_transform) +vec4 terrain_tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] khr_gltf_transform) { - // Immediately convert to left-handed coordinate system ((0,1) -> (0, -1)) - vec2 weights = vec2(0, -1); + // Immediately convert to left-handed coordinate system, but it has no + // effect here because y is 0 ((1,0) -> (1,0)) + vec2 weights = vec2(1, 0); - // Apply KHR_texture_transform (rotation only) - float khr_rotation = khr_gltf_transform[0].z; + // Apply inverse KHR_texture_transform (rotation and scale sign only) + float khr_rotation = -khr_gltf_transform[0].z; mat2 khr_rotation_mat = mat2( cos(khr_rotation),-sin(khr_rotation), sin(khr_rotation), cos(khr_rotation) ); weights = khr_rotation_mat * weights; + vec2 khr_scale_sign = sign(khr_gltf_transform[0].xy); + weights *= khr_scale_sign.xy; + + // Set weights to default if 0 for some reason + weights.x += 1.0 - abs(sign(sign(weights.x) + (0.5 * sign(weights.y)))); // Convert back to right-handed coordinate system weights.y = -weights.y; + // Similar to the MikkTSpace-compatible method of extracting the binormal + // from the normal and tangent, as seen in the fragment shader vec3 vertex_binormal = vertex_tangent.w * cross(vertex_normal, vertex_tangent.xyz); - return (weights.x * vertex_binormal.xyz) + (weights.y * vertex_tangent.xyz); + // An additional sign flip prevents the binormal from being flipped as a + // result of a propagation of the tangent sign during the cross product. + float sign_flip = khr_scale_sign.x * khr_scale_sign.y; + return vec4((weights.x * vertex_tangent.xyz) + (weights.y * vertex_binormal.xyz), vertex_tangent.w * sign_flip); } From 186395ee4b48cf62cbcb484ba4e5d22154942ef5 Mon Sep 17 00:00:00 2001 From: Cosmic Linden Date: Fri, 28 Jun 2024 15:09:42 -0700 Subject: [PATCH 30/30] secondlife/viewer#1847: Add test plan --- doc/testplans/pbr_terrain_appearance.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/doc/testplans/pbr_terrain_appearance.md b/doc/testplans/pbr_terrain_appearance.md index 11b501be3a..770e39204e 100644 --- a/doc/testplans/pbr_terrain_appearance.md +++ b/doc/testplans/pbr_terrain_appearance.md @@ -50,3 +50,14 @@ If triplanar mapping is enabled, and an avatar faces an axially-aligned wall, th Textures of materials should not appear mirrored. When triplanar mapping is enabled, rotations on the axially aligned walls should apply in the same direction as they would on flat ground. + +## PBR Terrain Normal Textures + +This section assumes terrain normal maps are enabled at the current graphics setting. + +PBR terrain should have approximately correct lighting based on the normal texture: + +- When on flat ground +- On cliffs, when triplanar mapping is enabled. Lighting will be somewhat less accurate when the cliff face is not axially aligned. +- If no Terrain Texture Transform is applied. +- If a Terrain Texture Transform is applied, especially for rotation or negative scale.