Merge pull request #4308 from secondlife/geenz/develop-to-gltf-mesh

Geenz/develop to gltf mesh
master
Jonathan "Geenz" Goodman 2025-06-27 23:58:12 -04:00 committed by GitHub
commit 06a9e45fa3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
73 changed files with 2258 additions and 966 deletions

View File

@ -306,7 +306,7 @@ jobs:
AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
needs: build
runs-on: windows-large
runs-on: windows-latest
steps:
- name: Sign and package Windows viewer
if: env.AZURE_KEY_VAULT_URI && env.AZURE_CERT_NAME && env.AZURE_CLIENT_ID && env.AZURE_CLIENT_SECRET && env.AZURE_TENANT_ID

21
.github/workflows/check-pr.yaml vendored Normal file
View File

@ -0,0 +1,21 @@
name: Check PR
on:
pull_request:
types: [opened, edited, reopened, synchronize]
permissions:
contents: read
jobs:
check-description:
runs-on: ubuntu-latest
steps:
- name: Check PR description
uses: actions/github-script@v7
with:
script: |
const description = context.payload.pull_request.body || '';
if (description.trim().length < 20) {
core.setFailed("❌ PR description is too short. Please provide at least 20 characters.");
}

View File

@ -1,174 +1,575 @@
name: Run QA Test # Runs automated tests on a self-hosted QA machine
permissions:
contents: read
#pull-requests: write # maybe need to re-add this later
on:
workflow_run:
workflows: ["Build"]
types:
- completed
concurrency:
group: qa-test-run
cancel-in-progress: true # Cancels any queued job when a new one starts
jobs:
debug-workflow:
runs-on: ubuntu-latest
steps:
- name: Debug Workflow Variables
env:
HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }}
HEAD_COMMIT_MSG: ${{ github.event.workflow_run.head_commit.message }}
run: |
echo "Workflow Conclusion: ${{ github.event.workflow_run.conclusion }}"
echo "Workflow Head Branch: $HEAD_BRANCH"
echo "Workflow Run ID: ${{ github.event.workflow_run.id }}"
echo "Head Commit Message: $HEAD_COMMIT_MSG"
echo "GitHub Ref: ${{ github.ref }}"
echo "GitHub Ref Name: ${{ github.ref_name }}"
echo "GitHub Event Name: ${{ github.event_name }}"
echo "GitHub Workflow Name: ${{ github.workflow }}"
install-viewer-and-run-tests:
runs-on: [self-hosted, qa-machine]
# Run test only on successful builds of Second_Life_X branches
if: >
github.event.workflow_run.conclusion == 'success' &&
(
startsWith(github.event.workflow_run.head_branch, 'Second_Life')
)
steps:
- name: Temporarily Allow PowerShell Scripts (Process Scope)
run: |
Set-ExecutionPolicy RemoteSigned -Scope Process -Force
- name: Verify viewer-sikulix-main Exists
run: |
if (-Not (Test-Path -Path 'C:\viewer-sikulix-main')) {
Write-Host '❌ Error: viewer-sikulix not found on runner!'
exit 1
}
Write-Host '✅ viewer-sikulix is already available.'
- name: Fetch & Download Windows Installer Artifact
shell: pwsh
run: |
$BUILD_ID = "${{ github.event.workflow_run.id }}"
$ARTIFACTS_URL = "https://api.github.com/repos/secondlife/viewer/actions/runs/$BUILD_ID/artifacts"
# Fetch the correct artifact URL
$response = Invoke-RestMethod -Headers @{Authorization="token ${{ secrets.GITHUB_TOKEN }}" } -Uri $ARTIFACTS_URL
$ARTIFACT_NAME = ($response.artifacts | Where-Object { $_.name -eq "Windows-installer" }).archive_download_url
if (-Not $ARTIFACT_NAME) {
Write-Host "❌ Error: Windows-installer artifact not found!"
exit 1
}
Write-Host "✅ Artifact found: $ARTIFACT_NAME"
# Secure download path
$DownloadPath = "$env:TEMP\secondlife-build-$BUILD_ID"
New-Item -ItemType Directory -Path $DownloadPath -Force | Out-Null
$InstallerPath = "$DownloadPath\installer.zip"
# Download the ZIP
Invoke-WebRequest -Uri $ARTIFACT_NAME -Headers @{Authorization="token ${{ secrets.GITHUB_TOKEN }}"} -OutFile $InstallerPath
# Ensure download succeeded
if (-Not (Test-Path $InstallerPath)) {
Write-Host "❌ Error: Failed to download Windows-installer.zip"
exit 1
}
- name: Extract Installer & Locate Executable
shell: pwsh
run: |
# Explicitly set BUILD_ID again (since it does not appear to persist across steps)
$BUILD_ID = "${{ github.event.workflow_run.id }}"
$ExtractPath = "$env:TEMP\secondlife-build-$BUILD_ID"
$InstallerZip = "$ExtractPath\installer.zip"
# Print paths for debugging
Write-Host "Extract Path: $ExtractPath"
Write-Host "Installer ZIP Path: $InstallerZip"
# Verify ZIP exists before extracting
if (-Not (Test-Path $InstallerZip)) {
Write-Host "❌ Error: ZIP file not found at $InstallerZip!"
exit 1
}
Write-Host "✅ ZIP file exists and is valid. Extracting..."
Expand-Archive -Path $InstallerZip -DestinationPath $ExtractPath -Force
# Find installer executable
$INSTALLER_PATH = (Get-ChildItem -Path $ExtractPath -Filter '*.exe' -Recurse | Select-Object -First 1).FullName
if (-Not $INSTALLER_PATH -or $INSTALLER_PATH -eq "") {
Write-Host "❌ Error: No installer executable found in the extracted files!"
Write-Host "📂 Extracted Files:"
Get-ChildItem -Path $ExtractPath -Recurse | Format-Table -AutoSize
exit 1
}
Write-Host "✅ Installer found: $INSTALLER_PATH"
echo "INSTALLER_PATH=$INSTALLER_PATH" | Out-File -FilePath $env:GITHUB_ENV -Append
- name: Install Second Life Using Task Scheduler (Bypass UAC)
shell: pwsh
run: |
$action = New-ScheduledTaskAction -Execute "${{ env.INSTALLER_PATH }}" -Argument "/S"
$principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest
$task = New-ScheduledTask -Action $action -Principal $principal
Register-ScheduledTask -TaskName "SilentSLInstaller" -InputObject $task -Force
Start-ScheduledTask -TaskName "SilentSLInstaller"
- name: Wait for Installation to Complete
shell: pwsh
run: |
Write-Host "Waiting for the Second Life installer to finish..."
do {
Start-Sleep -Seconds 5
$installerProcess = Get-Process | Where-Object { $_.Path -eq "${{ env.INSTALLER_PATH }}" }
} while ($installerProcess)
Write-Host "✅ Installation completed!"
- name: Cleanup Task Scheduler Entry
shell: pwsh
run: |
Unregister-ScheduledTask -TaskName "SilentSLInstaller" -Confirm:$false
Write-Host "✅ Task Scheduler entry removed."
- name: Delete Installer ZIP
shell: pwsh
run: |
# Explicitly set BUILD_ID again
$BUILD_ID = "${{ github.event.workflow_run.id }}"
$DeletePath = "$env:TEMP\secondlife-build-$BUILD_ID\installer.zip"
Write-Host "Checking if installer ZIP exists: $DeletePath"
# Ensure the ZIP file exists before trying to delete it
if (Test-Path $DeletePath) {
Remove-Item -Path $DeletePath -Force
Write-Host "✅ Successfully deleted: $DeletePath"
} else {
Write-Host "⚠️ Warning: ZIP file does not exist, skipping deletion."
}
- name: Run QA Test Script
run: |
Write-Host "Running QA Test script..."
python C:\viewer-sikulix-main\runTests.py
# - name: Upload Test Results
# uses: actions/upload-artifact@v3
# with:
# name: test-results
# path: C:\viewer-sikulix-main\regressionTest\test_results.html
name: Run QA Test # Runs automated tests on self-hosted QA machines
permissions:
contents: read
on:
workflow_run:
workflows: ["Build"]
types:
- completed
workflow_dispatch:
inputs:
build_id:
description: 'Build workflow run ID (e.g. For github.com/secondlife/viewer/actions/runs/1234567890 the ID is 1234567890)'
required: true
default: '14806728332'
jobs:
debug-workflow:
runs-on: ubuntu-latest
steps:
- name: Debug Workflow Variables
run: |
echo "Workflow Conclusion: ${{ github.event.workflow_run.conclusion }}"
echo "Workflow Head Branch: ${{ github.event.workflow_run.head_branch }}"
echo "Workflow Run ID: ${{ github.event.workflow_run.id }}"
echo "Head Commit Message: ${{ github.event.workflow_run.head_commit.message }}"
echo "GitHub Ref: ${{ github.ref }}"
echo "GitHub Ref Name: ${{ github.ref_name }}"
echo "GitHub Event Name: ${{ github.event_name }}"
echo "GitHub Workflow Name: ${{ github.workflow }}"
install-viewer-and-run-tests:
concurrency:
group: ${{ github.workflow }}-${{ matrix.runner }}
cancel-in-progress: false # Prevents cancellation of in-progress jobs
strategy:
matrix:
include:
- os: windows
runner: qa-windows-atlas
artifact: Windows-installer
install-path: 'C:\viewer-automation-main'
- os: windows
runner: qa-dan-asus
artifact: Windows-installer
install-path: 'C:\viewer-automation-main'
# Commented out until mac runner is available
# - os: mac
# runner: qa-mac-atlas
# artifact: Mac-installer
# install-path: '$HOME/Documents/viewer-automation'
fail-fast: false
runs-on: [self-hosted, "${{ matrix.runner }}"]
# Run test only on successful builds of Second_Life_X branches or on manual dispatch
if: >
(github.event_name == 'workflow_run' &&
github.event.workflow_run.conclusion == 'success' &&
startsWith(github.event.workflow_run.head_branch, 'Second_Life')) ||
github.event_name == 'workflow_dispatch'
steps:
# Windows-specific steps
- name: Set Build ID
if: matrix.os == 'windows'
shell: pwsh
run: |
if ("${{ github.event_name }}" -eq "workflow_dispatch") {
echo "BUILD_ID=${{ github.event.inputs.build_id }}" | Out-File -FilePath $env:GITHUB_ENV -Append
echo "ARTIFACTS_URL=https://api.github.com/repos/secondlife/viewer/actions/runs/${{ github.event.inputs.build_id }}/artifacts" | Out-File -FilePath $env:GITHUB_ENV -Append
} else {
echo "BUILD_ID=${{ github.event.workflow_run.id }}" | Out-File -FilePath $env:GITHUB_ENV -Append
echo "ARTIFACTS_URL=https://api.github.com/repos/secondlife/viewer/actions/runs/${{ github.event.workflow_run.id }}/artifacts" | Out-File -FilePath $env:GITHUB_ENV -Append
}
- name: Temporarily Allow PowerShell Scripts (Windows)
if: matrix.os == 'windows'
shell: pwsh
run: |
Set-ExecutionPolicy RemoteSigned -Scope Process -Force
- name: Verify viewer-automation-main Exists (Windows)
if: matrix.os == 'windows'
shell: pwsh
run: |
if (-Not (Test-Path -Path '${{ matrix.install-path }}')) {
Write-Host '❌ Error: viewer-automation folder not found on runner!'
exit 1
}
Write-Host '✅ viewer-automation folder is provided.'
- name: Verify viewer-automation-main is Up-To-Date (Windows)
if: matrix.os == 'windows'
shell: pwsh
continue-on-error: true
run: |
cd ${{ matrix.install-path }}
Write-Host "Checking for repository updates..."
# Check if .git directory exists
if (Test-Path -Path ".git") {
try {
# Save local changes instead of discarding them
git stash push -m "Automated stash before update $(Get-Date)"
Write-Host "Local changes saved (if any)"
# Update the repository
git pull
Write-Host "✅ Repository updated successfully"
# Try to restore local changes if any were stashed
$stashList = git stash list
if ($stashList -match "Automated stash before update") {
try {
git stash pop
Write-Host "✅ Local changes restored successfully"
} catch {
Write-Host "⚠️ Conflict when restoring local changes"
# Save the conflicted state in a new branch for later review
$branchName = "conflict-recovery-$(Get-Date -Format 'yyyyMMdd-HHmmss')"
git checkout -b $branchName
Write-Host "✅ Created branch '$branchName' with conflicted state"
# For test execution, revert to a clean state
git reset --hard HEAD
Write-Host "✅ Reset to clean state for test execution"
}
}
} catch {
Write-Host "⚠️ Could not update repository: $_"
Write-Host "Continuing with existing files..."
}
} else {
Write-Host "⚠️ Not a Git repository, using existing files"
}
- name: Verify Python Installation (Windows)
if: matrix.os == 'windows'
shell: pwsh
run: |
try {
$pythonVersion = (python --version)
Write-Host "✅ Python found: $pythonVersion"
} catch {
Write-Host "❌ Error: Python not found in PATH. Please install Python on this runner."
exit 1
}
- name: Setup Python Virtual Environment (Windows)
if: matrix.os == 'windows'
shell: pwsh
run: |
Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process -Force
cd ${{ matrix.install-path }}
if (-Not (Test-Path -Path ".venv")) {
Write-Host "Creating virtual environment..."
python -m venv .venv
} else {
Write-Host "Using existing virtual environment"
}
# Direct environment activation to avoid script execution issues
$env:VIRTUAL_ENV = "$PWD\.venv"
$env:PATH = "$env:VIRTUAL_ENV\Scripts;$env:PATH"
# Install dependencies
if (Test-Path -Path "requirements.txt") {
Write-Host "Installing dependencies from requirements.txt..."
pip install -r requirements.txt
# Install Playwright browsers - add this line
Write-Host "Installing Playwright browsers..."
python -m playwright install
} else {
pip install outleap requests behave playwright
# Install Playwright browsers - add this line
Write-Host "Installing Playwright browsers..."
python -m playwright install
}
- name: Fetch & Download Installer Artifact (Windows)
if: matrix.os == 'windows'
shell: pwsh
run: |
$BUILD_ID = "${{ env.BUILD_ID }}"
$ARTIFACTS_URL = "${{ env.ARTIFACTS_URL }}"
# Fetch the correct artifact URL
$response = Invoke-RestMethod -Headers @{Authorization="token ${{ secrets.GITHUB_TOKEN }}" } -Uri $ARTIFACTS_URL
$ARTIFACT_NAME = ($response.artifacts | Where-Object { $_.name -eq "${{ matrix.artifact }}" }).archive_download_url
if (-Not $ARTIFACT_NAME) {
Write-Host "❌ Error: ${{ matrix.artifact }} artifact not found!"
exit 1
}
Write-Host "✅ Artifact found: $ARTIFACT_NAME"
# Secure download path
$DownloadPath = "$env:TEMP\secondlife-build-$BUILD_ID"
New-Item -ItemType Directory -Path $DownloadPath -Force | Out-Null
$InstallerPath = "$DownloadPath\installer.zip"
# Download the ZIP
Invoke-WebRequest -Uri $ARTIFACT_NAME -Headers @{Authorization="token ${{ secrets.GITHUB_TOKEN }}"} -OutFile $InstallerPath
# Ensure download succeeded
if (-Not (Test-Path $InstallerPath)) {
Write-Host "❌ Error: Failed to download ${{ matrix.artifact }}.zip"
exit 1
}
# Set the path for other steps
echo "DOWNLOAD_PATH=$DownloadPath" | Out-File -FilePath $env:GITHUB_ENV -Append
- name: Extract Installer & Locate Executable (Windows)
if: matrix.os == 'windows'
shell: pwsh
run: |
$BUILD_ID = "${{ env.BUILD_ID }}"
$ExtractPath = "${{ env.DOWNLOAD_PATH }}"
$InstallerZip = "$ExtractPath\installer.zip"
# Print paths for debugging
Write-Host "Extract Path: $ExtractPath"
Write-Host "Installer ZIP Path: $InstallerZip"
# Verify ZIP exists before extracting
if (-Not (Test-Path $InstallerZip)) {
Write-Host "❌ Error: ZIP file not found at $InstallerZip!"
exit 1
}
Write-Host "✅ ZIP file exists and is valid. Extracting..."
Expand-Archive -Path $InstallerZip -DestinationPath $ExtractPath -Force
# Find installer executable
$INSTALLER_PATH = (Get-ChildItem -Path $ExtractPath -Filter '*.exe' -Recurse | Select-Object -First 1).FullName
if (-Not $INSTALLER_PATH -or $INSTALLER_PATH -eq "") {
Write-Host "❌ Error: No installer executable found in the extracted files!"
Write-Host "📂 Extracted Files:"
Get-ChildItem -Path $ExtractPath -Recurse | Format-Table -AutoSize
exit 1
}
Write-Host "✅ Installer found: $INSTALLER_PATH"
echo "INSTALLER_PATH=$INSTALLER_PATH" | Out-File -FilePath $env:GITHUB_ENV -Append
- name: Install Second Life (Windows)
if: matrix.os == 'windows'
shell: pwsh
run: |
# Windows - Use Task Scheduler to bypass UAC
$action = New-ScheduledTaskAction -Execute "${{ env.INSTALLER_PATH }}" -Argument "/S"
$principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest
$task = New-ScheduledTask -Action $action -Principal $principal
Register-ScheduledTask -TaskName "SilentSLInstaller" -InputObject $task -Force
Start-ScheduledTask -TaskName "SilentSLInstaller"
- name: Wait for Installation to Complete (Windows)
if: matrix.os == 'windows'
shell: pwsh
run: |
Write-Host "Waiting for the Second Life installer to finish..."
do {
Start-Sleep -Seconds 5
$installerProcess = Get-Process | Where-Object { $_.Path -eq "${{ env.INSTALLER_PATH }}" }
} while ($installerProcess)
Write-Host "✅ Installation completed!"
- name: Cleanup After Installation (Windows)
if: matrix.os == 'windows'
shell: pwsh
run: |
# Cleanup Task Scheduler Entry
Unregister-ScheduledTask -TaskName "SilentSLInstaller" -Confirm:$false
Write-Host "✅ Task Scheduler entry removed."
# Delete Installer ZIP
$DeletePath = "${{ env.DOWNLOAD_PATH }}\installer.zip"
Write-Host "Checking if installer ZIP exists: $DeletePath"
# Ensure the ZIP file exists before trying to delete it
if (Test-Path $DeletePath) {
Remove-Item -Path $DeletePath -Force
Write-Host "✅ Successfully deleted: $DeletePath"
} else {
Write-Host "⚠️ Warning: ZIP file does not exist, skipping deletion."
}
- name: Run QA Test Script (Windows)
if: matrix.os == 'windows'
shell: pwsh
run: |
Write-Host "Running QA Test script on Windows runner: ${{ matrix.runner }}..."
cd ${{ matrix.install-path }}
# Activate virtual environment
Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process -Force
$env:VIRTUAL_ENV = "$PWD\.venv"
$env:PATH = "$env:VIRTUAL_ENV\Scripts;$env:PATH"
# Set runner name as environment variable
$env:RUNNER_NAME = "${{ matrix.runner }}"
# Run the test script
python runTests.py
# Mac-specific steps
- name: Set Build ID (Mac)
if: matrix.os == 'mac'
shell: bash
run: |
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
echo "BUILD_ID=${{ github.event.inputs.build_id }}" >> $GITHUB_ENV
echo "ARTIFACTS_URL=https://api.github.com/repos/secondlife/viewer/actions/runs/${{ github.event.inputs.build_id }}/artifacts" >> $GITHUB_ENV
else
echo "BUILD_ID=${{ github.event.workflow_run.id }}" >> $GITHUB_ENV
echo "ARTIFACTS_URL=https://api.github.com/repos/secondlife/viewer/actions/runs/${{ github.event.workflow_run.id }}/artifacts" >> $GITHUB_ENV
fi
- name: Verify viewer-automation-main Exists (Mac)
if: matrix.os == 'mac'
shell: bash
run: |
if [ ! -d "${{ matrix.install-path }}" ]; then
echo "❌ Error: viewer-automation folder not found on runner!"
exit 1
fi
echo "✅ viewer-automation is provided."
- name: Verify viewer-automation-main is Up-To-Date (Mac)
if: matrix.os == 'mac'
shell: bash
continue-on-error: true
run: |
cd ${{ matrix.install-path }}
echo "Checking for repository updates..."
# Check if .git directory exists
if [ -d ".git" ]; then
# Save local changes instead of discarding them
git stash push -m "Automated stash before update $(date)"
echo "Local changes saved (if any)"
# Update the repository
git pull || echo "⚠️ Could not update repository"
echo "✅ Repository updated (or attempted update)"
# Try to restore local changes if any were stashed
if git stash list | grep -q "Automated stash before update"; then
# Try to pop the stash, but be prepared for conflicts
if ! git stash pop; then
echo "⚠️ Conflict when restoring local changes"
# Save the conflicted state in a new branch for later review
branch_name="conflict-recovery-$(date +%Y%m%d-%H%M%S)"
git checkout -b "$branch_name"
echo "✅ Created branch '$branch_name' with conflicted state"
# For test execution, revert to a clean state
git reset --hard HEAD
echo "✅ Reset to clean state for test execution"
else
echo "✅ Local changes restored successfully"
fi
fi
else
echo "⚠️ Not a Git repository, using existing files"
fi
- name: Verify Python Installation (Mac)
if: matrix.os == 'mac'
shell: bash
run: |
if command -v python3 &> /dev/null; then
PYTHON_VERSION=$(python3 --version)
echo "✅ Python found: $PYTHON_VERSION"
else
echo "❌ Error: Python3 not found in PATH. Please install Python on this runner."
exit 1
fi
- name: Setup Python Virtual Environment (Mac)
if: matrix.os == 'mac'
shell: bash
run: |
cd ${{ matrix.install-path }}
# Create virtual environment if it doesn't exist
if [ ! -d ".venv" ]; then
echo "Creating virtual environment..."
python3 -m venv .venv
else
echo "Using existing virtual environment"
fi
# Activate virtual environment
source .venv/bin/activate
# Install dependencies
if [ -f "requirements.txt" ]; then
pip install -r requirements.txt
echo "✅ Installed dependencies from requirements.txt"
# Install Playwright browsers - add this line
echo "Installing Playwright browsers..."
python -m playwright install
else
pip install outleap requests behave playwright
echo "⚠️ requirements.txt not found, installed basic dependencies"
# Install Playwright browsers - add this line
echo "Installing Playwright browsers..."
python -m playwright install
fi
- name: Fetch & Download Installer Artifact (Mac)
if: matrix.os == 'mac'
shell: bash
run: |
# Mac-specific Bash commands
response=$(curl -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" -s ${{ env.ARTIFACTS_URL }})
ARTIFACT_NAME=$(echo $response | jq -r '.artifacts[] | select(.name=="${{ matrix.artifact }}") | .archive_download_url')
if [ -z "$ARTIFACT_NAME" ]; then
echo "❌ Error: ${{ matrix.artifact }} artifact not found!"
exit 1
fi
echo "✅ Artifact found: $ARTIFACT_NAME"
# Secure download path
DOWNLOAD_PATH="/tmp/secondlife-build-${{ env.BUILD_ID }}"
mkdir -p $DOWNLOAD_PATH
INSTALLER_PATH="$DOWNLOAD_PATH/installer.zip"
# Download the ZIP
curl -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" -L $ARTIFACT_NAME -o $INSTALLER_PATH
# Ensure download succeeded
if [ ! -f "$INSTALLER_PATH" ]; then
echo "❌ Error: Failed to download ${{ matrix.artifact }}.zip"
exit 1
fi
# Set the path for other steps
echo "DOWNLOAD_PATH=$DOWNLOAD_PATH" >> $GITHUB_ENV
- name: Extract Installer & Locate Executable (Mac)
if: matrix.os == 'mac'
shell: bash
run: |
EXTRACT_PATH="${{ env.DOWNLOAD_PATH }}"
INSTALLER_ZIP="$EXTRACT_PATH/installer.zip"
# Debug output
echo "Extract Path: $EXTRACT_PATH"
echo "Installer ZIP Path: $INSTALLER_ZIP"
# Verify ZIP exists
if [ ! -f "$INSTALLER_ZIP" ]; then
echo "❌ Error: ZIP file not found at $INSTALLER_ZIP!"
exit 1
fi
echo "✅ ZIP file exists and is valid. Extracting..."
# Extract the ZIP
unzip -o "$INSTALLER_ZIP" -d "$EXTRACT_PATH"
# Find DMG file
INSTALLER_PATH=$(find "$EXTRACT_PATH" -name "*.dmg" -type f | head -1)
if [ -z "$INSTALLER_PATH" ]; then
echo "❌ Error: No installer DMG found in the extracted files!"
echo "📂 Extracted Files:"
ls -la "$EXTRACT_PATH"
exit 1
fi
echo "✅ Installer found: $INSTALLER_PATH"
echo "INSTALLER_PATH=$INSTALLER_PATH" >> $GITHUB_ENV
- name: Install Second Life (Mac)
if: matrix.os == 'mac'
shell: bash
run: |
# Mac installation
echo "Mounting DMG installer..."
MOUNT_POINT="/tmp/secondlife-dmg"
mkdir -p "$MOUNT_POINT"
# Mount the DMG
hdiutil attach "${{ env.INSTALLER_PATH }}" -mountpoint "$MOUNT_POINT" -nobrowse
echo "✅ DMG mounted at $MOUNT_POINT"
# Find the app in the mounted DMG
APP_PATH=$(find "$MOUNT_POINT" -name "*.app" -type d | head -1)
if [ -z "$APP_PATH" ]; then
echo "❌ Error: No .app bundle found in the mounted DMG!"
exit 1
fi
echo "Installing application to Applications folder..."
# Copy the app to the Applications folder (or specified install path)
cp -R "$APP_PATH" "${{ matrix.install-path }}"
# Verify the app was copied successfully
if [ ! -d "${{ matrix.install-path }}/$(basename "$APP_PATH")" ]; then
echo "❌ Error: Failed to install application to ${{ matrix.install-path }}!"
exit 1
fi
echo "✅ Application installed successfully to ${{ matrix.install-path }}"
# Save mount point for cleanup
echo "MOUNT_POINT=$MOUNT_POINT" >> $GITHUB_ENV
- name: Wait for Installation to Complete (Mac)
if: matrix.os == 'mac'
shell: bash
run: |
echo "Waiting for installation to complete..."
# Sleep to allow installation to finish (adjust as needed)
sleep 30
echo "✅ Installation completed"
- name: Cleanup After Installation (Mac)
if: matrix.os == 'mac'
shell: bash
run: |
# Mac cleanup
# Unmount the DMG
echo "Unmounting DMG..."
hdiutil detach "${{ env.MOUNT_POINT }}" -force
# Clean up temporary files
echo "Cleaning up temporary files..."
rm -rf "${{ env.DOWNLOAD_PATH }}"
rm -rf "${{ env.MOUNT_POINT }}"
echo "✅ Cleanup completed"
- name: Run QA Test Script (Mac)
if: matrix.os == 'mac'
shell: bash
run: |
echo "Running QA Test script on Mac runner: ${{ matrix.runner }}..."
cd ${{ matrix.install-path }}
# Activate virtual environment
source .venv/bin/activate
# Set runner name as environment variable
export RUNNER_NAME="${{ matrix.runner }}"
# Run the test script
python runTests.py
# - name: Upload Test Results
# if: always()
# uses: actions/upload-artifact@v4
# with:
# name: test-results-${{ matrix.runner }}
# path: ${{ matrix.install-path }}/regressionTest/test_results.html

View File

@ -12,7 +12,7 @@ repos:
- id: indent-with-spaces
files: \.(cpp|c|h|inl|py|glsl|cmake)$
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
rev: v5.0.0
hooks:
- id: check-xml
- id: mixed-line-ending

View File

@ -0,0 +1,160 @@
# Test plan for PRIM_MEDIA_FIRST_CLICK_INTERACT
## Requirements
- At least two accounts
- At least one group
- Land under your control
## Feature Brief
Historically media-on-a-prim (MOAP) in Second Life has been bound to a focus system which blocks mouse click/hover events, this feature creates exceptions to this focus system for a configurable set of objects to meet user preference.
## Testing
The following scripts and test cases cover each individual operational mode of the feature; in practice these modes can be combined by advanced users in any configuration they desire from debug settings. Even though the intended use case combines multiple modes, individual modes can be tested for functionality when tested as described below.
If testing an arbitrary combination of operational modes beyond what the GUI offers is desired, the parameters of the bitfield for calculation are located in lltoolpie.h under the MediaFirstClickTypes enum. As of writing there exists a total of ~127 possible unique/valid combinations, which is why testing each mode individually is considered the most efficient for a full functionality test.
### Scripts
#### Script A
This script creates a media surface that is eligible for media first-click interact. Depending on test conditions, this will exhibit new behavior.
```lsl
default {
state_entry() {
llSetLinkMedia( LINK_THIS, 0, [
PRIM_MEDIA_CURRENT_URL, "http://lecs-viewer-web-components.s3.amazonaws.com/v3.0/agni/avatars.html",
PRIM_MEDIA_HOME_URL, "http://lecs-viewer-web-components.s3.amazonaws.com/v3.0/agni/avatars.html",
PRIM_MEDIA_FIRST_CLICK_INTERACT, TRUE,
PRIM_MEDIA_AUTO_PLAY, TRUE,
PRIM_MEDIA_CONTROLS, PRIM_MEDIA_CONTROLS_MINI
] );
}
}
```
#### Script B
This script creates a media surface that is NOT eligible for media first-click interact. In all but one test case, this will behave the same way.
```lsl
default {
state_entry() {
llSetLinkMedia( LINK_THIS, 0, [
PRIM_MEDIA_CURRENT_URL, "http://lecs-viewer-web-components.s3.amazonaws.com/v3.0/agni/avatars.html",
PRIM_MEDIA_HOME_URL, "http://lecs-viewer-web-components.s3.amazonaws.com/v3.0/agni/avatars.html",
PRIM_MEDIA_FIRST_CLICK_INTERACT, FALSE,
PRIM_MEDIA_AUTO_PLAY, TRUE,
PRIM_MEDIA_CONTROLS, PRIM_MEDIA_CONTROLS_MINI
] );
}
}
```
## Standard testing procedure
You will be asked to enable media faces on multiple cubes, make sure that the webpage loads on each, and interact with them in the following ways.
1. Enable media for the cube, and verify that it displays a webpage.
2. Click on the terrain to clear any focus.
3. Hover your mouse over UI elements of the webpage, and **observe** if they highlight/react to the mouse cursor.
4. If hover events are not registered, clicking on the webpage and then **observe** if they begin reacting to hover events.
5. Clicking on the terrain to clear any focus once again.
6. Clicking on a UI element of the webpage and **observe** if it reacts to the first click, or requires a second click. *(Maximum of 2 clicks per attempt)*
These steps will be repeated for one or more pairs of cubes per test case to ensure that media first click interact is functioning within expectations. Unless otherwise mentioned for a specific test case, you simply need only be in the same region as the cubes to test with them.
## Test cases
All test cases begin with at least two cubes rezzed, one containing Script A henceforth referred to as Cube A and one with Script B referred to as Cube B. The steps of some test cases may impact the condition of the cubes, so keeping a spare set rezzed or in inventory to rapidly duplicate should improve efficiency if testing cases in series.
### Case 1 (MEDIA_FIRST_CLICK_NONE)
Ensure that debug setting `MediaFirstClickInteract` is set to `0`
Starting with Cube A and Cube B, perform the testing procedure on each.
**Expected observations:** Both webpages do not react to hover events until clicked, both webpages do not react to clicks until clicked once to establish focus
### Case 2 (MEDIA_FIRST_CLICK_HUD)
Ensure that debug setting `MediaFirstClickInteract` is set to `1`
Starting with Cube A and Cube B, attach them both to your HUD and perform the testing procedure on each. You may need to rotate or scale the cubes to fit on your screen before beginning testing. You may attach both at the same time, or only one at a time.
**Expected observations:** The webpage on Cube A will react to mouse cursor hover events and clicks without needing a focus click, but the webpage on Cube B will not.
### Case 3 (MEDIA_FIRST_CLICK_OWN)
Ensure that debug setting `MediaFirstClickInteract` is set to `2`
This test case requires two pairs of cubes, and the second pair must not be owned by your testing account. What owns them is not important, it can be a group or your second testing account.
Perform the testing procedure on both sets of cubes.
**Expected observations:** The webpage on Cube A will react to mouse cursor hover events and clicks without needing a focus click, but the webpage on Cube B will not. The other pair of cubes will react the same as your Cube B.
### Case 4 (MEDIA_FIRST_CLICK_GROUP)
Ensure that debug setting `MediaFirstClickInteract` is set to `4`
This test case requires two pairs of cubes, and the second pair must be deeded or set to a group that your testing account is a member of, but does not have set as active at the beginning of the test. As long as the second set of cubes is set to a group that your primary test account is a member of, the avatar that owns them does not matter.
1. Perform the testing procedure on both sets of cubes.
2. Activate the group that the second set of cubes is set / deeded to
3. Perform the testing procedure on both sets of cubes once more.
**Expected observations:** Both cubes owned by your primary testing account will not react to mouse cursor hover events and clicks without needing a focus click. Cube A set to group will react to mouse cursor hover events and clicks without needing a focus click, but Cube B will not.
### Case 5 (MEDIA_FIRST_CLICK_FRIEND)
Ensure that debug setting `MediaFirstClickInteract` is set to `8`
This test case requires three sets of cubes, one owned by you, one owned by another avatar on your friend list, and a third set owned by an avatar that is not on your friend list, or deeded to group. You can optionally use two sets of cubes, and dissolve friendship with your second account to test non-friend cubes.
Perform the testing procedure on all cubes
**Expected observations:** Cube A owned by a friended avatar will react to mouse cursor hover events and clicks without needing a focus click. All other cubes will not.
### Case 6 (MEDIA_FIRST_CLICK_LAND)
Ensure that debug setting `MediaFirstClickInteract` is set to `16`
This is the most tricky test case due to the multiple combinations that this operational mode considers valid. You will need multiple cubes, and can omit Cube B for brevity unless running a full test pass. This is probably most efficiently tested from your second account, using your first account to adjust the test parameters to fit other sub-cases.
Note: This requires the avatar that is performing the tests to physically be in the same parcel as the test cube(s). If you are standing outside of the parcel the media cubes are in, they will never react to mouse cursor hover events and clicks without needing a focus click under this operational mode.
1. Place down a set of cubes owned by the same avatar as the land
- The second account should see Cube A react to mouse cursor hover events and clicks without needing a focus click
- Cube B if tested, will not react in all further sub-cases and will not be mentioned further.
2. Adjust the conditions of the cubes and parcel such that they are owned by another avatar, but have the same group as the land set
- The second account should see Cube A react to mouse cursor hover events and clicks without needing a focus click
3. Adjust the conditions of the cubes and parcel such that they are deeded to the same group that the parcel is deeded to
- The second account should see Cube A react to mouse cursor hover events and clicks without needing a focus click
4. Adjust the conditions of the cubes and parcel such that the parcel and cubes do not share an owner, or a group
- The second account should see Cube A NOT react to mouse cursor hover events until clicked, and clicks WILL need a focus click before registering.
### Case 7 (MEDIA_FIRST_CLICK_ANY) (optional)
Ensure that debug setting `MediaFirstClickInteract` is set to `31`
Repeat test cases 1-6.
1. Test case 1 should fail
2. Test cases 2-6 should pass
### Case 8 (MEDIA_FIRST_CLICK_ALL) (optional)
Ensure that debug setting `MediaFirstClickInteract` is set to `1073741824`
Repeat test cases 1-6, there is no pass/fail for this run.
All cubes including B types should exhibit the same first-click interact behavior.

View File

@ -72,7 +72,6 @@ else()
find_library(COCOA_LIBRARY Cocoa)
find_library(IOKIT_LIBRARY IOKit)
find_library(AGL_LIBRARY AGL)
find_library(APPKIT_LIBRARY AppKit)
find_library(COREAUDIO_LIBRARY CoreAudio)
@ -81,7 +80,6 @@ else()
${IOKIT_LIBRARY}
${COREFOUNDATION_LIBRARY}
${CARBON_LIBRARY}
${AGL_LIBRARY}
${APPKIT_LIBRARY}
${COREAUDIO_LIBRARY}
)

View File

@ -242,21 +242,20 @@ LLJoint *LLJoint::getRoot()
//-----------------------------------------------------------------------------
// findJoint()
//-----------------------------------------------------------------------------
LLJoint *LLJoint::findJoint( const std::string &name )
LLJoint* LLJoint::findJoint(std::string_view name)
{
if (name == getName())
return this;
for (LLJoint* joint : mChildren)
{
LLJoint *found = joint->findJoint(name);
if (found)
if (LLJoint* found = joint->findJoint(name))
{
return found;
}
}
return NULL;
return nullptr;
}

View File

@ -222,7 +222,7 @@ public:
LLJoint *getRoot();
// search for child joints by name
LLJoint *findJoint( const std::string &name );
LLJoint* findJoint(std::string_view name);
// add/remove children
void addChild( LLJoint *joint );

View File

@ -68,7 +68,7 @@ public:
// Called from MAIN THREAD.
void pause();
void unpause();
bool isPaused() { return isStopped() || mPaused; }
bool isPaused() const { return isStopped() || mPaused; }
// Cause the thread to wake up and check its condition
void wake();

View File

@ -110,9 +110,10 @@ std::vector<std::string> LLDir::getFilesInDir(const std::string &dirname)
std::vector<std::string> v;
if (exists(p))
boost::system::error_code ec;
if (exists(p, ec) && !ec.failed())
{
if (is_directory(p))
if (is_directory(p, ec) && !ec.failed())
{
boost::filesystem::directory_iterator end_iter;
for (boost::filesystem::directory_iterator dir_itr(p);

View File

@ -75,7 +75,7 @@ bool LLImageDimensionsInfo::load(const std::string& src_filename,U32 codec)
bool LLImageDimensionsInfo::getImageDimensionsBmp()
{
// Make sure the file is long enough.
const S32 DATA_LEN = 26; // BMP header (14) + DIB header size (4) + width (4) + height (4)
constexpr S32 DATA_LEN = 26; // BMP header (14) + DIB header size (4) + width (4) + height (4)
if (!checkFileLength(DATA_LEN))
{
LL_WARNS() << "Premature end of file" << LL_ENDL;
@ -105,7 +105,7 @@ bool LLImageDimensionsInfo::getImageDimensionsBmp()
bool LLImageDimensionsInfo::getImageDimensionsTga()
{
const S32 TGA_FILE_HEADER_SIZE = 12;
constexpr S32 TGA_FILE_HEADER_SIZE = 12;
// Make sure the file is long enough.
if (!checkFileLength(TGA_FILE_HEADER_SIZE + 1 /* width */ + 1 /* height */))
@ -124,7 +124,7 @@ bool LLImageDimensionsInfo::getImageDimensionsTga()
bool LLImageDimensionsInfo::getImageDimensionsPng()
{
const S32 PNG_MAGIC_SIZE = 8;
constexpr S32 PNG_MAGIC_SIZE = 8;
// Make sure the file is long enough.
if (!checkFileLength(PNG_MAGIC_SIZE + 8 + sizeof(S32) * 2 /* width, height */))
@ -134,7 +134,7 @@ bool LLImageDimensionsInfo::getImageDimensionsPng()
}
// Read PNG signature.
const U8 png_magic[PNG_MAGIC_SIZE] = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A};
constexpr U8 png_magic[PNG_MAGIC_SIZE] = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A};
U8 signature[PNG_MAGIC_SIZE];
mInfile.read((void*)signature, PNG_MAGIC_SIZE);
@ -166,34 +166,36 @@ bool LLImageDimensionsInfo::getImageDimensionsJpeg()
{
sJpegErrorEncountered = false;
clean();
FILE *fp = LLFile::fopen(mSrcFilename, "rb");
if (fp == NULL)
FILE* fp = LLFile::fopen(mSrcFilename, "rb");
if (!fp)
{
setLastError("Unable to open file for reading", mSrcFilename);
return false;
}
/* Make sure this is a JPEG file. */
const size_t JPEG_MAGIC_SIZE = 2;
const U8 jpeg_magic[JPEG_MAGIC_SIZE] = {0xFF, 0xD8};
constexpr size_t JPEG_MAGIC_SIZE = 2;
constexpr U8 jpeg_magic[JPEG_MAGIC_SIZE] = {0xFF, 0xD8};
U8 signature[JPEG_MAGIC_SIZE];
if (fread(signature, sizeof(signature), 1, fp) != 1)
{
LL_WARNS() << "Premature end of file" << LL_ENDL;
fclose(fp);
return false;
}
if (memcmp(signature, jpeg_magic, JPEG_MAGIC_SIZE) != 0)
{
LL_WARNS() << "Not a JPEG" << LL_ENDL;
mWarning = "texture_load_format_error";
fclose(fp);
return false;
}
fseek(fp, 0, SEEK_SET); // go back to start of the file
/* Init jpeg */
jpeg_error_mgr jerr;
jpeg_decompress_struct cinfo;
jpeg_decompress_struct cinfo{};
cinfo.err = jpeg_std_error(&jerr);
// Call our function instead of exit() if Libjpeg encounters an error.
// This is done to avoid crash in this case (STORM-472).

View File

@ -38,7 +38,7 @@ class LLImageDimensionsInfo
{
public:
LLImageDimensionsInfo():
mData(NULL)
mData(nullptr)
,mHeight(0)
,mWidth(0)
{}
@ -67,7 +67,7 @@ protected:
{
mInfile.close();
delete[] mData;
mData = NULL;
mData = nullptr;
mWidth = 0;
mHeight = 0;
}

View File

@ -281,10 +281,11 @@ S32 LLImageJ2C::calcDataSizeJ2C(S32 w, S32 h, S32 comp, S32 discard_level, F32 r
S32 height = (h > 0) ? h : 2048;
S32 max_dimension = llmax(width, height); // Find largest dimension
S32 block_area = MAX_BLOCK_SIZE * MAX_BLOCK_SIZE; // Calculated initial block area from established max block size (currently 64)
block_area *= llmax((max_dimension / MAX_BLOCK_SIZE / max_components), 1); // Adjust initial block area by ratio of largest dimension to block size per component
S32 totalbytes = (S32) (block_area * max_components * precision); // First block layer computed before loop without compression rate
S32 block_layers = 1; // Start at layer 1 since first block layer is computed outside loop
while (block_layers < 6) // Walk five layers for the five discards in JPEG2000
S32 max_layers = (S32)llmax(llround(log2f((float)max_dimension) - log2f((float)MAX_BLOCK_SIZE)), 4); // Find number of powers of two between extents and block size to a minimum of 4
block_area *= llmax(max_layers, 1); // Adjust initial block area by max number of layers
S32 totalbytes = (S32) (MIN_LAYER_SIZE * max_components * precision); // Start estimation with a minimum reasonable size
S32 block_layers = 0;
while (block_layers <= max_layers) // Walk the layers
{
if (block_layers <= (5 - discard_level)) // Walk backwards from discard 5 to required discard layer.
totalbytes += (S32) (block_area * max_components * precision * rate); // Add each block layer reduced by assumed compression rate

View File

@ -32,8 +32,6 @@
#include "event.h"
#include "cio.h"
#define MAX_ENCODED_DISCARD_LEVELS 5
// Factory function: see declaration in llimagej2c.cpp
LLImageJ2CImpl* fallbackCreateLLImageJ2CImpl()
{
@ -132,73 +130,96 @@ static void opj_error(const char* msg, void* user_data)
static OPJ_SIZE_T opj_read(void * buffer, OPJ_SIZE_T bytes, void* user_data)
{
llassert(user_data);
llassert(user_data && buffer);
JPEG2KBase* jpeg_codec = static_cast<JPEG2KBase*>(user_data);
OPJ_SIZE_T remainder = (jpeg_codec->size - jpeg_codec->offset);
if (remainder <= 0)
if (jpeg_codec->offset < 0 || static_cast<OPJ_SIZE_T>(jpeg_codec->offset) >= jpeg_codec->size)
{
jpeg_codec->offset = jpeg_codec->size;
// Indicate end of stream (hacky?)
return (OPJ_OFF_T)-1;
return static_cast<OPJ_SIZE_T>(-1); // Indicate EOF
}
OPJ_SIZE_T to_read = llclamp(U32(bytes), U32(0), U32(remainder));
OPJ_SIZE_T remainder = jpeg_codec->size - static_cast<OPJ_SIZE_T>(jpeg_codec->offset);
OPJ_SIZE_T to_read = (bytes < remainder) ? bytes : remainder;
memcpy(buffer, jpeg_codec->buffer + jpeg_codec->offset, to_read);
jpeg_codec->offset += to_read;
return to_read;
}
static OPJ_SIZE_T opj_write(void * buffer, OPJ_SIZE_T bytes, void* user_data)
{
llassert(user_data);
llassert(user_data && buffer);
JPEG2KBase* jpeg_codec = static_cast<JPEG2KBase*>(user_data);
OPJ_SIZE_T remainder = jpeg_codec->size - jpeg_codec->offset;
if (remainder < bytes)
OPJ_OFF_T required_offset = jpeg_codec->offset + static_cast<OPJ_OFF_T>(bytes);
// Overflow check
if (required_offset < jpeg_codec->offset)
return 0; // Overflow detected
// Resize if needed (exponential growth)
if (required_offset > static_cast<OPJ_OFF_T>(jpeg_codec->size))
{
OPJ_SIZE_T new_size = jpeg_codec->size + (bytes - remainder);
OPJ_SIZE_T new_size = jpeg_codec->size ? jpeg_codec->size : 1024;
while (required_offset > static_cast<OPJ_OFF_T>(new_size))
new_size *= 2;
const OPJ_SIZE_T MAX_BUFFER_SIZE = 512 * 1024 * 1024; // 512 MB, increase if needed
if (new_size > MAX_BUFFER_SIZE) return 0;
U8* new_buffer = (U8*)ll_aligned_malloc_16(new_size);
memcpy(new_buffer, jpeg_codec->buffer, jpeg_codec->offset);
U8* old_buffer = jpeg_codec->buffer;
if (!new_buffer) return 0; // Allocation failed
if (jpeg_codec->offset > 0)
memcpy(new_buffer, jpeg_codec->buffer, static_cast<size_t>(jpeg_codec->offset));
ll_aligned_free_16(jpeg_codec->buffer);
jpeg_codec->buffer = new_buffer;
ll_aligned_free_16(old_buffer);
jpeg_codec->size = new_size;
}
memcpy(jpeg_codec->buffer + jpeg_codec->offset, buffer, bytes);
jpeg_codec->offset += bytes;
memcpy(jpeg_codec->buffer + jpeg_codec->offset, buffer, static_cast<size_t>(bytes));
jpeg_codec->offset = required_offset;
return bytes;
}
static OPJ_OFF_T opj_skip(OPJ_OFF_T bytes, void* user_data)
{
llassert(user_data);
JPEG2KBase* jpeg_codec = static_cast<JPEG2KBase*>(user_data);
jpeg_codec->offset += bytes;
if (jpeg_codec->offset > (OPJ_OFF_T)jpeg_codec->size)
OPJ_OFF_T new_offset = jpeg_codec->offset + bytes;
if (new_offset < 0 || new_offset > static_cast<OPJ_OFF_T>(jpeg_codec->size))
{
jpeg_codec->offset = jpeg_codec->size;
// Indicate end of stream
return (OPJ_OFF_T)-1;
}
if (jpeg_codec->offset < 0)
{
// Shouldn't be possible?
jpeg_codec->offset = 0;
// Clamp and indicate EOF or error
jpeg_codec->offset = llclamp<OPJ_OFF_T>(new_offset, 0, static_cast<OPJ_OFF_T>(jpeg_codec->size));
return (OPJ_OFF_T)-1;
}
jpeg_codec->offset = new_offset;
return bytes;
}
static OPJ_BOOL opj_seek(OPJ_OFF_T bytes, void * user_data)
static OPJ_BOOL opj_seek(OPJ_OFF_T offset, void * user_data)
{
llassert(user_data);
JPEG2KBase* jpeg_codec = static_cast<JPEG2KBase*>(user_data);
jpeg_codec->offset = bytes;
jpeg_codec->offset = llclamp(U32(jpeg_codec->offset), U32(0), U32(jpeg_codec->size));
if (offset < 0 || offset > static_cast<OPJ_OFF_T>(jpeg_codec->size))
return OPJ_FALSE;
jpeg_codec->offset = offset;
return OPJ_TRUE;
}
static void opj_free_user_data(void * user_data)
{
llassert(user_data);
JPEG2KBase* jpeg_codec = static_cast<JPEG2KBase*>(user_data);
// Don't free, data is managed externally
jpeg_codec->buffer = nullptr;
@ -208,14 +229,54 @@ static void opj_free_user_data(void * user_data)
static void opj_free_user_data_write(void * user_data)
{
llassert(user_data);
JPEG2KBase* jpeg_codec = static_cast<JPEG2KBase*>(user_data);
// Free, data was allocated here
ll_aligned_free_16(jpeg_codec->buffer);
jpeg_codec->buffer = nullptr;
if (jpeg_codec->buffer)
{
ll_aligned_free_16(jpeg_codec->buffer);
jpeg_codec->buffer = nullptr;
}
jpeg_codec->size = 0;
jpeg_codec->offset = 0;
}
/**
* Estimates the number of layers necessary depending on the image surface (w x h)
*/
static U32 estimate_num_layers(U32 surface)
{
if (surface <= 1024) return 2; // Tiny (≤32×32)
else if (surface <= 16384) return 3; // Small (≤128×128)
else if (surface <= 262144) return 4; // Medium (≤512×512)
else if (surface <= 1048576) return 5; // Up to ~1MP
else return 6; // Up to ~1.52MP
}
/**
* Sets the parameters.tcp_rates according to the number of layers and a last tcp_rate value (which equals to the final compression ratio).
*
* Example for 6 layers:
*
* i = 5, parameters.tcp_rates[6 - 1 - 5] = 8.0f * (1 << (5 << 1)) = 8192 // Layer 5 (lowest quality)
* i = 4, parameters.tcp_rates[6 - 1 - 4] = 8.0f * (1 << (4 << 1)) = 2048 // Layer 4
* i = 3, parameters.tcp_rates[6 - 1 - 3] = 8.0f * (1 << (3 << 1)) = 512 // Layer 3
* i = 2, parameters.tcp_rates[6 - 1 - 2] = 8.0f * (1 << (2 << 1)) = 128 // Layer 2
* i = 1, parameters.tcp_rates[6 - 1 - 1] = 8.0f * (1 << (1 << 1)) = 32 // Layer 1
* i = 0, parameters.tcp_rates[6 - 1 - 0] = 8.0f * (1 << (0 << 1)) = 8 // Layer 0 (highest quality)
*
*/
static void set_tcp_rates(opj_cparameters_t* parameters, U32 num_layers = 1, F32 last_tcp_rate = LAST_TCP_RATE)
{
parameters->tcp_numlayers = num_layers;
for (int i = num_layers - 1; i >= 0; i--)
{
parameters->tcp_rates[num_layers - 1 - i] = last_tcp_rate * static_cast<F32>(1 << (i << 1));
}
}
class JPEG2KDecode : public JPEG2KBase
{
public:
@ -430,15 +491,16 @@ public:
opj_set_default_encoder_parameters(&parameters);
parameters.cod_format = OPJ_CODEC_J2K;
parameters.cp_disto_alloc = 1;
parameters.prog_order = OPJ_RLCP; // should be the default, but, just in case
parameters.cp_disto_alloc = 1; // enable rate allocation by distortion
parameters.max_cs_size = 0; // do not cap max size because we're using tcp_rates and also irrelevant with lossless.
if (reversible)
{
parameters.max_cs_size = 0; // do not limit size for reversible compression
parameters.irreversible = 0; // should be the default, but, just in case
parameters.tcp_numlayers = 1;
/* documentation seems to be wrong, should be 0.0f for lossless, not 1.0f
see https://github.com/uclouvain/openjpeg/blob/39e8c50a2f9bdcf36810ee3d41bcbf1cc78968ae/src/lib/openjp2/j2k.c#L7755
see https://github.com/uclouvain/openjpeg/blob/e7453e398b110891778d8da19209792c69ca7169/src/lib/openjp2/j2k.c#L7817
*/
parameters.tcp_rates[0] = 0.0f;
}
@ -493,53 +555,22 @@ public:
encoder = opj_create_compress(OPJ_CODEC_J2K);
parameters.tcp_mct = (image->numcomps >= 3) ? 1 : 0;
parameters.cod_format = OPJ_CODEC_J2K;
parameters.prog_order = OPJ_RLCP;
parameters.cp_disto_alloc = 1;
parameters.tcp_mct = (image->numcomps >= 3) ? 1 : 0; // no color transform for RGBA images
// if not lossless compression, computes tcp_numlayers and max_cs_size depending on the image dimensions
if( parameters.irreversible ) {
if( parameters.irreversible )
{
// computes a number of layers
U32 surface = rawImageIn.getWidth() * rawImageIn.getHeight();
U32 nb_layers = 1;
U32 s = 64*64;
while (surface > s)
{
nb_layers++;
s *= 4;
}
nb_layers = llclamp(nb_layers, 1, 6);
parameters.tcp_numlayers = nb_layers;
parameters.tcp_rates[nb_layers - 1] = (U32)(1.f / DEFAULT_COMPRESSION_RATE); // 1:8 by default
// gets the necessary number of layers
U32 nb_layers = estimate_num_layers(surface);
// for each subsequent layer, computes its rate and adds surface * numcomps * 1/rate to the max_cs_size
U32 max_cs_size = (U32)(surface * image->numcomps * DEFAULT_COMPRESSION_RATE);
U32 multiplier;
for (int i = nb_layers - 2; i >= 0; i--)
{
if( i == nb_layers - 2 )
{
multiplier = 15;
}
else if( i == nb_layers - 3 )
{
multiplier = 4;
}
else
{
multiplier = 2;
}
parameters.tcp_rates[i] = parameters.tcp_rates[i + 1] * multiplier;
max_cs_size += (U32)(surface * image->numcomps * (1 / parameters.tcp_rates[i]));
}
// fills parameters.tcp_rates and updates parameters.tcp_numlayers
set_tcp_rates(&parameters, nb_layers, LAST_TCP_RATE);
//ensure that we have at least a minimal size
max_cs_size = llmax(max_cs_size, (U32)FIRST_PACKET_SIZE);
parameters.max_cs_size = max_cs_size;
}
if (!opj_setup_encoder(encoder, &parameters, image))
@ -551,7 +582,20 @@ public:
opj_set_warning_handler(encoder, opj_warn, this);
opj_set_error_handler(encoder, opj_error, this);
U32 tile_count = (rawImageIn.getWidth() >> 6) * (rawImageIn.getHeight() >> 6);
U32 width_tiles = (rawImageIn.getWidth() >> 6);
U32 height_tiles = (rawImageIn.getHeight() >> 6);
// Allow images with a width or height that are MIN_IMAGE_SIZE <= x < 64
if (width_tiles == 0 && (rawImageIn.getWidth() >= MIN_IMAGE_SIZE))
{
width_tiles = 1;
}
if (height_tiles == 0 && (rawImageIn.getHeight() >= MIN_IMAGE_SIZE))
{
height_tiles = 1;
}
U32 tile_count = width_tiles * height_tiles;
U32 data_size_guess = tile_count * TILE_SIZE;
// will be freed in opj_free_user_data_write
@ -566,7 +610,7 @@ public:
opj_stream_destroy(stream);
}
stream = opj_stream_create(data_size_guess, false);
stream = opj_stream_create(data_size_guess, OPJ_FALSE);
if (!stream)
{
return false;
@ -607,17 +651,15 @@ public:
void setImage(const LLImageRaw& raw)
{
opj_image_cmptparm_t cmptparm[MAX_ENCODED_DISCARD_LEVELS];
memset(&cmptparm[0], 0, MAX_ENCODED_DISCARD_LEVELS * sizeof(opj_image_cmptparm_t));
S32 numcomps = raw.getComponents();
S32 width = raw.getWidth();
S32 height = raw.getHeight();
S32 width = raw.getWidth();
S32 height = raw.getHeight();
std::vector<opj_image_cmptparm_t> cmptparm(numcomps);
for (S32 c = 0; c < numcomps; c++)
{
cmptparm[c].prec = 8;
cmptparm[c].bpp = 8;
cmptparm[c].prec = 8; // replaces .bpp
cmptparm[c].sgnd = 0;
cmptparm[c].dx = parameters.subsampling_dx;
cmptparm[c].dy = parameters.subsampling_dy;
@ -625,7 +667,7 @@ public:
cmptparm[c].h = height;
}
image = opj_image_create(numcomps, &cmptparm[0], OPJ_CLRSPC_SRGB);
image = opj_image_create(numcomps, cmptparm.data(), OPJ_CLRSPC_SRGB);
image->x1 = width;
image->y1 = height;
@ -637,7 +679,7 @@ public:
{
for (S32 x = 0; x < width; x++)
{
const U8 *pixel = src_datap + (y*width + x) * numcomps;
const U8 *pixel = src_datap + (y * width + x) * numcomps;
for (S32 c = 0; c < numcomps; c++)
{
image->comps[c].data[i] = *pixel;
@ -857,12 +899,11 @@ bool LLImageJ2COJ::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, con
{
JPEG2KEncode encode(comment_text, reversible);
bool encoded = encode.encode(raw_image, base);
if (encoded)
if (!encoded)
{
LL_WARNS() << "Openjpeg encoding implementation isn't complete, returning false" << LL_ENDL;
LL_WARNS() << "Openjpeg encoding was unsuccessful, returning false" << LL_ENDL;
}
return encoded;
//return false;
}
bool LLImageJ2COJ::getMetadata(LLImageJ2C &base)

View File

@ -29,6 +29,8 @@
#include "llimagej2c.h"
const F32 LAST_TCP_RATE = 1.f/DEFAULT_COMPRESSION_RATE; // should be 8, giving a 1:8 ratio
class LLImageJ2COJ : public LLImageJ2CImpl
{
public:

View File

@ -37,98 +37,98 @@
#include "llsettingsdaycycle.h"
// Grid out of which parcels taken is stepped every 4 meters.
const F32 PARCEL_GRID_STEP_METERS = 4.f;
constexpr F32 PARCEL_GRID_STEP_METERS = 4.f;
// Area of one "square" of parcel
const S32 PARCEL_UNIT_AREA = 16;
constexpr S32 PARCEL_UNIT_AREA = 16;
// Height _above_ground_ that parcel boundary ends
const F32 PARCEL_HEIGHT = 50.f;
constexpr F32 PARCEL_HEIGHT = 50.f;
//Height above ground which parcel boundries exist for explicitly banned avatars
const F32 BAN_HEIGHT = 5000.f;
constexpr F32 BAN_HEIGHT = 5000.f;
// Maximum number of entries in an access list
const S32 PARCEL_MAX_ACCESS_LIST = 300;
constexpr S32 PARCEL_MAX_ACCESS_LIST = 300;
//Maximum number of entires in an update packet
//for access/ban lists.
const F32 PARCEL_MAX_ENTRIES_PER_PACKET = 48.f;
constexpr F32 PARCEL_MAX_ENTRIES_PER_PACKET = 48.f;
// Maximum number of experiences
const S32 PARCEL_MAX_EXPERIENCE_LIST = 24;
constexpr S32 PARCEL_MAX_EXPERIENCE_LIST = 24;
// Weekly charge for listing a parcel in the directory
const S32 PARCEL_DIRECTORY_FEE = 30;
constexpr S32 PARCEL_DIRECTORY_FEE = 30;
const S32 PARCEL_PASS_PRICE_DEFAULT = 10;
const F32 PARCEL_PASS_HOURS_DEFAULT = 1.f;
constexpr S32 PARCEL_PASS_PRICE_DEFAULT = 10;
constexpr F32 PARCEL_PASS_HOURS_DEFAULT = 1.f;
// Number of "chunks" in which parcel overlay data is sent
// Chunk 0 = southern rows, entire width
const S32 PARCEL_OVERLAY_CHUNKS = 4;
constexpr S32 PARCEL_OVERLAY_CHUNKS = 4;
// Bottom three bits are a color index for the land overlay
const U8 PARCEL_COLOR_MASK = 0x07;
const U8 PARCEL_PUBLIC = 0x00;
const U8 PARCEL_OWNED = 0x01;
const U8 PARCEL_GROUP = 0x02;
const U8 PARCEL_SELF = 0x03;
const U8 PARCEL_FOR_SALE = 0x04;
const U8 PARCEL_AUCTION = 0x05;
constexpr U8 PARCEL_COLOR_MASK = 0x07;
constexpr U8 PARCEL_PUBLIC = 0x00;
constexpr U8 PARCEL_OWNED = 0x01;
constexpr U8 PARCEL_GROUP = 0x02;
constexpr U8 PARCEL_SELF = 0x03;
constexpr U8 PARCEL_FOR_SALE = 0x04;
constexpr U8 PARCEL_AUCTION = 0x05;
// unused 0x06
// unused 0x07
// flag, unused 0x08
const U8 PARCEL_HIDDENAVS = 0x10; // avatars not visible outside of parcel. Used for 'see avs' feature, but must be off for compatibility
const U8 PARCEL_SOUND_LOCAL = 0x20;
const U8 PARCEL_WEST_LINE = 0x40; // flag, property line on west edge
const U8 PARCEL_SOUTH_LINE = 0x80; // flag, property line on south edge
constexpr U8 PARCEL_HIDDENAVS = 0x10; // avatars not visible outside of parcel. Used for 'see avs' feature, but must be off for compatibility
constexpr U8 PARCEL_SOUND_LOCAL = 0x20;
constexpr U8 PARCEL_WEST_LINE = 0x40; // flag, property line on west edge
constexpr U8 PARCEL_SOUTH_LINE = 0x80; // flag, property line on south edge
// Transmission results for parcel properties
const S32 PARCEL_RESULT_NO_DATA = -1;
const S32 PARCEL_RESULT_SUCCESS = 0; // got exactly one parcel
const S32 PARCEL_RESULT_MULTIPLE = 1; // got multiple parcels
constexpr S32 PARCEL_RESULT_NO_DATA = -1;
constexpr S32 PARCEL_RESULT_SUCCESS = 0; // got exactly one parcel
constexpr S32 PARCEL_RESULT_MULTIPLE = 1; // got multiple parcels
const S32 SELECTED_PARCEL_SEQ_ID = -10000;
const S32 COLLISION_NOT_IN_GROUP_PARCEL_SEQ_ID = -20000;
const S32 COLLISION_BANNED_PARCEL_SEQ_ID = -30000;
const S32 COLLISION_NOT_ON_LIST_PARCEL_SEQ_ID = -40000;
const S32 HOVERED_PARCEL_SEQ_ID = -50000;
constexpr S32 SELECTED_PARCEL_SEQ_ID = -10000;
constexpr S32 COLLISION_NOT_IN_GROUP_PARCEL_SEQ_ID = -20000;
constexpr S32 COLLISION_BANNED_PARCEL_SEQ_ID = -30000;
constexpr S32 COLLISION_NOT_ON_LIST_PARCEL_SEQ_ID = -40000;
constexpr S32 HOVERED_PARCEL_SEQ_ID = -50000;
const U32 RT_NONE = 0x1 << 0;
const U32 RT_OWNER = 0x1 << 1;
const U32 RT_GROUP = 0x1 << 2;
const U32 RT_OTHER = 0x1 << 3;
const U32 RT_LIST = 0x1 << 4;
const U32 RT_SELL = 0x1 << 5;
constexpr U32 RT_NONE = 0x1 << 0;
constexpr U32 RT_OWNER = 0x1 << 1;
constexpr U32 RT_GROUP = 0x1 << 2;
constexpr U32 RT_OTHER = 0x1 << 3;
constexpr U32 RT_LIST = 0x1 << 4;
constexpr U32 RT_SELL = 0x1 << 5;
const S32 INVALID_PARCEL_ID = -1;
constexpr S32 INVALID_PARCEL_ID = -1;
const S32 INVALID_PARCEL_ENVIRONMENT_VERSION = -2;
constexpr S32 INVALID_PARCEL_ENVIRONMENT_VERSION = -2;
// if Region settings are used, parcel env. version is -1
const S32 UNSET_PARCEL_ENVIRONMENT_VERSION = -1;
constexpr S32 UNSET_PARCEL_ENVIRONMENT_VERSION = -1;
// Timeouts for parcels
// default is 21 days * 24h/d * 60m/h * 60s/m *1000000 usec/s = 1814400000000
const U64 DEFAULT_USEC_CONVERSION_TIMEOUT = U64L(1814400000000);
constexpr U64 DEFAULT_USEC_CONVERSION_TIMEOUT = U64L(1814400000000);
// ***** TESTING is 10 minutes
//const U64 DEFAULT_USEC_CONVERSION_TIMEOUT = U64L(600000000);
// group is 60 days * 24h/d * 60m/h * 60s/m *1000000 usec/s = 5184000000000
const U64 GROUP_USEC_CONVERSION_TIMEOUT = U64L(5184000000000);
constexpr U64 GROUP_USEC_CONVERSION_TIMEOUT = U64L(5184000000000);
// ***** TESTING is 10 minutes
//const U64 GROUP_USEC_CONVERSION_TIMEOUT = U64L(600000000);
// default sale timeout is 2 days -> 172800000000
const U64 DEFAULT_USEC_SALE_TIMEOUT = U64L(172800000000);
constexpr U64 DEFAULT_USEC_SALE_TIMEOUT = U64L(172800000000);
// ***** TESTING is 10 minutes
//const U64 DEFAULT_USEC_SALE_TIMEOUT = U64L(600000000);
// more grace period extensions.
const U64 SEVEN_DAYS_IN_USEC = U64L(604800000000);
constexpr U64 SEVEN_DAYS_IN_USEC = U64L(604800000000);
// if more than 100,000s before sale revert, and no extra extension
// has been given, go ahead and extend it more. That's about 1.2 days.
const S32 EXTEND_GRACE_IF_MORE_THAN_SEC = 100000;
constexpr S32 EXTEND_GRACE_IF_MORE_THAN_SEC = 100000;
@ -250,9 +250,9 @@ public:
void setMediaURL(const std::string& url);
void setMediaType(const std::string& type);
void setMediaDesc(const std::string& desc);
void setMediaID(const LLUUID& id) { mMediaID = id; }
void setMediaAutoScale ( U8 flagIn ) { mMediaAutoScale = flagIn; }
void setMediaLoop (U8 loop) { mMediaLoop = loop; }
void setMediaID(const LLUUID& id) { mMediaID = id; }
void setMediaAutoScale ( U8 flagIn ) { mMediaAutoScale = flagIn; }
void setMediaLoop(U8 loop) { mMediaLoop = loop; }
void setMediaWidth(S32 width);
void setMediaHeight(S32 height);
void setMediaCurrentURL(const std::string& url);

View File

@ -361,14 +361,12 @@ LLSD LLSettingsBase::interpolateSDValue(const std::string& key_name, const LLSD
new_array = q.getValue();
}
else
{ // TODO: We could expand this to inspect the type and do a deep lerp based on type.
// for now assume a heterogeneous array of reals.
{
size_t len = std::max(value.size(), other_value.size());
for (size_t i = 0; i < len; ++i)
{
new_array[i] = lerp((F32)value[i].asReal(), (F32)other_value[i].asReal(), (F32)mix);
new_array[i] = interpolateSDValue(key_name, value[i], other_value[i], defaults, mix, skip, slerps);
}
}

View File

@ -657,15 +657,16 @@ void LLSettingsSky::blend(LLSettingsBase::ptr_t &end, F64 blendf)
mHasLegacyHaze |= lerp_legacy_float(mHazeDensity, mLegacyHazeDensity, other->mHazeDensity, other->mLegacyHazeDensity, 0.7f, (F32)blendf);
mHasLegacyHaze |= lerp_legacy_float(mDistanceMultiplier, mLegacyDistanceMultiplier, other->mDistanceMultiplier, other->mLegacyDistanceMultiplier, 0.8f, (F32)blendf);
mHasLegacyHaze |= lerp_legacy_float(mDensityMultiplier, mLegacyDensityMultiplier, other->mDensityMultiplier, other->mLegacyDensityMultiplier, 0.0001f, (F32)blendf);
mHasLegacyHaze |= lerp_legacy_color(mAmbientColor, mLegacyAmbientColor, other->mAmbientColor, other->mLegacyAmbientColor, LLColor3(0.25f, 0.25f, 0.25f), (F32)blendf);
mHasLegacyHaze |= lerp_legacy_color(mBlueHorizon, mLegacyBlueHorizon, other->mBlueHorizon, other->mLegacyBlueHorizon, LLColor3(0.4954f, 0.4954f, 0.6399f), (F32)blendf);
mHasLegacyHaze |= lerp_legacy_color(mBlueDensity, mLegacyBlueDensity, other->mBlueDensity, other->mLegacyBlueDensity, LLColor3(0.2447f, 0.4487f, 0.7599f), (F32)blendf);
parammapping_t defaults = other->getParameterMap();
stringset_t skip = getSkipInterpolateKeys();
stringset_t slerps = getSlerpKeys();
mAbsorptionConfigs = interpolateSDMap(mAbsorptionConfigs, other->mAbsorptionConfigs, defaults, blendf, skip, slerps);
mMieConfigs = interpolateSDMap(mMieConfigs, other->mMieConfigs, defaults, blendf, skip, slerps);
mRayleighConfigs = interpolateSDMap(mRayleighConfigs, other->mRayleighConfigs, defaults, blendf, skip, slerps);
mAbsorptionConfigs = interpolateSDValue("absorption_config", mAbsorptionConfigs, other->mAbsorptionConfigs, defaults, blendf, skip, slerps);
mMieConfigs = interpolateSDValue("mie_config", mMieConfigs, other->mMieConfigs, defaults, blendf, skip, slerps);
mRayleighConfigs = interpolateSDValue("rayleigh_config", mRayleighConfigs, other->mRayleighConfigs, defaults, blendf, skip, slerps);
setDirtyFlag(true);
setReplaced();

View File

@ -27,7 +27,6 @@
#include "linden_common.h"
#include "math.h"
//#include "vmath.h"
#include "v3math.h"
#include "llquaternion.h"
#include "m3math.h"

View File

@ -27,7 +27,6 @@
#include "linden_common.h"
#include "llmath.h"
//#include "vmath.h"
#include "v3math.h"
#include "patch_dct.h"
#include "patch_code.h"

View File

@ -27,7 +27,6 @@
#include "linden_common.h"
#include "llmath.h"
//#include "vmath.h"
#include "v3math.h"
#include "patch_dct.h"

View File

@ -27,7 +27,6 @@
#include "linden_common.h"
#include "llmath.h"
//#include "vmath.h"
#include "v3math.h"
#include "patch_dct.h"

View File

@ -575,7 +575,7 @@ void LLPluginProcessParent::idle(void)
params.args.add("-e");
params.args.add("tell application \"Terminal\"");
params.args.add("-e");
params.args.add(STRINGIZE("set win to do script \"lldb -pid "
params.args.add(STRINGIZE("set win to do script \"lldb -p "
<< mProcess->getProcessID() << "\""));
params.args.add("-e");
params.args.add("do script \"continue\" in win");

View File

@ -2230,6 +2230,9 @@ void LLLineEditor::clear()
{
mText.clear();
setCursor(0);
mFontBufferPreSelection.reset();
mFontBufferSelection.reset();
mFontBufferPostSelection.reset();
}
//virtual

View File

@ -1007,7 +1007,7 @@ void LLScrollListCtrl::deleteItems(const LLSD& sd)
void LLScrollListCtrl::deleteSelectedItems()
{
item_list::iterator iter;
for (iter = mItemList.begin(); iter < mItemList.end(); )
for (iter = mItemList.begin(); iter != mItemList.end(); )
{
LLScrollListItem* itemp = *iter;
if (itemp->getSelected())

View File

@ -657,7 +657,7 @@ attributedStringInfo getSegments(NSAttributedString *str)
};
int string_length = [aString length];
unichar text[string_length];
unichar *text = new unichar[string_length];
attributedStringInfo segments;
// I used 'respondsToSelector:@selector(string)'
// to judge aString is an attributed string or not.
@ -685,6 +685,8 @@ attributedStringInfo getSegments(NSAttributedString *str)
// we must clear the marked text when aString is null.
[self unmarkText];
}
delete [] text;
} else {
if (mHasMarkedText)
{

View File

@ -103,7 +103,6 @@ LLWindow::LLWindow(LLWindowCallbacks* callbacks, bool fullscreen, U32 flags)
mFullscreen(fullscreen),
mFullscreenWidth(0),
mFullscreenHeight(0),
mFullscreenBits(0),
mFullscreenRefresh(0),
mSupportedResolutions(NULL),
mNumSupportedResolutions(0),

View File

@ -223,7 +223,6 @@ protected:
bool mFullscreen;
S32 mFullscreenWidth;
S32 mFullscreenHeight;
S32 mFullscreenBits;
S32 mFullscreenRefresh;
LLWindowResolution* mSupportedResolutions;
S32 mNumSupportedResolutions;

View File

@ -695,8 +695,7 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
}
if (dev_mode.dmPelsWidth == width &&
dev_mode.dmPelsHeight == height &&
dev_mode.dmBitsPerPel == BITS_PER_PIXEL)
dev_mode.dmPelsHeight == height)
{
success = true;
if ((dev_mode.dmDisplayFrequency - current_refresh)
@ -736,7 +735,7 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
// If we found a good resolution, use it.
if (success)
{
success = setDisplayResolution(width, height, BITS_PER_PIXEL, closest_refresh);
success = setDisplayResolution(width, height, closest_refresh);
}
// Keep a copy of the actual current device mode in case we minimize
@ -749,7 +748,6 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
mFullscreen = true;
mFullscreenWidth = dev_mode.dmPelsWidth;
mFullscreenHeight = dev_mode.dmPelsHeight;
mFullscreenBits = dev_mode.dmBitsPerPel;
mFullscreenRefresh = dev_mode.dmDisplayFrequency;
LL_INFOS("Window") << "Running at " << dev_mode.dmPelsWidth
@ -763,7 +761,6 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
mFullscreen = false;
mFullscreenWidth = -1;
mFullscreenHeight = -1;
mFullscreenBits = -1;
mFullscreenRefresh = -1;
std::map<std::string,std::string> args;
@ -1185,7 +1182,7 @@ bool LLWindowWin32::switchContext(bool fullscreen, const LLCoordScreen& size, bo
// If we found a good resolution, use it.
if (success)
{
success = setDisplayResolution(width, height, BITS_PER_PIXEL, closest_refresh);
success = setDisplayResolution(width, height, closest_refresh);
}
// Keep a copy of the actual current device mode in case we minimize
@ -1197,7 +1194,6 @@ bool LLWindowWin32::switchContext(bool fullscreen, const LLCoordScreen& size, bo
mFullscreen = true;
mFullscreenWidth = dev_mode.dmPelsWidth;
mFullscreenHeight = dev_mode.dmPelsHeight;
mFullscreenBits = dev_mode.dmBitsPerPel;
mFullscreenRefresh = dev_mode.dmDisplayFrequency;
LL_INFOS("Window") << "Running at " << dev_mode.dmPelsWidth
@ -1223,7 +1219,6 @@ bool LLWindowWin32::switchContext(bool fullscreen, const LLCoordScreen& size, bo
mFullscreen = false;
mFullscreenWidth = -1;
mFullscreenHeight = -1;
mFullscreenBits = -1;
mFullscreenRefresh = -1;
LL_INFOS("Window") << "Unable to run fullscreen at " << width << "x" << height << LL_ENDL;
@ -3517,7 +3512,7 @@ F32 LLWindowWin32::getPixelAspectRatio()
// Change display resolution. Returns true if successful.
// protected
bool LLWindowWin32::setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh)
bool LLWindowWin32::setDisplayResolution(S32 width, S32 height, S32 refresh)
{
DEVMODE dev_mode;
::ZeroMemory(&dev_mode, sizeof(DEVMODE));
@ -3529,7 +3524,6 @@ bool LLWindowWin32::setDisplayResolution(S32 width, S32 height, S32 bits, S32 re
{
if (dev_mode.dmPelsWidth == width &&
dev_mode.dmPelsHeight == height &&
dev_mode.dmBitsPerPel == bits &&
dev_mode.dmDisplayFrequency == refresh )
{
// ...display mode identical, do nothing
@ -3541,9 +3535,8 @@ bool LLWindowWin32::setDisplayResolution(S32 width, S32 height, S32 bits, S32 re
dev_mode.dmSize = sizeof(dev_mode);
dev_mode.dmPelsWidth = width;
dev_mode.dmPelsHeight = height;
dev_mode.dmBitsPerPel = bits;
dev_mode.dmDisplayFrequency = refresh;
dev_mode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY;
dev_mode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY;
// CDS_FULLSCREEN indicates that this is a temporary change to the device mode.
LONG cds_result = ChangeDisplaySettings(&dev_mode, CDS_FULLSCREEN);
@ -3553,7 +3546,7 @@ bool LLWindowWin32::setDisplayResolution(S32 width, S32 height, S32 bits, S32 re
if (!success)
{
LL_WARNS("Window") << "setDisplayResolution failed, "
<< width << "x" << height << "x" << bits << " @ " << refresh << LL_ENDL;
<< width << "x" << height << " @ " << refresh << LL_ENDL;
}
return success;
@ -3564,7 +3557,7 @@ bool LLWindowWin32::setFullscreenResolution()
{
if (mFullscreen)
{
return setDisplayResolution( mFullscreenWidth, mFullscreenHeight, mFullscreenBits, mFullscreenRefresh);
return setDisplayResolution( mFullscreenWidth, mFullscreenHeight, mFullscreenRefresh);
}
else
{

View File

@ -150,7 +150,7 @@ protected:
virtual LLSD getNativeKeyData();
// Changes display resolution. Returns true if successful
bool setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh);
bool setDisplayResolution(S32 width, S32 height, S32 refresh);
// Go back to last fullscreen display resolution.
bool setFullscreenResolution();

View File

@ -11488,6 +11488,28 @@
<key>Value</key>
<string>fss.txt</string>
</map>
<key>StatsFrametimeSampleSeconds</key>
<map>
<key>Comment</key>
<string>The number of seconds to sample extended frametime data (percentiles, stddev).</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>5</integer>
</map>
<key>StatsFrametimeEventThreshold</key>
<map>
<key>Comment</key>
<string>The percentage that the frametime difference must exceed in order to register a frametime event. 0.1 = 10%, 0.25 = 25%, etc.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>F32</string>
<key>Value</key>
<real>0.1</real>
</map>
<key>SystemLanguage</key>
<map>
<key>Comment</key>
@ -16190,5 +16212,27 @@
<key>Value</key>
<integer>1</integer>
</map>
<key>MediaAutoPlayHuds</key>
<map>
<key>Comment</key>
<string>Automatically play HUD media</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>MediaFirstClickInteract</key>
<map>
<key>Comment</key>
<string>This setting controls which media (once loaded) does not require a first click to focus before interaction can begin. This allows clicks to be passed directly to media bypassing the focus click requirement. This setting is a bitfield, precomputed values are as follows: Disabled=0; Worn HUDs only=1; Owned objects=3; Friend objects=7; Group objects=15; Landowner objects=31; Any object=31; All MOAP=1073741824. For complete details see lltoolpie.h enum MediaFirstClickTypes.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>1</integer>
</map>
</map>
</llsd>

View File

@ -3469,11 +3469,14 @@ void LLAgent::initOriginGlobal(const LLVector3d &origin_global)
bool LLAgent::leftButtonGrabbed() const
{
const bool camera_mouse_look = gAgentCamera.cameraMouselook();
return (!camera_mouse_look && mControlsTakenCount[CONTROL_LBUTTON_DOWN_INDEX] > 0)
|| (camera_mouse_look && mControlsTakenCount[CONTROL_ML_LBUTTON_DOWN_INDEX] > 0)
|| (!camera_mouse_look && mControlsTakenPassedOnCount[CONTROL_LBUTTON_DOWN_INDEX] > 0)
|| (camera_mouse_look && mControlsTakenPassedOnCount[CONTROL_ML_LBUTTON_DOWN_INDEX] > 0);
if (gAgentCamera.cameraMouselook())
{
return mControlsTakenCount[CONTROL_ML_LBUTTON_DOWN_INDEX] > 0;
}
else
{
return mControlsTakenCount[CONTROL_LBUTTON_DOWN_INDEX] > 0;
}
}
bool LLAgent::rotateGrabbed() const

View File

@ -1988,16 +1988,6 @@ LLVector3d LLAgentCamera::calcCameraPositionTargetGlobal(bool *hit_limit)
isConstrained = true;
}
}
// JC - Could constrain camera based on parcel stuff here.
// LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromPosGlobal(camera_position_global);
//
// if (regionp && !regionp->mParcelOverlay->isBuildCameraAllowed(regionp->getPosRegionFromGlobal(camera_position_global)))
// {
// camera_position_global = last_position_global;
//
// isConstrained = true;
// }
}
// Don't let camera go underground

View File

@ -5679,9 +5679,9 @@ void LLAppViewer::forceErrorThreadCrash()
thread->start();
}
void LLAppViewer::initMainloopTimeout(const std::string& state, F32 secs)
void LLAppViewer::initMainloopTimeout(std::string_view state, F32 secs)
{
if(!mMainloopTimeout)
if (!mMainloopTimeout)
{
mMainloopTimeout = new LLWatchdogTimeout();
resumeMainloopTimeout(state, secs);
@ -5690,20 +5690,20 @@ void LLAppViewer::initMainloopTimeout(const std::string& state, F32 secs)
void LLAppViewer::destroyMainloopTimeout()
{
if(mMainloopTimeout)
if (mMainloopTimeout)
{
delete mMainloopTimeout;
mMainloopTimeout = NULL;
mMainloopTimeout = nullptr;
}
}
void LLAppViewer::resumeMainloopTimeout(const std::string& state, F32 secs)
void LLAppViewer::resumeMainloopTimeout(std::string_view state, F32 secs)
{
if(mMainloopTimeout)
if (mMainloopTimeout)
{
if(secs < 0.0f)
if (secs < 0.0f)
{
static LLCachedControl<F32> mainloop_timeout(gSavedSettings, "MainloopTimeoutDefault", 60);
static LLCachedControl<F32> mainloop_timeout(gSavedSettings, "MainloopTimeoutDefault", 60.f);
secs = mainloop_timeout;
}
@ -5714,19 +5714,19 @@ void LLAppViewer::resumeMainloopTimeout(const std::string& state, F32 secs)
void LLAppViewer::pauseMainloopTimeout()
{
if(mMainloopTimeout)
if (mMainloopTimeout)
{
mMainloopTimeout->stop();
}
}
void LLAppViewer::pingMainloopTimeout(const std::string& state, F32 secs)
void LLAppViewer::pingMainloopTimeout(std::string_view state, F32 secs)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_APP;
if(mMainloopTimeout)
if (mMainloopTimeout)
{
if(secs < 0.0f)
if (secs < 0.0f)
{
static LLCachedControl<F32> mainloop_timeout(gSavedSettings, "MainloopTimeoutDefault", 60);
secs = mainloop_timeout;

View File

@ -197,11 +197,11 @@ public:
// For thread debugging.
// llstartup needs to control init.
// llworld, send_agent_pause() also controls pause/resume.
void initMainloopTimeout(const std::string& state, F32 secs = -1.0f);
void initMainloopTimeout(std::string_view state, F32 secs = -1.0f);
void destroyMainloopTimeout();
void pauseMainloopTimeout();
void resumeMainloopTimeout(const std::string& state = "", F32 secs = -1.0f);
void pingMainloopTimeout(const std::string& state, F32 secs = -1.0f);
void resumeMainloopTimeout(std::string_view state = "", F32 secs = -1.0f);
void pingMainloopTimeout(std::string_view state, F32 secs = -1.0f);
// Handle the 'login completed' event.
// *NOTE:Mani Fix this for login abstraction!!

View File

@ -816,6 +816,29 @@ bool LLAppViewerWin32::reportCrashToBugsplat(void* pExcepInfo)
return false;
}
bool LLAppViewerWin32::initWindow()
{
// This is a workaround/hotfix for a change in Windows 11 24H2 (and possibly later)
// Where the window width and height need to correctly reflect an available FullScreen size
if (gSavedSettings.getBOOL("FullScreen"))
{
DEVMODE dev_mode;
::ZeroMemory(&dev_mode, sizeof(DEVMODE));
dev_mode.dmSize = sizeof(DEVMODE);
if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode))
{
gSavedSettings.setU32("WindowWidth", dev_mode.dmPelsWidth);
gSavedSettings.setU32("WindowHeight", dev_mode.dmPelsHeight);
}
else
{
LL_WARNS("AppInit") << "Unable to set WindowWidth and WindowHeight for FullScreen mode" << LL_ENDL;
}
}
return LLAppViewer::initWindow();
}
void LLAppViewerWin32::initLoggingAndGetLastDuration()
{
LLAppViewer::initLoggingAndGetLastDuration();

View File

@ -46,6 +46,7 @@ public:
bool reportCrashToBugsplat(void* pExcepInfo) override;
protected:
bool initWindow() override; // Override to initialize the viewer's window.
void initLoggingAndGetLastDuration() override; // Override to clean stack_trace info.
void initConsole() override; // Initialize OS level debugging console.
bool initHardwareTest() override; // Win32 uses DX9 to test hardware.

View File

@ -1042,7 +1042,9 @@ void LLFloaterUIPreview::getExecutablePath(const std::vector<std::string>& filen
{
CFStringRef executable_cfstr = (CFStringRef)CFDictionaryGetValue(bundleInfoDict, CFSTR("CFBundleExecutable")); // get the name of the actual executable (e.g. TextEdit or firefox-bin)
int max_file_length = 256; // (max file name length is 255 in OSX)
char executable_buf[max_file_length];
// Xcode 26: VLAs are a clang extension. Just create the buffer and delete it after.
char *executable_buf = new char [max_file_length];
if(CFStringGetCString(executable_cfstr, executable_buf, max_file_length, kCFStringEncodingMacRoman)) // convert CFStringRef to char*
{
executable_path += std::string("/Contents/MacOS/") + std::string(executable_buf); // append path to executable directory and then executable name to exec path
@ -1052,6 +1054,7 @@ void LLFloaterUIPreview::getExecutablePath(const std::vector<std::string>& filen
std::string warning = "Unable to get CString from CFString for executable path";
popupAndPrintWarning(warning);
}
delete [] executable_buf;
}
else
{

View File

@ -327,9 +327,6 @@ LLFloaterWorldMap::LLFloaterWorldMap(const LLSD& key)
mSetToUserPosition(true),
mTrackedLocation(0.0,0.0,0.0),
mTrackedStatus(LLTracker::TRACKING_NOTHING),
mListFriendCombo(nullptr),
mListLandmarkCombo(nullptr),
mListSearchResults(nullptr),
mParcelInfoObserver(nullptr),
mShowParcelInfo(false)
{
@ -383,32 +380,33 @@ bool LLFloaterWorldMap::postBuild()
mTeleportCoordSpinY = getChild<LLUICtrl>("teleport_coordinate_y");
mTeleportCoordSpinZ = getChild<LLUICtrl>("teleport_coordinate_z");
LLComboBox *avatar_combo = getChild<LLComboBox>("friend combo");
avatar_combo->selectFirstItem();
avatar_combo->setPrearrangeCallback( boost::bind(&LLFloaterWorldMap::onAvatarComboPrearrange, this) );
avatar_combo->setTextChangedCallback( boost::bind(&LLFloaterWorldMap::onComboTextEntry, this) );
mListFriendCombo = dynamic_cast<LLCtrlListInterface *>(avatar_combo);
mFriendCombo = getChild<LLComboBox>("friend combo");
mFriendCombo->selectFirstItem();
mFriendCombo->setPrearrangeCallback(boost::bind(&LLFloaterWorldMap::onAvatarComboPrearrange, this));
mFriendCombo->setTextChangedCallback(boost::bind(&LLFloaterWorldMap::onComboTextEntry, this));
mLocationEditor = getChild<LLSearchEditor>("location");
mLocationEditor->setFocusChangedCallback(boost::bind(&LLFloaterWorldMap::onLocationFocusChanged, this, _1));
mLocationEditor->setTextChangedCallback( boost::bind(&LLFloaterWorldMap::onSearchTextEntry, this));
mLocationEditor->setTextChangedCallback(boost::bind(&LLFloaterWorldMap::onSearchTextEntry, this));
getChild<LLScrollListCtrl>("search_results")->setDoubleClickCallback( boost::bind(&LLFloaterWorldMap::onClickTeleportBtn, this));
mListSearchResults = childGetListInterface("search_results");
mSearchResults = getChild<LLScrollListCtrl>("search_results");
mSearchResults->setDoubleClickCallback(boost::bind(&LLFloaterWorldMap::onClickTeleportBtn, this));
LLComboBox *landmark_combo = getChild<LLComboBox>( "landmark combo");
landmark_combo->selectFirstItem();
landmark_combo->setPrearrangeCallback( boost::bind(&LLFloaterWorldMap::onLandmarkComboPrearrange, this) );
landmark_combo->setTextChangedCallback( boost::bind(&LLFloaterWorldMap::onComboTextEntry, this) );
mListLandmarkCombo = dynamic_cast<LLCtrlListInterface *>(landmark_combo);
mLandmarkCombo = getChild<LLComboBox>("landmark combo");
mLandmarkCombo->selectFirstItem();
mLandmarkCombo->setPrearrangeCallback(boost::bind(&LLFloaterWorldMap::onLandmarkComboPrearrange, this));
mLandmarkCombo->setTextChangedCallback(boost::bind(&LLFloaterWorldMap::onComboTextEntry, this));
mZoomSlider = getChild<LLSliderCtrl>("zoom slider");
F32 slider_zoom = mMapView->getZoom();
mZoomSlider->setValue(slider_zoom);
mTrackCtrlsPanel = getChild<LLPanel>("layout_panel_4");
mSearchButton = getChild<LLButton>("DoSearch");
getChild<LLPanel>("expand_btn_panel")->setMouseDownCallback(boost::bind(&LLFloaterWorldMap::onExpandCollapseBtn, this));
setDefaultBtn(NULL);
mTrackCtrlsPanel->setDefaultBtn(nullptr);
onChangeMaturity();
@ -608,7 +606,6 @@ void LLFloaterWorldMap::draw()
}
mTeleportButton->setEnabled((bool)tracking_status);
// getChildView("Clear")->setEnabled((bool)tracking_status);
mShowDestinationButton->setEnabled((bool)tracking_status || LLWorldMap::getInstance()->isTracking());
mCopySlurlButton->setEnabled((mSLURL.isValid()) );
@ -700,26 +697,24 @@ void LLFloaterWorldMap::requestParcelInfo(const LLVector3d& pos_global, const LL
}
}
void LLFloaterWorldMap::trackAvatar( const LLUUID& avatar_id, const std::string& name )
void LLFloaterWorldMap::trackAvatar(const LLUUID& avatar_id, const std::string& name)
{
mShowParcelInfo = false;
LLCtrlSelectionInterface *iface = childGetSelectionInterface("friend combo");
if (!iface) return;
buildAvatarIDList();
if(iface->setCurrentByID(avatar_id) || gAgent.isGodlike())
if (mFriendCombo->setCurrentByID(avatar_id) || gAgent.isGodlike())
{
// *HACK: Adjust Z values automatically for liaisons & gods so
// they swoop down when they click on the map. Requested
// convenience.
if(gAgent.isGodlike())
if (gAgent.isGodlike())
{
mTeleportCoordSpinZ->setValue(LLSD(200.f));
}
// Don't re-request info if we already have it or we won't have it in time to teleport
if (mTrackedStatus != LLTracker::TRACKING_AVATAR || avatar_id != mTrackedAvatarID)
{
mTrackedStatus = LLTracker::TRACKING_AVATAR;
mTrackedStatus = LLTracker::TRACKING_AVATAR;
mTrackedAvatarID = avatar_id;
LLTracker::trackAvatar(avatar_id, name);
}
@ -728,52 +723,45 @@ void LLFloaterWorldMap::trackAvatar( const LLUUID& avatar_id, const std::string&
{
LLTracker::stopTracking(false);
}
setDefaultBtn("Teleport");
mTrackCtrlsPanel->setDefaultBtn(mTeleportButton);
}
void LLFloaterWorldMap::trackLandmark( const LLUUID& landmark_item_id )
void LLFloaterWorldMap::trackLandmark(const LLUUID& landmark_item_id)
{
mShowParcelInfo = false;
LLCtrlSelectionInterface *iface = childGetSelectionInterface("landmark combo");
if (!iface) return;
buildLandmarkIDLists();
bool found = false;
S32 idx;
S32 idx;
for (idx = 0; idx < mLandmarkItemIDList.size(); idx++)
{
if ( mLandmarkItemIDList.at(idx) == landmark_item_id)
if (mLandmarkItemIDList.at(idx) == landmark_item_id)
{
found = true;
break;
}
}
if (found && iface->setCurrentByID( landmark_item_id ) )
if (found && mLandmarkCombo->setCurrentByID(landmark_item_id))
{
LLUUID asset_id = mLandmarkAssetIDList.at( idx );
std::string name;
LLComboBox* combo = getChild<LLComboBox>( "landmark combo");
if (combo) name = combo->getSimple();
mTrackedStatus = LLTracker::TRACKING_LANDMARK;
LLTracker::trackLandmark(mLandmarkAssetIDList.at( idx ), // assetID
mLandmarkItemIDList.at( idx ), // itemID
name); // name
LLUUID asset_id = mLandmarkAssetIDList.at(idx);
std::string name = mLandmarkCombo->getSimple();
mTrackedStatus = LLTracker::TRACKING_LANDMARK;
LLTracker::trackLandmark(mLandmarkAssetIDList.at(idx), // assetID
mLandmarkItemIDList.at(idx), // itemID
name); // name
if( asset_id != sHomeID )
if (asset_id != sHomeID)
{
// start the download process
gLandmarkList.getAsset( asset_id);
gLandmarkList.getAsset(asset_id);
}
// We have to download both region info and landmark data, so set busy. JC
// getWindow()->incBusyCount();
}
else
{
LLTracker::stopTracking(false);
}
setDefaultBtn("Teleport");
mTrackCtrlsPanel->setDefaultBtn(mTeleportButton);
}
@ -782,7 +770,7 @@ void LLFloaterWorldMap::trackEvent(const LLItemInfo &event_info)
mShowParcelInfo = false;
mTrackedStatus = LLTracker::TRACKING_LOCATION;
LLTracker::trackLocation(event_info.getGlobalPosition(), event_info.getName(), event_info.getToolTip(), LLTracker::LOCATION_EVENT);
setDefaultBtn("Teleport");
mTrackCtrlsPanel->setDefaultBtn(mTeleportButton);
}
void LLFloaterWorldMap::trackGenericItem(const LLItemInfo &item)
@ -790,7 +778,7 @@ void LLFloaterWorldMap::trackGenericItem(const LLItemInfo &item)
mShowParcelInfo = false;
mTrackedStatus = LLTracker::TRACKING_LOCATION;
LLTracker::trackLocation(item.getGlobalPosition(), item.getName(), item.getToolTip(), LLTracker::LOCATION_ITEM);
setDefaultBtn("Teleport");
mTrackCtrlsPanel->setDefaultBtn(mTeleportButton);
}
void LLFloaterWorldMap::trackLocation(const LLVector3d& pos_global)
@ -804,7 +792,7 @@ void LLFloaterWorldMap::trackLocation(const LLVector3d& pos_global)
S32 world_x = S32(pos_global.mdV[0] / 256);
S32 world_y = S32(pos_global.mdV[1] / 256);
LLWorldMapMessage::getInstance()->sendMapBlockRequest(world_x, world_y, world_x, world_y, true);
setDefaultBtn("");
mTrackCtrlsPanel->setDefaultBtn(nullptr);
// clicked on a non-region - turn off coord display
enableTeleportCoordsDisplay( false );
@ -818,7 +806,7 @@ void LLFloaterWorldMap::trackLocation(const LLVector3d& pos_global)
LLTracker::stopTracking(false);
LLWorldMap::getInstance()->setTracking(pos_global);
LLWorldMap::getInstance()->setTrackingInvalid();
setDefaultBtn("");
mTrackCtrlsPanel->setDefaultBtn(nullptr);
// clicked on a down region - turn off coord display
enableTeleportCoordsDisplay( false );
@ -849,7 +837,7 @@ void LLFloaterWorldMap::trackLocation(const LLVector3d& pos_global)
// we have a valid region - turn on coord display
enableTeleportCoordsDisplay( true );
setDefaultBtn("Teleport");
mTrackCtrlsPanel->setDefaultBtn(mTeleportButton);
}
// enable/disable teleport destination coordinates
@ -964,7 +952,7 @@ void LLFloaterWorldMap::trackURL(const std::string& region_name, S32 x_coord, S3
local_pos.mV[VZ] = (F32)z_coord;
LLVector3d global_pos = sim_info->getGlobalPos(local_pos);
trackLocation(global_pos);
setDefaultBtn("Teleport");
mTrackCtrlsPanel->setDefaultBtn(mTeleportButton);
}
else
{
@ -1025,17 +1013,14 @@ void LLFloaterWorldMap::observeFriends()
void LLFloaterWorldMap::friendsChanged()
{
LLAvatarTracker& t = LLAvatarTracker::instance();
const LLUUID& avatar_id = t.getAvatarID();
LLAvatarTracker& t = LLAvatarTracker::instance();
const LLUUID& avatar_id = t.getAvatarID();
buildAvatarIDList();
if(avatar_id.notNull())
if (avatar_id.notNull())
{
LLCtrlSelectionInterface *iface = childGetSelectionInterface("friend combo");
const LLRelationship* buddy_info = t.getBuddyInfo(avatar_id);
if(!iface ||
!iface->setCurrentByID(avatar_id) ||
(buddy_info && !buddy_info->isRightGrantedFrom(LLRelationship::GRANT_MAP_LOCATION)) ||
gAgent.isGodlike())
if (!mFriendCombo->setCurrentByID(avatar_id) ||
(buddy_info && !buddy_info->isRightGrantedFrom(LLRelationship::GRANT_MAP_LOCATION)) || gAgent.isGodlike())
{
LLTracker::stopTracking(false);
}
@ -1045,15 +1030,12 @@ void LLFloaterWorldMap::friendsChanged()
// No longer really builds a list. Instead, just updates mAvatarCombo.
void LLFloaterWorldMap::buildAvatarIDList()
{
LLCtrlListInterface *list = mListFriendCombo;
if (!list) return;
// Delete all but the "None" entry
S32 list_size = list->getItemCount();
S32 list_size = mFriendCombo->getItemCount();
if (list_size > 1)
{
list->selectItemRange(1, -1);
list->operateOnSelection(LLCtrlListInterface::OP_DELETE);
mFriendCombo->selectItemRange(1, -1);
mFriendCombo->operateOnSelection(LLCtrlListInterface::OP_DELETE);
}
// Get all of the calling cards for avatar that are currently online
@ -1061,29 +1043,26 @@ void LLFloaterWorldMap::buildAvatarIDList()
LLAvatarTracker::instance().applyFunctor(collector);
LLCollectMappableBuddies::buddy_map_t::iterator it;
LLCollectMappableBuddies::buddy_map_t::iterator end;
it = collector.mMappable.begin();
it = collector.mMappable.begin();
end = collector.mMappable.end();
for( ; it != end; ++it)
for (; it != end; ++it)
{
list->addSimpleElement((*it).second, ADD_BOTTOM, (*it).first);
mFriendCombo->addSimpleElement((*it).second, ADD_BOTTOM, (*it).first);
}
list->setCurrentByID( LLAvatarTracker::instance().getAvatarID() );
list->selectFirstItem();
mFriendCombo->setCurrentByID(LLAvatarTracker::instance().getAvatarID());
mFriendCombo->selectFirstItem();
}
void LLFloaterWorldMap::buildLandmarkIDLists()
{
LLCtrlListInterface *list = mListLandmarkCombo;
if (!list) return;
// Delete all but the "None" entry
S32 list_size = list->getItemCount();
S32 list_size = mLandmarkCombo->getItemCount();
if (list_size > 1)
{
list->selectItemRange(1, -1);
list->operateOnSelection(LLCtrlListInterface::OP_DELETE);
mLandmarkCombo->selectItemRange(1, -1);
mLandmarkCombo->operateOnSelection(LLCtrlListInterface::OP_DELETE);
}
mLandmarkItemIDList.clear();
@ -1115,13 +1094,13 @@ void LLFloaterWorldMap::buildLandmarkIDLists()
{
LLInventoryItem* item = items.at(i);
list->addSimpleElement(item->getName(), ADD_BOTTOM, item->getUUID());
mLandmarkCombo->addSimpleElement(item->getName(), ADD_BOTTOM, item->getUUID());
mLandmarkAssetIDList.push_back( item->getAssetUUID() );
mLandmarkItemIDList.push_back( item->getUUID() );
}
list->selectFirstItem();
mLandmarkCombo->selectFirstItem();
}
@ -1139,10 +1118,9 @@ F32 LLFloaterWorldMap::getDistanceToDestination(const LLVector3d &destination,
void LLFloaterWorldMap::clearLocationSelection(bool clear_ui, bool dest_reached)
{
LLCtrlListInterface *list = mListSearchResults;
if (list && (!dest_reached || (list->getItemCount() == 1)))
if (!dest_reached || (mSearchResults->getItemCount() == 1))
{
list->operateOnAll(LLCtrlListInterface::OP_DELETE);
mSearchResults->operateOnAll(LLCtrlListInterface::OP_DELETE);
}
LLWorldMap::getInstance()->cancelTracking();
mCompletingRegionName = "";
@ -1153,11 +1131,7 @@ void LLFloaterWorldMap::clearLandmarkSelection(bool clear_ui)
{
if (clear_ui || !childHasKeyboardFocus("landmark combo"))
{
LLCtrlListInterface *list = mListLandmarkCombo;
if (list)
{
list->selectByValue( "None" );
}
mLandmarkCombo->selectByValue("None");
}
}
@ -1167,10 +1141,9 @@ void LLFloaterWorldMap::clearAvatarSelection(bool clear_ui)
if (clear_ui || !childHasKeyboardFocus("friend combo"))
{
mTrackedStatus = LLTracker::TRACKING_NOTHING;
LLCtrlListInterface *list = mListFriendCombo;
if (list && list->getSelectedValue().asString() != "None")
if (mFriendCombo->getSelectedValue().asString() != "None")
{
list->selectByValue( "None" );
mFriendCombo->selectByValue("None");
}
}
}
@ -1226,25 +1199,21 @@ void LLFloaterWorldMap::onGoHome()
}
void LLFloaterWorldMap::onLandmarkComboPrearrange( )
void LLFloaterWorldMap::onLandmarkComboPrearrange()
{
if( mIsClosing )
if (mIsClosing)
{
return;
}
LLCtrlListInterface *list = mListLandmarkCombo;
if (!list) return;
LLUUID current_choice = list->getCurrentID();
LLUUID current_choice = mLandmarkCombo->getCurrentID();
buildLandmarkIDLists();
if( current_choice.isNull() || !list->setCurrentByID( current_choice ) )
if (current_choice.isNull() || !mLandmarkCombo->setCurrentByID(current_choice))
{
LLTracker::stopTracking(false);
}
}
void LLFloaterWorldMap::onComboTextEntry()
@ -1264,33 +1233,28 @@ void LLFloaterWorldMap::onSearchTextEntry( )
void LLFloaterWorldMap::onLandmarkComboCommit()
{
if( mIsClosing )
if (mIsClosing)
{
return;
}
LLCtrlListInterface *list = mListLandmarkCombo;
if (!list) return;
LLUUID asset_id;
LLUUID item_id = list->getCurrentID();
LLUUID item_id = mLandmarkCombo->getCurrentID();
LLTracker::stopTracking(false);
//RN: stopTracking() clears current combobox selection, need to reassert it here
list->setCurrentByID(item_id);
// RN: stopTracking() clears current combobox selection, need to reassert it here
mLandmarkCombo->setCurrentByID(item_id);
if( item_id.isNull() )
{
}
else if( item_id == sHomeID )
if (item_id.isNull()) {}
else if (item_id == sHomeID)
{
asset_id = sHomeID;
}
else
{
LLInventoryItem* item = gInventory.getItem( item_id );
if( item )
LLInventoryItem* item = gInventory.getItem(item_id);
if (item)
{
asset_id = item->getAssetUUID();
}
@ -1301,34 +1265,31 @@ void LLFloaterWorldMap::onLandmarkComboCommit()
}
}
trackLandmark( item_id);
trackLandmark(item_id);
onShowTargetBtn();
// Reset to user postion if nothing is tracked
mSetToUserPosition = ( LLTracker::getTrackingStatus() == LLTracker::TRACKING_NOTHING );
mSetToUserPosition = (LLTracker::getTrackingStatus() == LLTracker::TRACKING_NOTHING);
}
// static
void LLFloaterWorldMap::onAvatarComboPrearrange( )
void LLFloaterWorldMap::onAvatarComboPrearrange()
{
if( mIsClosing )
if (mIsClosing)
{
return;
}
LLCtrlListInterface *list = mListFriendCombo;
if (!list) return;
LLUUID current_choice;
if( LLAvatarTracker::instance().haveTrackingInfo() )
if (LLAvatarTracker::instance().haveTrackingInfo())
{
current_choice = LLAvatarTracker::instance().getAvatarID();
}
buildAvatarIDList();
if( !list->setCurrentByID( current_choice ) || current_choice.isNull() )
if (!mFriendCombo->setCurrentByID(current_choice) || current_choice.isNull())
{
LLTracker::stopTracking(false);
}
@ -1336,26 +1297,21 @@ void LLFloaterWorldMap::onAvatarComboPrearrange( )
void LLFloaterWorldMap::onAvatarComboCommit()
{
if( mIsClosing )
if (mIsClosing)
{
return;
}
LLCtrlListInterface *list = mListFriendCombo;
if (!list) return;
const LLUUID& new_avatar_id = list->getCurrentID();
const LLUUID& new_avatar_id = mFriendCombo->getCurrentID();
if (new_avatar_id.notNull())
{
std::string name;
LLComboBox* combo = getChild<LLComboBox>("friend combo");
if (combo) name = combo->getSimple();
std::string name = mFriendCombo->getSimple();
trackAvatar(new_avatar_id, name);
onShowTargetBtn();
}
else
{ // Reset to user postion if nothing is tracked
mSetToUserPosition = ( LLTracker::getTrackingStatus() == LLTracker::TRACKING_NOTHING );
{ // Reset to user postion if nothing is tracked
mSetToUserPosition = (LLTracker::getTrackingStatus() == LLTracker::TRACKING_NOTHING);
}
}
@ -1375,11 +1331,11 @@ void LLFloaterWorldMap::updateSearchEnabled()
if (childHasKeyboardFocus("location") &&
mLocationEditor->getValue().asString().length() > 0)
{
setDefaultBtn("DoSearch");
mTrackCtrlsPanel->setDefaultBtn(mSearchButton);
}
else
{
setDefaultBtn(NULL);
mTrackCtrlsPanel->setDefaultBtn(nullptr);
}
}
@ -1487,8 +1443,9 @@ void LLFloaterWorldMap::onExpandCollapseBtn()
std::string image_name = getString(toggle_collapse ? "expand_icon" : "collapse_icon");
std::string tooltip = getString(toggle_collapse ? "expand_tooltip" : "collapse_tooltip");
getChild<LLIconCtrl>("expand_collapse_icon")->setImage(LLUI::getUIImage(image_name));
getChild<LLIconCtrl>("expand_collapse_icon")->setToolTip(tooltip);
LLIconCtrl* expandCollapseIcon = getChild<LLIconCtrl>("expand_collapse_icon");
expandCollapseIcon->setImage(LLUI::getUIImage(image_name));
expandCollapseIcon->setToolTip(tooltip);
getChild<LLPanel>("expand_btn_panel")->setToolTip(tooltip);
}
@ -1680,9 +1637,9 @@ void LLFloaterWorldMap::teleportToAvatar()
void LLFloaterWorldMap::flyToAvatar()
{
if( LLAvatarTracker::instance().haveTrackingInfo() )
if (LLAvatarTracker::instance().haveTrackingInfo())
{
gAgent.startAutoPilotGlobal( LLAvatarTracker::instance().getGlobalPos() );
gAgent.startAutoPilotGlobal(LLAvatarTracker::instance().getGlobalPos());
}
}
@ -1693,8 +1650,7 @@ void LLFloaterWorldMap::updateSims(bool found_null_sim)
return;
}
LLScrollListCtrl *list = getChild<LLScrollListCtrl>("search_results");
list->operateOnAll(LLCtrlListInterface::OP_DELETE);
mSearchResults->operateOnAll(LLCtrlListInterface::OP_DELETE);
auto name_length = mCompletingRegionName.length();
@ -1722,7 +1678,7 @@ void LLFloaterWorldMap::updateSims(bool found_null_sim)
value["id"] = info->getName();
value["columns"][0]["column"] = "sim_name";
value["columns"][0]["value"] = info->getName();
list->addElement(value);
mSearchResults->addElement(value);
num_results++;
}
}
@ -1737,21 +1693,21 @@ void LLFloaterWorldMap::updateSims(bool found_null_sim)
// if match found, highlight it and go
if (!match.isUndefined())
{
list->selectByValue(match);
mSearchResults->selectByValue(match);
}
// else select first found item
else
{
list->selectFirstItem();
mSearchResults->selectFirstItem();
}
getChild<LLUICtrl>("search_results")->setFocus(true);
mSearchResults->setFocus(true);
onCommitSearchResult();
}
else
{
// if we found nothing, say "none"
list->setCommentText(LLTrans::getString("worldmap_results_none_found"));
list->operateOnAll(LLCtrlListInterface::OP_DESELECT);
mSearchResults->setCommentText(LLTrans::getString("worldmap_results_none_found"));
mSearchResults->operateOnAll(LLCtrlListInterface::OP_DESELECT);
}
}
@ -1765,11 +1721,7 @@ void LLFloaterWorldMap::onTeleportFinished()
void LLFloaterWorldMap::onCommitSearchResult()
{
LLCtrlListInterface *list = mListSearchResults;
if (!list) return;
LLSD selected_value = list->getSelectedValue();
std::string sim_name = selected_value.asString();
std::string sim_name = mSearchResults->getSelectedValue().asString();
if (sim_name.empty())
{
return;
@ -1785,7 +1737,7 @@ void LLFloaterWorldMap::onCommitSearchResult()
{
LLVector3d pos_global = info->getGlobalOrigin();
const F64 SIM_COORD_DEFAULT = 128.0;
constexpr F64 SIM_COORD_DEFAULT = 128.0;
LLVector3 pos_local(SIM_COORD_DEFAULT, SIM_COORD_DEFAULT, 0.0f);
// Did this value come from a trackURL() request?
@ -1800,7 +1752,7 @@ void LLFloaterWorldMap::onCommitSearchResult()
mLocationEditor->setValue(sim_name);
trackLocation(pos_global);
setDefaultBtn("Teleport");
mTrackCtrlsPanel->setDefaultBtn(mTeleportButton);
break;
}
}

View File

@ -51,6 +51,8 @@ class LLCheckBoxCtrl;
class LLSliderCtrl;
class LLSpinCtrl;
class LLSearchEditor;
class LLComboBox;
class LLScrollListCtrl;
class LLWorldMapParcelInfoObserver : public LLRemoteParcelInfoObserver
{
@ -218,14 +220,11 @@ private:
LLUUID mTrackedAvatarID;
LLSLURL mSLURL;
LLCtrlListInterface * mListFriendCombo;
LLCtrlListInterface * mListLandmarkCombo;
LLCtrlListInterface * mListSearchResults;
LLButton* mTeleportButton = nullptr;
LLButton* mShowDestinationButton = nullptr;
LLButton* mCopySlurlButton = nullptr;
LLButton* mGoHomeButton = nullptr;
LLButton* mSearchButton = nullptr;
LLCheckBoxCtrl* mPeopleCheck = nullptr;
LLCheckBoxCtrl* mInfohubCheck = nullptr;
@ -245,6 +244,13 @@ private:
LLSliderCtrl* mZoomSlider = nullptr;
LLComboBox* mLandmarkCombo = nullptr;
LLComboBox* mFriendCombo = nullptr;
LLScrollListCtrl* mSearchResults = nullptr;
LLPanel* mTrackCtrlsPanel = nullptr;
boost::signals2::connection mTeleportFinishConnection;
};

View File

@ -225,10 +225,6 @@ void LLHUDText::renderText()
}
text_color = segment_iter->mColor;
if (mOnHUDAttachment)
{
text_color = linearColor4(text_color);
}
text_color.mV[VALPHA] *= alpha_factor;
hud_render_text(segment_iter->getText(), render_position, *fontp, style, shadow, x_offset, y_offset, text_color, mOnHUDAttachment);

View File

@ -959,7 +959,7 @@ void LLInventoryFilter::setFilterSubString(const std::string& string)
boost::char_separator<char> sep("+");
tokenizer tokens(filter_sub_string_new, sep);
for (auto token_iter : tokens)
for (const auto& token_iter : tokens)
{
mFilterTokens.push_back(token_iter);
}
@ -1025,7 +1025,7 @@ void LLInventoryFilter::setFilterSubString(const std::string& string)
}
// Cancel out UUID once the search string is modified
if (mFilterOps.mFilterTypes == FILTERTYPE_UUID)
if (mFilterOps.mFilterTypes & FILTERTYPE_UUID)
{
mFilterOps.mFilterTypes &= ~FILTERTYPE_UUID;
mFilterOps.mFilterUUID = LLUUID::null;
@ -1707,7 +1707,7 @@ std::string LLInventoryFilter::getEmptyLookupMessage(bool is_empty_folder) const
}
}
bool LLInventoryFilter::areDateLimitsSet()
bool LLInventoryFilter::areDateLimitsSet() const
{
return mFilterOps.mMinDate != time_min()
|| mFilterOps.mMaxDate != time_max()

View File

@ -341,7 +341,7 @@ public:
bool checkAgainstFilterThumbnails(const LLUUID& object_id) const;
private:
bool areDateLimitsSet();
bool areDateLimitsSet() const;
bool checkAgainstFilterSubString(const std::string& desc) const;
bool checkAgainstFilterType(const class LLFolderViewModelItemInventory* listener) const;
bool checkAgainstFilterType(const LLInventoryItem* item) const;

View File

@ -2350,9 +2350,9 @@ bool can_move_to_my_outfits_as_outfit(LLInventoryModel* model, LLInventoryCatego
return false;
}
if (items->size() == 0)
if (items->size() == 0 && inv_cat->getPreferredType() != LLFolderType::FT_OUTFIT)
{
// Nothing to move(create)
// Nothing to create an outfit folder from
return false;
}

View File

@ -162,6 +162,36 @@ void LLPanelFace::updateSelectedGLTFMaterials(std::function<void(LLGLTFMaterial*
LLSelectMgr::getInstance()->getSelection()->applyToTEs(&select_func);
}
void LLPanelFace::updateSelectedGLTFMaterialsWithScale(std::function<void(LLGLTFMaterial*, const F32, const F32)> func)
{
struct LLSelectedTEGLTFMaterialFunctor : public LLSelectedTEFunctor
{
LLSelectedTEGLTFMaterialFunctor(std::function<void(LLGLTFMaterial*, const F32, const F32)> func) : mFunc(func) {}
virtual ~LLSelectedTEGLTFMaterialFunctor() {};
bool apply(LLViewerObject* object, S32 face) override
{
LLGLTFMaterial new_override;
const LLTextureEntry* tep = object->getTE(face);
if (tep->getGLTFMaterialOverride())
{
new_override = *tep->getGLTFMaterialOverride();
}
U32 s_axis = VX;
U32 t_axis = VY;
LLPrimitive::getTESTAxes(face, &s_axis, &t_axis);
mFunc(&new_override, object->getScale().mV[s_axis], object->getScale().mV[t_axis]);
LLGLTFMaterialList::queueModify(object, face, &new_override);
return true;
}
std::function<void(LLGLTFMaterial*, const F32, const F32)> mFunc;
} select_func(func);
LLSelectMgr::getInstance()->getSelection()->applyToTEs(&select_func);
}
template<typename T>
void readSelectedGLTFMaterial(std::function<T(const LLGLTFMaterial*)> func, T& value, bool& identical, bool has_tolerance, T tolerance)
{
@ -182,6 +212,36 @@ void readSelectedGLTFMaterial(std::function<T(const LLGLTFMaterial*)> func, T& v
identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue(&select_func, value, has_tolerance, tolerance);
}
void getSelectedGLTFMaterialMaxRepeats(LLGLTFMaterial::TextureInfo channel, F32& repeats, bool& identical)
{
// The All channel should read base color values
if (channel == LLGLTFMaterial::TextureInfo::GLTF_TEXTURE_INFO_COUNT)
channel = LLGLTFMaterial::TextureInfo::GLTF_TEXTURE_INFO_BASE_COLOR;
struct LLSelectedTEGetGLTFMaterialMaxRepeatsFunctor : public LLSelectedTEGetFunctor<F32>
{
LLSelectedTEGetGLTFMaterialMaxRepeatsFunctor(LLGLTFMaterial::TextureInfo channel) : mChannel(channel) {}
virtual ~LLSelectedTEGetGLTFMaterialMaxRepeatsFunctor() {};
F32 get(LLViewerObject* object, S32 face) override
{
const LLTextureEntry* tep = object->getTE(face);
const LLGLTFMaterial* render_material = tep->getGLTFRenderMaterial();
if (!render_material)
return 0.f;
U32 s_axis = VX;
U32 t_axis = VY;
LLPrimitive::getTESTAxes(face, &s_axis, &t_axis);
F32 repeats_u = render_material->mTextureTransform[mChannel].mScale[VX] / object->getScale().mV[s_axis];
F32 repeats_v = render_material->mTextureTransform[mChannel].mScale[VY] / object->getScale().mV[t_axis];
return llmax(repeats_u, repeats_v);
}
LLGLTFMaterial::TextureInfo mChannel;
} max_repeats_func(channel);
identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue(&max_repeats_func, repeats);
}
BOOST_STATIC_ASSERT(MATTYPE_DIFFUSE == LLRender::DIFFUSE_MAP && MATTYPE_NORMAL == LLRender::NORMAL_MAP && MATTYPE_SPECULAR == LLRender::SPECULAR_MAP);
//
@ -322,6 +382,7 @@ bool LLPanelFace::postBuild()
getChildSetCommitCallback(mPBRScaleU, "gltfTextureScaleU", [&](LLUICtrl*, const LLSD&) { onCommitGLTFTextureScaleU(); });
getChildSetCommitCallback(mPBRScaleV, "gltfTextureScaleV", [&](LLUICtrl*, const LLSD&) { onCommitGLTFTextureScaleV(); });
getChildSetCommitCallback(mPBRRepeat, "gltfRptctrl", [&](LLUICtrl*, const LLSD&) { onCommitGLTFRepeatsPerMeter(); });
getChildSetCommitCallback(mPBRRotate, "gltfTextureRotation", [&](LLUICtrl*, const LLSD&) { onCommitGLTFRotation(); });
getChildSetCommitCallback(mPBROffsetU, "gltfTextureOffsetU", [&](LLUICtrl*, const LLSD&) { onCommitGLTFTextureOffsetU(); });
getChildSetCommitCallback(mPBROffsetV, "gltfTextureOffsetV", [&](LLUICtrl*, const LLSD&) { onCommitGLTFTextureOffsetV(); });
@ -1398,9 +1459,18 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
spec_scale_s = editable ? spec_scale_s : 1.0f;
spec_scale_s *= identical_planar_texgen ? 2.0f : 1.0f;
mTexScaleU->setValue(diff_scale_s);
mShinyScaleU->setValue(spec_scale_s);
mBumpyScaleU->setValue(norm_scale_s);
if (force_set_values)
{
mTexScaleU->forceSetValue(diff_scale_s);
mShinyScaleU->forceSetValue(spec_scale_s);
mBumpyScaleU->forceSetValue(norm_scale_s);
}
else
{
mTexScaleU->setValue(diff_scale_s);
mShinyScaleU->setValue(spec_scale_s);
mBumpyScaleU->setValue(norm_scale_s);
}
mTexScaleU->setEnabled(editable && has_material);
mShinyScaleU->setEnabled(editable && has_material && specmap_id.notNull());
@ -1448,13 +1518,16 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
if (force_set_values)
{
mTexScaleV->forceSetValue(diff_scale_t);
mShinyScaleV->forceSetValue(spec_scale_t);
mBumpyScaleV->forceSetValue(norm_scale_t);
}
else
{
mTexScaleV->setValue(diff_scale_t);
mShinyScaleV->setValue(spec_scale_t);
mBumpyScaleV->setValue(norm_scale_t);
}
mShinyScaleV->setValue(spec_scale_t);
mBumpyScaleV->setValue(norm_scale_t);
mTexScaleV->setTentative(LLSD(diff_scale_tentative));
mShinyScaleV->setTentative(LLSD(spec_scale_tentative));
@ -1594,36 +1667,57 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
F32 repeats_norm = 1.f;
F32 repeats_spec = 1.f;
F32 repeats_pbr_basecolor = 1.f;
F32 repeats_pbr_metallic_roughness = 1.f;
F32 repeats_pbr_normal = 1.f;
F32 repeats_pbr_emissive = 1.f;
bool identical_diff_repeats = false;
bool identical_norm_repeats = false;
bool identical_spec_repeats = false;
LLSelectedTE::getMaxDiffuseRepeats(repeats_diff, identical_diff_repeats);
LLSelectedTEMaterial::getMaxNormalRepeats(repeats_norm, identical_norm_repeats);
LLSelectedTEMaterial::getMaxSpecularRepeats(repeats_spec, identical_spec_repeats);
bool identical_pbr_basecolor_repeats = false;
bool identical_pbr_metallic_roughness_repeats = false;
bool identical_pbr_normal_repeats = false;
bool identical_pbr_emissive_repeats = false;
{
LLSpinCtrl* repeats_spin_ctrl = nullptr;
S32 index = mComboTexGen ? mComboTexGen->getCurrentIndex() : 0;
bool enabled = editable && (index != 1);
bool identical_repeats = true;
S32 material_selection = mComboMatMedia->getCurrentIndex();
F32 repeats = 1.0f;
U32 material_type = MATTYPE_DIFFUSE;
if (material_selection == MATMEDIA_MATERIAL)
LLRender::eTexIndex material_channel = LLRender::DIFFUSE_MAP;
if (material_selection != MATMEDIA_PBR)
{
material_type = mRadioMaterialType->getSelectedIndex();
repeats_spin_ctrl = mTexRepeat;
material_channel = getMatTextureChannel();
LLSelectedTE::getMaxDiffuseRepeats(repeats_diff, identical_diff_repeats);
LLSelectedTEMaterial::getMaxNormalRepeats(repeats_norm, identical_norm_repeats);
LLSelectedTEMaterial::getMaxSpecularRepeats(repeats_spec, identical_spec_repeats);
}
else if (material_selection == MATMEDIA_PBR)
{
repeats_spin_ctrl = mPBRRepeat;
enabled = editable && has_pbr_material;
material_type = mRadioPbrType->getSelectedIndex();
material_channel = getPBRTextureChannel();
getSelectedGLTFMaterialMaxRepeats(LLGLTFMaterial::TextureInfo::GLTF_TEXTURE_INFO_BASE_COLOR,
repeats_pbr_basecolor, identical_pbr_basecolor_repeats);
getSelectedGLTFMaterialMaxRepeats(LLGLTFMaterial::TextureInfo::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS,
repeats_pbr_metallic_roughness, identical_pbr_metallic_roughness_repeats);
getSelectedGLTFMaterialMaxRepeats(LLGLTFMaterial::TextureInfo::GLTF_TEXTURE_INFO_NORMAL,
repeats_pbr_normal, identical_pbr_normal_repeats);
getSelectedGLTFMaterialMaxRepeats(LLGLTFMaterial::TextureInfo::GLTF_TEXTURE_INFO_EMISSIVE,
repeats_pbr_emissive, identical_pbr_emissive_repeats);
}
switch (material_type)
switch (material_channel)
{
default:
case MATTYPE_DIFFUSE:
case LLRender::DIFFUSE_MAP:
if (material_selection != MATMEDIA_PBR)
{
enabled = editable && !id.isNull();
@ -1631,7 +1725,7 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
identical_repeats = identical_diff_repeats;
repeats = repeats_diff;
break;
case MATTYPE_SPECULAR:
case LLRender::SPECULAR_MAP:
if (material_selection != MATMEDIA_PBR)
{
enabled = (editable && ((shiny == SHINY_TEXTURE) && !specmap_id.isNull()));
@ -1639,7 +1733,7 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
identical_repeats = identical_spec_repeats;
repeats = repeats_spec;
break;
case MATTYPE_NORMAL:
case LLRender::NORMAL_MAP:
if (material_selection != MATMEDIA_PBR)
{
enabled = (editable && ((bumpy == BUMPY_TEXTURE) && !normmap_id.isNull()));
@ -1647,6 +1741,23 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
identical_repeats = identical_norm_repeats;
repeats = repeats_norm;
break;
case LLRender::NUM_TEXTURE_CHANNELS:
case LLRender::BASECOLOR_MAP:
identical_repeats = identical_pbr_basecolor_repeats;
repeats = repeats_pbr_basecolor;
break;
case LLRender::METALLIC_ROUGHNESS_MAP:
identical_repeats = identical_pbr_metallic_roughness_repeats;
repeats = repeats_pbr_metallic_roughness;
break;
case LLRender::GLTF_NORMAL_MAP:
identical_repeats = identical_pbr_normal_repeats;
repeats = repeats_pbr_normal;
break;
case LLRender::EMISSIVE_MAP:
identical_repeats = identical_pbr_emissive_repeats;
repeats = repeats_pbr_emissive;
break;
}
bool repeats_tentative = !identical_repeats;
@ -1654,14 +1765,14 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
if (force_set_values)
{
// onCommit, previosly edited element updates related ones
mTexRepeat->forceSetValue(editable ? repeats : 1.0f);
repeats_spin_ctrl->forceSetValue(editable ? repeats : 1.0f);
}
else
{
mTexRepeat->setValue(editable ? repeats : 1.0f);
repeats_spin_ctrl->setValue(editable ? repeats : 1.0f);
}
mTexRepeat->setTentative(LLSD(repeats_tentative));
mTexRepeat->setEnabled(has_material && !identical_planar_texgen && enabled);
repeats_spin_ctrl->setTentative(LLSD(repeats_tentative));
repeats_spin_ctrl->setEnabled(!identical_planar_texgen && enabled);
}
}
@ -1807,6 +1918,7 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
}
mLabelColorTransp->setEnabled(false);
mTexRepeat->setEnabled(false);
mPBRRepeat->setEnabled(false);
mLabelTexGen->setEnabled(false);
mLabelShininess->setEnabled(false);
mLabelBumpiness->setEnabled(false);
@ -2002,6 +2114,7 @@ void LLPanelFace::updateVisibilityGLTF(LLViewerObject* objectp /*= nullptr */)
mPBRRotate->setVisible(show_pbr);
mPBROffsetU->setVisible(show_pbr);
mPBROffsetV->setVisible(show_pbr);
mPBRRepeat->setVisible(show_pbr);
}
void LLPanelFace::updateCopyTexButton()
@ -3652,18 +3765,8 @@ void LLPanelFace::onCommitRepeatsPerMeter()
if (gSavedSettings.getBOOL("SyncMaterialSettings"))
{
LLSelectMgr::getInstance()->selectionTexScaleAutofit(repeats_per_meter);
mBumpyScaleU->setValue(obj_scale_s * repeats_per_meter);
mBumpyScaleV->setValue(obj_scale_t * repeats_per_meter);
LLSelectedTEMaterial::setNormalRepeatX(this, obj_scale_s * repeats_per_meter);
LLSelectedTEMaterial::setNormalRepeatY(this, obj_scale_t * repeats_per_meter);
mShinyScaleU->setValue(obj_scale_s * repeats_per_meter);
mShinyScaleV->setValue(obj_scale_t * repeats_per_meter);
LLSelectedTEMaterial::setSpecularRepeatX(this, obj_scale_s * repeats_per_meter);
LLSelectedTEMaterial::setSpecularRepeatY(this, obj_scale_t * repeats_per_meter);
LLSelectedTEMaterial::selectionNormalScaleAutofit(this, repeats_per_meter);
LLSelectedTEMaterial::selectionSpecularScaleAutofit(this, repeats_per_meter);
}
else
{
@ -3674,18 +3777,10 @@ void LLPanelFace::onCommitRepeatsPerMeter()
LLSelectMgr::getInstance()->selectionTexScaleAutofit(repeats_per_meter);
break;
case MATTYPE_NORMAL:
mBumpyScaleU->setValue(obj_scale_s * repeats_per_meter);
mBumpyScaleV->setValue(obj_scale_t * repeats_per_meter);
LLSelectedTEMaterial::setNormalRepeatX(this, obj_scale_s * repeats_per_meter);
LLSelectedTEMaterial::setNormalRepeatY(this, obj_scale_t * repeats_per_meter);
LLSelectedTEMaterial::selectionNormalScaleAutofit(this, repeats_per_meter);
break;
case MATTYPE_SPECULAR:
mBumpyScaleU->setValue(obj_scale_s * repeats_per_meter);
mBumpyScaleV->setValue(obj_scale_t * repeats_per_meter);
LLSelectedTEMaterial::setSpecularRepeatX(this, obj_scale_s * repeats_per_meter);
LLSelectedTEMaterial::setSpecularRepeatY(this, obj_scale_t * repeats_per_meter);
LLSelectedTEMaterial::selectionSpecularScaleAutofit(this, repeats_per_meter);
break;
default:
llassert(false);
@ -3696,6 +3791,21 @@ void LLPanelFace::onCommitRepeatsPerMeter()
updateUI(true);
}
// Commit the number of GLTF repeats per meter
void LLPanelFace::onCommitGLTFRepeatsPerMeter()
{
F32 repeats_per_meter = (F32)mPBRRepeat->getValue().asReal();
LLGLTFMaterial::TextureInfo material_type = getPBRTextureInfo();
updateGLTFTextureTransformWithScale(material_type, [&](LLGLTFMaterial::TextureTransform* new_transform, F32 scale_s, F32 scale_t)
{
new_transform->mScale.mV[VX] = scale_s * repeats_per_meter;
new_transform->mScale.mV[VY] = scale_t * repeats_per_meter;
});
updateUI(true);
}
struct LLPanelFaceSetMediaFunctor : public LLSelectedTEFunctor
{
virtual bool apply(LLViewerObject* object, S32 te)
@ -4795,6 +4905,29 @@ void LLPanelFace::updateGLTFTextureTransform(std::function<void(LLGLTFMaterial::
}
}
void LLPanelFace::updateGLTFTextureTransformWithScale(const LLGLTFMaterial::TextureInfo texture_info, std::function<void(LLGLTFMaterial::TextureTransform*, const F32, const F32)> edit)
{
if (texture_info == LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT)
{
updateSelectedGLTFMaterialsWithScale([&](LLGLTFMaterial* new_override, const F32 scale_s, const F32 scale_t)
{
for (U32 i = 0; i < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; ++i)
{
LLGLTFMaterial::TextureTransform& new_transform = new_override->mTextureTransform[(LLGLTFMaterial::TextureInfo)i];
edit(&new_transform, scale_s, scale_t);
}
});
}
else
{
updateSelectedGLTFMaterialsWithScale([&](LLGLTFMaterial* new_override, const F32 scale_s, const F32 scale_t)
{
LLGLTFMaterial::TextureTransform& new_transform = new_override->mTextureTransform[texture_info];
edit(&new_transform, scale_s, scale_t);
});
}
}
void LLPanelFace::setMaterialOverridesFromSelection()
{
const LLGLTFMaterial::TextureInfo texture_info = getPBRTextureInfo();
@ -4870,8 +5003,9 @@ void LLPanelFace::setMaterialOverridesFromSelection()
}
}
mPBRScaleU->setValue(transform.mScale[VX]);
mPBRScaleV->setValue(transform.mScale[VY]);
// Force set scales just in case they were set by repeats per meter and their spinner is focused
mPBRScaleU->forceSetValue(transform.mScale[VX]);
mPBRScaleV->forceSetValue(transform.mScale[VY]);
mPBRRotate->setValue(transform.mRotation * RAD_TO_DEG);
mPBROffsetU->setValue(transform.mOffset[VX]);
mPBROffsetV->setValue(transform.mOffset[VY]);
@ -4881,6 +5015,12 @@ void LLPanelFace::setMaterialOverridesFromSelection()
mPBRRotate->setTentative(!rotation_same);
mPBROffsetU->setTentative(!offset_u_same);
mPBROffsetV->setTentative(!offset_v_same);
F32 repeats = 1.f;
bool identical = false;
getSelectedGLTFMaterialMaxRepeats(getPBRDropChannel(), repeats, identical);
mPBRRepeat->forceSetValue(repeats);
mPBRRepeat->setTentative(!identical || !scale_u_same || !scale_v_same);
}
void LLPanelFace::Selection::connect()
@ -5374,6 +5514,62 @@ void LLPanelFace::LLSelectedTEMaterial::getCurrentDiffuseAlphaMode(U8& diffuse_a
identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &get_diff_mode, diffuse_alpha_mode);
}
void LLPanelFace::LLSelectedTEMaterial::selectionNormalScaleAutofit(LLPanelFace* panel_face, F32 repeats_per_meter)
{
struct f : public LLSelectedTEFunctor
{
LLPanelFace* mFacePanel;
F32 mRepeatsPerMeter;
f(LLPanelFace* face_panel, const F32& repeats_per_meter) : mFacePanel(face_panel), mRepeatsPerMeter(repeats_per_meter) {}
bool apply(LLViewerObject* object, S32 te)
{
if (object->permModify())
{
// Compute S,T to axis mapping
U32 s_axis, t_axis;
if (!LLPrimitive::getTESTAxes(te, &s_axis, &t_axis))
return true;
F32 new_s = object->getScale().mV[s_axis] * mRepeatsPerMeter;
F32 new_t = object->getScale().mV[t_axis] * mRepeatsPerMeter;
setNormalRepeatX(mFacePanel, new_s, te);
setNormalRepeatY(mFacePanel, new_t, te);
}
return true;
}
} setfunc(panel_face, repeats_per_meter);
LLSelectMgr::getInstance()->getSelection()->applyToTEs(&setfunc);
}
void LLPanelFace::LLSelectedTEMaterial::selectionSpecularScaleAutofit(LLPanelFace* panel_face, F32 repeats_per_meter)
{
struct f : public LLSelectedTEFunctor
{
LLPanelFace* mFacePanel;
F32 mRepeatsPerMeter;
f(LLPanelFace* face_panel, const F32& repeats_per_meter) : mFacePanel(face_panel), mRepeatsPerMeter(repeats_per_meter) {}
bool apply(LLViewerObject* object, S32 te)
{
if (object->permModify())
{
// Compute S,T to axis mapping
U32 s_axis, t_axis;
if (!LLPrimitive::getTESTAxes(te, &s_axis, &t_axis))
return true;
F32 new_s = object->getScale().mV[s_axis] * mRepeatsPerMeter;
F32 new_t = object->getScale().mV[t_axis] * mRepeatsPerMeter;
setSpecularRepeatX(mFacePanel, new_s, te);
setSpecularRepeatY(mFacePanel, new_t, te);
}
return true;
}
} setfunc(panel_face, repeats_per_meter);
LLSelectMgr::getInstance()->getSelection()->applyToTEs(&setfunc);
}
void LLPanelFace::LLSelectedTE::getObjectScaleS(F32& scale_s, bool& identical)
{
struct LLSelectedTEGetObjectScaleS : public LLSelectedTEGetFunctor<F32>

View File

@ -250,6 +250,7 @@ protected:
void onCommitGLTFRotation();
void onCommitGLTFTextureOffsetU();
void onCommitGLTFTextureOffsetV();
void onCommitGLTFRepeatsPerMeter();
void onClickAutoFix();
void onAlignTexture();
@ -361,6 +362,7 @@ private:
LLButton* mDelMedia { nullptr };
LLSpinCtrl* mPBRScaleU { nullptr };
LLSpinCtrl* mPBRScaleV { nullptr };
LLSpinCtrl* mPBRRepeat { nullptr };
LLSpinCtrl* mPBRRotate { nullptr };
LLSpinCtrl* mPBROffsetU { nullptr };
LLSpinCtrl* mPBROffsetV { nullptr };
@ -554,7 +556,9 @@ private:
void updateVisibilityGLTF(LLViewerObject* objectp = nullptr);
void updateSelectedGLTFMaterials(std::function<void(LLGLTFMaterial*)> func);
void updateSelectedGLTFMaterialsWithScale(std::function<void(LLGLTFMaterial*, const F32, const F32)> func);
void updateGLTFTextureTransform(std::function<void(LLGLTFMaterial::TextureTransform*)> edit);
void updateGLTFTextureTransformWithScale(const LLGLTFMaterial::TextureInfo texture_info, std::function<void(LLGLTFMaterial::TextureTransform*, const F32, const F32)> edit);
void setMaterialOverridesFromSelection();
@ -649,6 +653,8 @@ public:
static void getMaxSpecularRepeats(F32& repeats, bool& identical);
static void getMaxNormalRepeats(F32& repeats, bool& identical);
static void getCurrentDiffuseAlphaMode(U8& diffuse_alpha_mode, bool& identical, bool diffuse_texture_has_alpha);
static void selectionNormalScaleAutofit(LLPanelFace* panel_face, F32 repeats_per_meter);
static void selectionSpecularScaleAutofit(LLPanelFace* panel_face, F32 repeats_per_meter);
DEF_GET_MAT_STATE(LLUUID, const LLUUID&, getNormalID, LLUUID::null, false, LLUUID::null);
DEF_GET_MAT_STATE(LLUUID, const LLUUID&, getSpecularID, LLUUID::null, false, LLUUID::null);

View File

@ -54,17 +54,16 @@
//////////////////////////////////////////////////////////////////////////
LLPanelGroupBulkImpl::LLPanelGroupBulkImpl(const LLUUID& group_id) :
mGroupID(group_id),
mBulkAgentList(NULL),
mOKButton(NULL),
mBulkAgentList(nullptr),
mOKButton(nullptr),
mAddButton(nullptr),
mRemoveButton(NULL),
mGroupName(NULL),
mRemoveButton(nullptr),
mGroupName(nullptr),
mLoadingText(),
mTooManySelected(),
mCloseCallback(NULL),
mCloseCallbackUserData(NULL),
mAvatarNameCacheConnection(),
mRoleNames(NULL),
mCloseCallback(nullptr),
mCloseCallbackUserData(nullptr),
mRoleNames(nullptr),
mOwnerWarning(),
mAlreadyInGroup(),
mConfirmedOwnerInvite(false),
@ -74,10 +73,13 @@ LLPanelGroupBulkImpl::LLPanelGroupBulkImpl(const LLUUID& group_id) :
LLPanelGroupBulkImpl::~LLPanelGroupBulkImpl()
{
if (mAvatarNameCacheConnection.connected())
for (auto& [id, connection] : mAvatarNameCacheConnections)
{
mAvatarNameCacheConnection.disconnect();
if (connection.connected())
connection.disconnect();
}
mAvatarNameCacheConnections.clear();
}
void LLPanelGroupBulkImpl::callbackClickAdd(LLPanelGroupBulk* panelp)
@ -124,43 +126,42 @@ void LLPanelGroupBulkImpl::callbackSelect(LLUICtrl* ctrl, void* userdata)
void LLPanelGroupBulkImpl::addUsers(const uuid_vec_t& agent_ids)
{
std::vector<std::string> names;
for (const LLUUID& agent_id : agent_ids)
{
LLAvatarName av_name;
if (LLAvatarNameCache::get(agent_id, &av_name))
if (LLAvatarName av_name; LLAvatarNameCache::get(agent_id, &av_name))
{
onAvatarNameCache(agent_id, av_name);
}
else
{
if (mAvatarNameCacheConnection.connected())
if (auto found = mAvatarNameCacheConnections.find(agent_id); found != mAvatarNameCacheConnections.end())
{
mAvatarNameCacheConnection.disconnect();
if (found->second.connected())
found->second.disconnect();
mAvatarNameCacheConnections.erase(found);
}
// *TODO : Add a callback per avatar name being fetched.
mAvatarNameCacheConnection = LLAvatarNameCache::get(agent_id,
mAvatarNameCacheConnections.try_emplace(agent_id, LLAvatarNameCache::get(agent_id,
[&](const LLUUID& agent_id, const LLAvatarName& av_name)
{
onAvatarNameCache(agent_id, av_name);
});
}));
}
}
}
void LLPanelGroupBulkImpl::onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name)
{
if (mAvatarNameCacheConnection.connected())
if (auto found = mAvatarNameCacheConnections.find(agent_id); found != mAvatarNameCacheConnections.end())
{
mAvatarNameCacheConnection.disconnect();
if (found->second.connected())
found->second.disconnect();
mAvatarNameCacheConnections.erase(found);
}
std::vector<std::string> names;
uuid_vec_t agent_ids;
agent_ids.push_back(agent_id);
names.push_back(av_name.getCompleteName());
addUsers(names, agent_ids);
addUsers({ av_name.getCompleteName() }, { agent_id });
}
void LLPanelGroupBulkImpl::handleRemove()
@ -232,7 +233,7 @@ void LLPanelGroupBulkImpl::addUsers(const std::vector<std::string>& names, const
}
}
void LLPanelGroupBulkImpl::setGroupName(std::string name)
void LLPanelGroupBulkImpl::setGroupName(const std::string& name)
{
if (mGroupName)
{
@ -337,12 +338,7 @@ void LLPanelGroupBulk::updateGroupData()
void LLPanelGroupBulk::addUserCallback(const LLUUID& id, const LLAvatarName& av_name)
{
std::vector<std::string> names;
uuid_vec_t agent_ids;
agent_ids.push_back(id);
names.push_back(av_name.getAccountName());
mImplementation->addUsers(names, agent_ids);
mImplementation->addUsers({ av_name.getAccountName() }, { id });
}
void LLPanelGroupBulk::setCloseCallback(void (*close_callback)(void*), void* data)

View File

@ -59,7 +59,7 @@ public:
void handleSelection();
void addUsers(const std::vector<std::string>& names, const uuid_vec_t& agent_ids);
void setGroupName(std::string name);
void setGroupName(const std::string& name);
public:
@ -84,7 +84,7 @@ public:
void (*mCloseCallback)(void* data);
void* mCloseCallbackUserData;
boost::signals2::connection mAvatarNameCacheConnection;
std::map<LLUUID, boost::signals2::connection> mAvatarNameCacheConnections;
// The following are for the LLPanelGroupInvite subclass only.
// These aren't needed for LLPanelGroupBulkBan, but if we have to add another

View File

@ -78,9 +78,9 @@ static LLPanelInjector<LLPanelMainInventory> t_inventory("panel_main_inventory")
class LLFloaterInventoryFinder : public LLFloater
{
public:
LLFloaterInventoryFinder( LLPanelMainInventory* inventory_view);
virtual void draw();
/*virtual*/ bool postBuild();
LLFloaterInventoryFinder(LLPanelMainInventory* inventory_view);
void draw();
bool postBuild();
void changeFilter(LLInventoryFilter* filter);
void updateElementsFromFilter();
bool getCheckShowEmpty();
@ -90,17 +90,35 @@ public:
void onCreatorSelfFilterCommit();
void onCreatorOtherFilterCommit();
static void onTimeAgo(LLUICtrl*, void *);
static void onCloseBtn(void* user_data);
static void selectAllTypes(void* user_data);
static void selectNoTypes(void* user_data);
void onTimeAgo();
void onCloseBtn();
void selectAllTypes();
void selectNoTypes();
private:
LLPanelMainInventory* mPanelMainInventory;
LLSpinCtrl* mSpinSinceDays;
LLSpinCtrl* mSpinSinceHours;
LLCheckBoxCtrl* mCreatorSelf;
LLCheckBoxCtrl* mCreatorOthers;
LLInventoryFilter* mFilter;
LLPanelMainInventory* mPanelMainInventory{ nullptr };
LLSpinCtrl* mSpinSinceDays{ nullptr };
LLSpinCtrl* mSpinSinceHours{ nullptr };
LLCheckBoxCtrl* mCreatorSelf{ nullptr };
LLCheckBoxCtrl* mCreatorOthers{ nullptr };
LLInventoryFilter* mFilter{ nullptr };
LLCheckBoxCtrl* mCheckAnimation{ nullptr };
LLCheckBoxCtrl* mCheckCallingCard{ nullptr };
LLCheckBoxCtrl* mCheckClothing{ nullptr };
LLCheckBoxCtrl* mCheckGesture{ nullptr };
LLCheckBoxCtrl* mCheckLandmark{ nullptr };
LLCheckBoxCtrl* mCheckMaterial{ nullptr };
LLCheckBoxCtrl* mCheckNotecard{ nullptr };
LLCheckBoxCtrl* mCheckObject{ nullptr };
LLCheckBoxCtrl* mCheckScript{ nullptr };
LLCheckBoxCtrl* mCheckSounds{ nullptr };
LLCheckBoxCtrl* mCheckTexture{ nullptr };
LLCheckBoxCtrl* mCheckSnapshot{ nullptr };
LLCheckBoxCtrl* mCheckSettings{ nullptr };
LLCheckBoxCtrl* mCheckShowEmpty{ nullptr };
LLCheckBoxCtrl* mCheckSinceLogoff{ nullptr };
LLRadioGroup* mRadioDateSearchDirection{ nullptr };
};
///----------------------------------------------------------------------------
@ -734,7 +752,6 @@ bool LLPanelMainInventory::filtersVisible(void* user_data)
void LLPanelMainInventory::onClearSearch()
{
bool initially_active = false;
LLFloater *finder = getFinder();
if (mActivePanel && (getActivePanel() != mWornItemsPanel))
{
initially_active = mActivePanel->getFilter().isNotDefault();
@ -743,9 +760,9 @@ void LLPanelMainInventory::onClearSearch()
mActivePanel->setFilterLinks(LLInventoryFilter::FILTERLINK_INCLUDE_LINKS);
}
if (finder)
if (LLFloaterInventoryFinder* finder = getFinder())
{
LLFloaterInventoryFinder::selectAllTypes(finder);
finder->selectAllTypes();
}
// re-open folders that were initially open in case filter was active
@ -1145,36 +1162,53 @@ bool LLFloaterInventoryFinder::postBuild()
const LLRect& viewrect = mPanelMainInventory->getRect();
setRect(LLRect(viewrect.mLeft - getRect().getWidth(), viewrect.mTop, viewrect.mLeft, viewrect.mTop - getRect().getHeight()));
childSetAction("All", selectAllTypes, this);
childSetAction("None", selectNoTypes, this);
childSetAction("All", [this](LLUICtrl*, const LLSD&) { selectAllTypes(); });
childSetAction("None", [this](LLUICtrl*, const LLSD&) { selectNoTypes(); });
mSpinSinceHours = getChild<LLSpinCtrl>("spin_hours_ago");
childSetCommitCallback("spin_hours_ago", onTimeAgo, this);
mSpinSinceHours->setCommitCallback([this](LLUICtrl*, const LLSD&) { onTimeAgo(); });
mSpinSinceDays = getChild<LLSpinCtrl>("spin_days_ago");
childSetCommitCallback("spin_days_ago", onTimeAgo, this);
mSpinSinceDays->setCommitCallback([this](LLUICtrl*, const LLSD&) { onTimeAgo(); });
mCreatorSelf = getChild<LLCheckBoxCtrl>("check_created_by_me");
mCreatorOthers = getChild<LLCheckBoxCtrl>("check_created_by_others");
mCreatorSelf->setCommitCallback(boost::bind(&LLFloaterInventoryFinder::onCreatorSelfFilterCommit, this));
mCreatorOthers->setCommitCallback(boost::bind(&LLFloaterInventoryFinder::onCreatorOtherFilterCommit, this));
childSetAction("Close", onCloseBtn, this);
mCheckAnimation = getChild<LLCheckBoxCtrl>("check_animation");
mCheckCallingCard = getChild<LLCheckBoxCtrl>("check_calling_card");
mCheckClothing = getChild<LLCheckBoxCtrl>("check_clothing");
mCheckGesture = getChild<LLCheckBoxCtrl>("check_gesture");
mCheckLandmark = getChild<LLCheckBoxCtrl>("check_landmark");
mCheckMaterial = getChild<LLCheckBoxCtrl>("check_material");
mCheckNotecard = getChild<LLCheckBoxCtrl>("check_notecard");
mCheckObject = getChild<LLCheckBoxCtrl>("check_object");
mCheckScript = getChild<LLCheckBoxCtrl>("check_script");
mCheckSounds = getChild<LLCheckBoxCtrl>("check_sound");
mCheckTexture = getChild<LLCheckBoxCtrl>("check_texture");
mCheckSnapshot = getChild<LLCheckBoxCtrl>("check_snapshot");
mCheckSettings = getChild<LLCheckBoxCtrl>("check_settings");
mCheckShowEmpty = getChild<LLCheckBoxCtrl>("check_show_empty");
mCheckSinceLogoff = getChild<LLCheckBoxCtrl>("check_since_logoff");
mRadioDateSearchDirection = getChild<LLRadioGroup>("date_search_direction");
childSetAction("Close", [this](LLUICtrl*, const LLSD&) { onCloseBtn(); });
updateElementsFromFilter();
return true;
}
void LLFloaterInventoryFinder::onTimeAgo(LLUICtrl *ctrl, void *user_data)
void LLFloaterInventoryFinder::onTimeAgo()
{
LLFloaterInventoryFinder *self = (LLFloaterInventoryFinder *)user_data;
if (!self) return;
if ( self->mSpinSinceDays->get() || self->mSpinSinceHours->get() )
if (mSpinSinceDays->get() || mSpinSinceHours->get())
{
self->getChild<LLUICtrl>("check_since_logoff")->setValue(false);
mCheckSinceLogoff->setValue(false);
U32 days = (U32)self->mSpinSinceDays->get();
U32 hours = (U32)self->mSpinSinceHours->get();
U32 days = (U32)mSpinSinceDays->get();
U32 hours = (U32)mSpinSinceHours->get();
if (hours >= 24)
{
// Try to handle both cases of spinner clicking and text input in a sensible fashion as best as possible.
@ -1190,11 +1224,11 @@ void LLFloaterInventoryFinder::onTimeAgo(LLUICtrl *ctrl, void *user_data)
days = hours / 24;
}
hours = (U32)hours % 24;
self->mSpinSinceHours->setFocus(false);
self->mSpinSinceDays->setFocus(false);
self->mSpinSinceDays->set((F32)days);
self->mSpinSinceHours->set((F32)hours);
self->mSpinSinceHours->setFocus(true);
mSpinSinceHours->setFocus(false);
mSpinSinceDays->setFocus(false);
mSpinSinceDays->set((F32)days);
mSpinSinceHours->set((F32)hours);
mSpinSinceHours->setFocus(true);
}
}
}
@ -1223,29 +1257,28 @@ void LLFloaterInventoryFinder::updateElementsFromFilter()
// update the ui elements
setTitle(mFilter->getName());
getChild<LLUICtrl>("check_animation")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_ANIMATION));
mCheckAnimation->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_ANIMATION));
mCheckCallingCard->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_CALLINGCARD));
mCheckClothing->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_WEARABLE));
mCheckGesture->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_GESTURE));
mCheckLandmark->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_LANDMARK));
mCheckMaterial->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_MATERIAL));
mCheckNotecard->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_NOTECARD));
mCheckObject->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_OBJECT));
mCheckScript->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_LSL));
mCheckSounds->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_SOUND));
mCheckTexture->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_TEXTURE));
mCheckSnapshot->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_SNAPSHOT));
mCheckSettings->setValue((S32)(filter_types & 0x1 << LLInventoryType::IT_SETTINGS));
mCheckShowEmpty->setValue(show_folders == LLInventoryFilter::SHOW_ALL_FOLDERS);
getChild<LLUICtrl>("check_calling_card")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_CALLINGCARD));
getChild<LLUICtrl>("check_clothing")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_WEARABLE));
getChild<LLUICtrl>("check_gesture")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_GESTURE));
getChild<LLUICtrl>("check_landmark")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_LANDMARK));
getChild<LLUICtrl>("check_material")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_MATERIAL));
getChild<LLUICtrl>("check_notecard")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_NOTECARD));
getChild<LLUICtrl>("check_object")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_OBJECT));
getChild<LLUICtrl>("check_script")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_LSL));
getChild<LLUICtrl>("check_sound")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_SOUND));
getChild<LLUICtrl>("check_texture")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_TEXTURE));
getChild<LLUICtrl>("check_snapshot")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_SNAPSHOT));
getChild<LLUICtrl>("check_settings")->setValue((S32)(filter_types & 0x1 << LLInventoryType::IT_SETTINGS));
getChild<LLUICtrl>("check_show_empty")->setValue(show_folders == LLInventoryFilter::SHOW_ALL_FOLDERS);
mCreatorSelf->setValue(show_created_by_me);
mCreatorOthers->setValue(show_created_by_others);
getChild<LLUICtrl>("check_created_by_me")->setValue(show_created_by_me);
getChild<LLUICtrl>("check_created_by_others")->setValue(show_created_by_others);
getChild<LLUICtrl>("check_since_logoff")->setValue(mFilter->isSinceLogoff());
mCheckSinceLogoff->setValue(mFilter->isSinceLogoff());
mSpinSinceHours->set((F32)(hours % 24));
mSpinSinceDays->set((F32)(hours / 24));
getChild<LLRadioGroup>("date_search_direction")->setSelectedIndex(date_search_direction);
mRadioDateSearchDirection->setSelectedIndex(date_search_direction);
}
void LLFloaterInventoryFinder::draw()
@ -1253,80 +1286,80 @@ void LLFloaterInventoryFinder::draw()
U64 filter = 0xffffffffffffffffULL;
bool filtered_by_all_types = true;
if (!getChild<LLUICtrl>("check_animation")->getValue())
if (!mCheckAnimation->getValue())
{
filter &= ~(0x1 << LLInventoryType::IT_ANIMATION);
filtered_by_all_types = false;
}
if (!getChild<LLUICtrl>("check_calling_card")->getValue())
if (!mCheckCallingCard->getValue())
{
filter &= ~(0x1 << LLInventoryType::IT_CALLINGCARD);
filtered_by_all_types = false;
}
if (!getChild<LLUICtrl>("check_clothing")->getValue())
if (!mCheckClothing->getValue())
{
filter &= ~(0x1 << LLInventoryType::IT_WEARABLE);
filtered_by_all_types = false;
}
if (!getChild<LLUICtrl>("check_gesture")->getValue())
if (!mCheckGesture->getValue())
{
filter &= ~(0x1 << LLInventoryType::IT_GESTURE);
filtered_by_all_types = false;
}
if (!getChild<LLUICtrl>("check_landmark")->getValue())
if (!mCheckLandmark->getValue())
{
filter &= ~(0x1 << LLInventoryType::IT_LANDMARK);
filtered_by_all_types = false;
}
if (!getChild<LLUICtrl>("check_material")->getValue())
if (!mCheckMaterial->getValue())
{
filter &= ~(0x1 << LLInventoryType::IT_MATERIAL);
filtered_by_all_types = false;
}
if (!getChild<LLUICtrl>("check_notecard")->getValue())
if (!mCheckNotecard->getValue())
{
filter &= ~(0x1 << LLInventoryType::IT_NOTECARD);
filtered_by_all_types = false;
}
if (!getChild<LLUICtrl>("check_object")->getValue())
if (!mCheckObject->getValue())
{
filter &= ~(0x1 << LLInventoryType::IT_OBJECT);
filter &= ~(0x1 << LLInventoryType::IT_ATTACHMENT);
filtered_by_all_types = false;
}
if (!getChild<LLUICtrl>("check_script")->getValue())
if (!mCheckScript->getValue())
{
filter &= ~(0x1 << LLInventoryType::IT_LSL);
filtered_by_all_types = false;
}
if (!getChild<LLUICtrl>("check_sound")->getValue())
if (!mCheckSounds->getValue())
{
filter &= ~(0x1 << LLInventoryType::IT_SOUND);
filtered_by_all_types = false;
}
if (!getChild<LLUICtrl>("check_texture")->getValue())
if (!mCheckTexture->getValue())
{
filter &= ~(0x1 << LLInventoryType::IT_TEXTURE);
filtered_by_all_types = false;
}
if (!getChild<LLUICtrl>("check_snapshot")->getValue())
if (!mCheckSnapshot->getValue())
{
filter &= ~(0x1 << LLInventoryType::IT_SNAPSHOT);
filtered_by_all_types = false;
}
if (!getChild<LLUICtrl>("check_settings")->getValue())
if (!mCheckSettings->getValue())
{
filter &= ~(0x1 << LLInventoryType::IT_SETTINGS);
filtered_by_all_types = false;
@ -1444,65 +1477,56 @@ void LLFloaterInventoryFinder::onCreatorOtherFilterCommit()
bool LLFloaterInventoryFinder::getCheckShowEmpty()
{
return getChild<LLUICtrl>("check_show_empty")->getValue();
return mCheckShowEmpty->getValue();
}
bool LLFloaterInventoryFinder::getCheckSinceLogoff()
{
return getChild<LLUICtrl>("check_since_logoff")->getValue();
return mCheckSinceLogoff->getValue();
}
U32 LLFloaterInventoryFinder::getDateSearchDirection()
{
return getChild<LLRadioGroup>("date_search_direction")->getSelectedIndex();
return mRadioDateSearchDirection->getSelectedIndex();
}
void LLFloaterInventoryFinder::onCloseBtn(void* user_data)
void LLFloaterInventoryFinder::onCloseBtn()
{
LLFloaterInventoryFinder* finderp = (LLFloaterInventoryFinder*)user_data;
finderp->closeFloater();
closeFloater();
}
// static
void LLFloaterInventoryFinder::selectAllTypes(void* user_data)
void LLFloaterInventoryFinder::selectAllTypes()
{
LLFloaterInventoryFinder* self = (LLFloaterInventoryFinder*)user_data;
if(!self) return;
self->getChild<LLUICtrl>("check_animation")->setValue(true);
self->getChild<LLUICtrl>("check_calling_card")->setValue(true);
self->getChild<LLUICtrl>("check_clothing")->setValue(true);
self->getChild<LLUICtrl>("check_gesture")->setValue(true);
self->getChild<LLUICtrl>("check_landmark")->setValue(true);
self->getChild<LLUICtrl>("check_material")->setValue(true);
self->getChild<LLUICtrl>("check_notecard")->setValue(true);
self->getChild<LLUICtrl>("check_object")->setValue(true);
self->getChild<LLUICtrl>("check_script")->setValue(true);
self->getChild<LLUICtrl>("check_sound")->setValue(true);
self->getChild<LLUICtrl>("check_texture")->setValue(true);
self->getChild<LLUICtrl>("check_snapshot")->setValue(true);
self->getChild<LLUICtrl>("check_settings")->setValue(true);
mCheckAnimation->setValue(true);
mCheckCallingCard->setValue(true);
mCheckClothing->setValue(true);
mCheckGesture->setValue(true);
mCheckLandmark->setValue(true);
mCheckMaterial->setValue(true);
mCheckNotecard->setValue(true);
mCheckObject->setValue(true);
mCheckScript->setValue(true);
mCheckSounds->setValue(true);
mCheckTexture->setValue(true);
mCheckSnapshot->setValue(true);
mCheckSettings->setValue(true);
}
//static
void LLFloaterInventoryFinder::selectNoTypes(void* user_data)
void LLFloaterInventoryFinder::selectNoTypes()
{
LLFloaterInventoryFinder* self = (LLFloaterInventoryFinder*)user_data;
if(!self) return;
self->getChild<LLUICtrl>("check_animation")->setValue(false);
self->getChild<LLUICtrl>("check_calling_card")->setValue(false);
self->getChild<LLUICtrl>("check_clothing")->setValue(false);
self->getChild<LLUICtrl>("check_gesture")->setValue(false);
self->getChild<LLUICtrl>("check_landmark")->setValue(false);
self->getChild<LLUICtrl>("check_material")->setValue(false);
self->getChild<LLUICtrl>("check_notecard")->setValue(false);
self->getChild<LLUICtrl>("check_object")->setValue(false);
self->getChild<LLUICtrl>("check_script")->setValue(false);
self->getChild<LLUICtrl>("check_sound")->setValue(false);
self->getChild<LLUICtrl>("check_texture")->setValue(false);
self->getChild<LLUICtrl>("check_snapshot")->setValue(false);
self->getChild<LLUICtrl>("check_settings")->setValue(false);
mCheckAnimation->setValue(false);
mCheckCallingCard->setValue(false);
mCheckClothing->setValue(false);
mCheckGesture->setValue(false);
mCheckLandmark->setValue(false);
mCheckMaterial->setValue(false);
mCheckNotecard->setValue(false);
mCheckObject->setValue(false);
mCheckScript->setValue(false);
mCheckSounds->setValue(false);
mCheckTexture->setValue(false);
mCheckSnapshot->setValue(false);
mCheckSettings->setValue(false);
}
//////////////////////////////////////////////////////////////////////////////////

View File

@ -1175,6 +1175,7 @@ void LLPanelPermissions::onCommitName(LLUICtrl*, void* data)
{
LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
new_item->rename(tb->getText());
new_item->setComplete(true); // to not err at updateServer
new_item->updateServer(false);
gInventory.updateItem(new_item);
gInventory.notifyObservers();

View File

@ -248,6 +248,8 @@ void LLPanelProfilePicks::onClickNewBtn()
select_tab(true).
label(pick_panel->getPickName()));
updateButtons();
pick_panel->addLocationChangedCallbacks();
}
void LLPanelProfilePicks::onClickDelete()
@ -607,10 +609,12 @@ void LLPanelProfilePick::setAvatarId(const LLUUID& avatar_id)
{
mPickName->setEnabled(true);
mPickDescription->setEnabled(true);
mSetCurrentLocationButton->setVisible(true);
}
else
{
mSnapshotCtrl->setEnabled(false);
mSetCurrentLocationButton->setVisible(false);
}
}
@ -621,6 +625,7 @@ bool LLPanelProfilePick::postBuild()
mSaveButton = getChild<LLButton>("save_changes_btn");
mCreateButton = getChild<LLButton>("create_changes_btn");
mCancelButton = getChild<LLButton>("cancel_changes_btn");
mSetCurrentLocationButton = getChild<LLButton>("set_to_curr_location_btn");
mSnapshotCtrl = getChild<LLTextureCtrl>("pick_snapshot");
mSnapshotCtrl->setCommitCallback(boost::bind(&LLPanelProfilePick::onSnapshotChanged, this));
@ -633,6 +638,7 @@ bool LLPanelProfilePick::postBuild()
mSaveButton->setCommitCallback(boost::bind(&LLPanelProfilePick::onClickSave, this));
mCreateButton->setCommitCallback(boost::bind(&LLPanelProfilePick::onClickSave, this));
mCancelButton->setCommitCallback(boost::bind(&LLPanelProfilePick::onClickCancel, this));
mSetCurrentLocationButton->setCommitCallback(boost::bind(&LLPanelProfilePick::onClickSetLocation, this));
mPickName->setKeystrokeCallback(boost::bind(&LLPanelProfilePick::onPickChanged, this, _1), NULL);
mPickName->setEnabled(false);
@ -811,6 +817,32 @@ bool LLPanelProfilePick::isDirty() const
return false;
}
void LLPanelProfilePick::onClickSetLocation()
{
// Save location for later use.
setPosGlobal(gAgent.getPositionGlobal());
std::string parcel_name, region_name;
LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
if (parcel)
{
mParcelId = parcel->getID();
parcel_name = parcel->getName();
}
LLViewerRegion* region = gAgent.getRegion();
if (region)
{
region_name = region->getName();
}
setPickLocation(createLocationText(getLocationNotice(), parcel_name, region_name, getPosGlobal()));
mLocationChanged = true;
enableSaveButton(true);
}
void LLPanelProfilePick::onClickSave()
{
if (mRegionCallbackConnection.connected())
@ -821,6 +853,10 @@ void LLPanelProfilePick::onClickSave()
{
mParcelCallbackConnection.disconnect();
}
if (mLocationChanged)
{
onClickSetLocation();
}
sendUpdate();
mLocationChanged = false;
@ -871,6 +907,12 @@ void LLPanelProfilePick::processParcelInfo(const LLParcelData& parcel_data)
}
}
void LLPanelProfilePick::addLocationChangedCallbacks()
{
mRegionCallbackConnection = gAgent.addRegionChangedCallback([this]() { onClickSetLocation(); });
mParcelCallbackConnection = gAgent.addParcelChangedCallback([this]() { onClickSetLocation(); });
}
void LLPanelProfilePick::setParcelID(const LLUUID& parcel_id)
{
if (mParcelId != parcel_id)

View File

@ -141,6 +141,8 @@ public:
LLUUID getParcelID() const { return mParcelId; }
void setErrorStatus(S32 status, const std::string& reason) override {};
void addLocationChangedCallbacks();
protected:
/**
@ -202,6 +204,11 @@ public:
*/
void resetDirty() override;
/**
* Callback for "Set Location" button click
*/
void onClickSetLocation();
/**
* Callback for "Save" and "Create" button click
*/
@ -224,6 +231,7 @@ protected:
LLTextureCtrl* mSnapshotCtrl;
LLLineEditor* mPickName;
LLTextEditor* mPickDescription;
LLButton* mSetCurrentLocationButton;
LLButton* mSaveButton;
LLButton* mCreateButton;
LLButton* mCancelButton;
@ -241,7 +249,7 @@ protected:
bool mLocationChanged;
bool mNewPick;
bool mIsEditing;
bool mIsEditing;
void onDescriptionFocusReceived();
};

View File

@ -28,7 +28,6 @@
#define LL_LLSKY_H
#include "llmath.h"
//#include "vmath.h"
#include "v3math.h"
#include "v4math.h"
#include "v4color.h"

View File

@ -27,8 +27,6 @@
#ifndef LL_LLSPRITE_H
#define LL_LLSPRITE_H
////#include "vmath.h"
//#include "llmath.h"
#include "v3math.h"
#include "v4math.h"
#include "v4color.h"

View File

@ -27,7 +27,6 @@
#ifndef LL_LLSURFACE_H
#define LL_LLSURFACE_H
//#include "vmath.h"
#include "v3math.h"
#include "v3dmath.h"
#include "v4math.h"

View File

@ -72,6 +72,7 @@
#include "llweb.h"
#include "pipeline.h" // setHighlightObject
#include "lluiusage.h"
#include "llcallingcard.h"
extern bool gDebugClicks;
@ -1501,6 +1502,134 @@ static void handle_click_action_play()
}
}
bool LLToolPie::shouldAllowFirstMediaInteraction(const LLPickInfo& pick, bool moap_flag)
{
// Early failure cases
if(!pick.getObject())
{
LL_WARNS() << "pick.getObject() is NULL" << LL_ENDL;
return false;
}
static LLCachedControl<S32> FirstClickPref(gSavedSettings, "MediaFirstClickInteract", 1);
// Special / early-exit cases first, then checks get more complex and needy as we go down
// Feature disabled
if(FirstClickPref == MEDIA_FIRST_CLICK_NONE)
{
LL_DEBUGS_ONCE() << "FirstClickPref == MEDIA_FIRST_CLICK_NONE" << LL_ENDL;
return false;
}
// Every check beyond this point requires PRIM_MEDIA_FIRST_CLICK_INTERACT to be TRUE
if(!moap_flag && !(FirstClickPref & MEDIA_FIRST_CLICK_BYPASS_MOAP_FLAG))
{
LL_DEBUGS_ONCE() << "PRIM_MEDIA_FIRST_CLICK_INTERACT not set" << LL_ENDL;
return false;
}
// Any object with PRIM_MEDIA_FIRST_CLICK_INTERACT set to TRUE
if(FirstClickPref & MEDIA_FIRST_CLICK_ANY)
{
LL_DEBUGS_ONCE() << "FirstClickPref & MEDIA_FIRST_CLICK_ANY" << LL_ENDL;
return true;
}
// The following checks require some object information so we obtain that
LLPointer<LLViewerObject> object = pick.getObject();
if(object.isNull())
{
LL_WARNS() << "pick.getObject() is NULL" << LL_ENDL;
return false;
}
// Own objects
if((FirstClickPref & MEDIA_FIRST_CLICK_OWN) && object->permYouOwner())
{
LL_DEBUGS_ONCE() << "FirstClickPref & MEDIA_FIRST_CLICK_OWN" << LL_ENDL;
return true;
}
// HUD attachments
if((FirstClickPref & MEDIA_FIRST_CLICK_HUD) && object->isHUDAttachment())
{
LL_DEBUGS_ONCE() << "FirstClickPref & MEDIA_FIRST_CLICK_HUD" << LL_ENDL;
return true;
}
// Further object detail required beyond this point
LLPermissions* perms = LLSelectMgr::getInstance()->getHoverNode()->mPermissions;
if(perms == nullptr)
{
LL_WARNS() << "LLSelectMgr::getInstance()->getHoverNode()->mPermissions is NULL" << LL_ENDL;
return false;
}
LLUUID owner_id = perms->getOwner();
LLUUID group_id = perms->getGroup();
if(owner_id.isNull() && group_id.isNull())
{
LL_WARNS() << "Owner information was not reliably obtained" << LL_ENDL;
return false;
}
// Check if the object is owned by a friend of the agent
if(FirstClickPref & MEDIA_FIRST_CLICK_FRIEND)
{
LL_DEBUGS_ONCE() << "FirstClickPref & MEDIA_FIRST_CLICK_FRIEND. id: " << owner_id << LL_ENDL;
return LLAvatarTracker::instance().isBuddy(owner_id);
}
// Check for objects set to or owned by the active group
if(FirstClickPref & MEDIA_FIRST_CLICK_GROUP)
{
// Get our active group
LLUUID active_group = gAgent.getGroupID();
if(active_group.notNull() && (active_group == group_id || active_group == owner_id))
{
LL_DEBUGS_ONCE() << "FirstClickPref & MEDIA_FIRST_CLICK_GROUP.Active group: " << active_group << ", group_id:" << group_id << ", owner_id: " << owner_id << LL_ENDL;
return true;
}
}
// This check ensures that the following conditions are met:
// 1. The object is located in the same parcel as the agent.
// 2. One of the following is true:
// a. The object is owned by the same group as the parcel.
// b. The object is set to the same group as the parcel.
// c. The object is owned by the same owner as the parcel.
// Conditions 2a and 2b are mutually exclusive, our check is the same for both.
if(FirstClickPref & MEDIA_FIRST_CLICK_LAND)
{
LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
if(parcel == nullptr)
{
LL_WARNS() << "LLViewerParcelMgr::getInstance()->getAgentParcel() is NULL" << LL_ENDL;
return false;
}
// Same parcel as the agent only
if(!LLViewerParcelMgr::getInstance()->inAgentParcel(object->getPositionGlobal()))
{
LL_WARNS_ONCE() << "Object is not in the same parcel as the agent" << LL_ENDL;
return false;
}
LLUUID parcel_owner = parcel->getOwnerID();
LLUUID parcel_group = parcel->getGroupID();
// The parcel owner and group can't both be null
if(parcel_owner.isNull() && parcel_group.isNull())
{
LL_WARNS() << "Parcel owner and group are both null" << LL_ENDL;
return false;
}
if(owner_id == parcel_owner || group_id == parcel_group)
{
LL_DEBUGS_ONCE() << "FirstClickPref & MEDIA_FIRST_CLICK_LAND. Parcel owner: " << parcel_owner << ", group_id:" << group_id << ", owner_id: " << owner_id << LL_ENDL;
return true;
}
}
return false;
}
bool LLToolPie::handleMediaClick(const LLPickInfo& pick)
{
//FIXME: how do we handle object in different parcel than us?
@ -1535,6 +1664,16 @@ bool LLToolPie::handleMediaClick(const LLPickInfo& pick)
{
// It's okay to give this a null impl
LLViewerMediaFocus::getInstance()->setFocusFace(pick.getObject(), pick.mObjectFace, media_impl, pick.mNormal);
if (shouldAllowFirstMediaInteraction(pick, mep->getFirstClickInteract()))
{
if (media_impl.notNull())
{
media_impl->mouseDown(pick.mUVCoords, gKeyboard->currentMask(true));
mMediaMouseCaptureID = mep->getMediaID();
setMouseCapture(true);
return true;
}
}
}
else
{
@ -1647,7 +1786,7 @@ bool LLToolPie::handleMediaHover(const LLPickInfo& pick)
}
// If this is the focused media face, send mouse move events.
if (LLViewerMediaFocus::getInstance()->isFocusedOnFace(objectp, pick.mObjectFace))
if (LLViewerMediaFocus::getInstance()->isFocusedOnFace(objectp, pick.mObjectFace) || (shouldAllowFirstMediaInteraction(pick, mep->getFirstClickInteract())))
{
media_impl->mouseMove(pick.mUVCoords, gKeyboard->currentMask(true));
gViewerWindow->setCursor(media_impl->getLastSetCursor());

View File

@ -89,6 +89,22 @@ private:
void showVisualContextMenuEffect();
ECursorType cursorFromObject(LLViewerObject* object);
enum MediaFirstClickTypes
{
MEDIA_FIRST_CLICK_NONE = 0, // Special case: Feature is disabled
MEDIA_FIRST_CLICK_HUD = 1 << 0, // 0b00000001 (1)
MEDIA_FIRST_CLICK_OWN = 1 << 1, // 0b00000010 (2)
MEDIA_FIRST_CLICK_GROUP = 1 << 2, // 0b00000100 (4)
MEDIA_FIRST_CLICK_FRIEND = 1 << 3, // 0b00001000 (8)
MEDIA_FIRST_CLICK_LAND = 1 << 4, // 0b00010000 (16)
// Covers any object with PRIM_MEDIA_FIRST_CLICK_INTERACT (combines all previous flags)
MEDIA_FIRST_CLICK_ANY = ~(3<<30), // 0b00111111111111111111111111111111
// Covers all media regardless of other rules or PRIM_MEDIA_FIRST_CLICK_INTERACT
MEDIA_FIRST_CLICK_BYPASS_MOAP_FLAG = 1 << 30 // 0b01000000000000000000000000000000 (1073741824)
};
bool shouldAllowFirstMediaInteraction(const LLPickInfo& info, bool moap_flag);
bool handleMediaClick(const LLPickInfo& info);
bool handleMediaDblClick(const LLPickInfo& info);
bool handleMediaHover(const LLPickInfo& info);

View File

@ -100,13 +100,13 @@
extern LLPointer<LLViewerTexture> gStartTexture;
extern bool gShiftFrame;
LLPointer<LLViewerTexture> gDisconnectedImagep = NULL;
LLPointer<LLViewerTexture> gDisconnectedImagep = nullptr;
// used to toggle renderer back on after teleport
bool gTeleportDisplay = false;
LLFrameTimer gTeleportDisplayTimer;
LLFrameTimer gTeleportArrivalTimer;
const F32 RESTORE_GL_TIME = 5.f; // Wait this long while reloading textures before we raise the curtain
constexpr F32 RESTORE_GL_TIME = 5.f; // Wait this long while reloading textures before we raise the curtain
bool gForceRenderLandFence = false;
bool gDisplaySwapBuffers = false;
@ -120,9 +120,9 @@ bool gSnapshotNoPost = false;
bool gShaderProfileFrame = false;
// This is how long the sim will try to teleport you before giving up.
const F32 TELEPORT_EXPIRY = 15.0f;
constexpr F32 TELEPORT_EXPIRY = 15.0f;
// Additional time (in seconds) to wait per attachment
const F32 TELEPORT_EXPIRY_PER_ATTACHMENT = 3.f;
constexpr F32 TELEPORT_EXPIRY_PER_ATTACHMENT = 3.f;
U32 gRecentFrameCount = 0; // number of 'recent' frames
LLFrameTimer gRecentFPSTime;
@ -130,8 +130,6 @@ LLFrameTimer gRecentMemoryTime;
LLFrameTimer gAssetStorageLogTime;
// Rendering stuff
void pre_show_depth_buffer();
void post_show_depth_buffer();
void render_ui(F32 zoom_factor = 1.f, int subfield = 0);
void swap();
void render_hud_attachments();
@ -212,7 +210,8 @@ void display_update_camera()
F32 final_far = gAgentCamera.mDrawDistance;
if (gCubeSnapshot)
{
final_far = gSavedSettings.getF32("RenderReflectionProbeDrawDistance");
static LLCachedControl<F32> reflection_probe_draw_distance(gSavedSettings, "RenderReflectionProbeDrawDistance", 64.f);
final_far = reflection_probe_draw_distance();
}
else if (CAMERA_MODE_CUSTOMIZE_AVATAR == gAgentCamera.getCameraMode())
{
@ -237,7 +236,7 @@ void display_update_camera()
void display_stats()
{
LL_PROFILE_ZONE_SCOPED;
const F32 FPS_LOG_FREQUENCY = 10.f;
constexpr F32 FPS_LOG_FREQUENCY = 10.f;
if (gRecentFPSTime.getElapsedTimeF32() >= FPS_LOG_FREQUENCY)
{
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("DS - FPS");
@ -246,7 +245,7 @@ void display_stats()
gRecentFrameCount = 0;
gRecentFPSTime.reset();
}
F32 mem_log_freq = gSavedSettings.getF32("MemoryLogFrequency");
static LLCachedControl<F32> mem_log_freq(gSavedSettings, "MemoryLogFrequency", 600.f);
if (mem_log_freq > 0.f && gRecentMemoryTime.getElapsedTimeF32() >= mem_log_freq)
{
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("DS - Memory");
@ -256,7 +255,7 @@ void display_stats()
LLMemory::logMemoryInfo(true) ;
gRecentMemoryTime.reset();
}
const F32 ASSET_STORAGE_LOG_FREQUENCY = 60.f;
constexpr F32 ASSET_STORAGE_LOG_FREQUENCY = 60.f;
if (gAssetStorageLogTime.getElapsedTimeF32() >= ASSET_STORAGE_LOG_FREQUENCY)
{
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("DS - Asset Storage");
@ -572,8 +571,10 @@ void display(bool rebuild, F32 zoom_factor, int subfield, bool for_snapshot)
LLImageGL::updateStats(gFrameTimeSeconds);
LLVOAvatar::sRenderName = gSavedSettings.getS32("AvatarNameTagMode");
LLVOAvatar::sRenderGroupTitles = (gSavedSettings.getBOOL("NameTagShowGroupTitles") && gSavedSettings.getS32("AvatarNameTagMode"));
static LLCachedControl<S32> avatar_name_tag_mode(gSavedSettings, "AvatarNameTagMode", 1);
static LLCachedControl<bool> name_tag_show_group_titles(gSavedSettings, "NameTagShowGroupTitles", true);
LLVOAvatar::sRenderName = avatar_name_tag_mode;
LLVOAvatar::sRenderGroupTitles = name_tag_show_group_titles && avatar_name_tag_mode > 0;
gPipeline.mBackfaceCull = true;
gFrameCount++;
@ -796,7 +797,7 @@ void display(bool rebuild, F32 zoom_factor, int subfield, bool for_snapshot)
}
gGL.setColorMask(true, true);
glClearColor(0,0,0,0);
glClearColor(0.f, 0.f, 0.f, 0.f);
LLGLState::checkStates();
@ -964,7 +965,7 @@ void display(bool rebuild, F32 zoom_factor, int subfield, bool for_snapshot)
gPipeline.mRT->deferredScreen.bindTarget();
if (gUseWireframe)
{
F32 g = 0.5f;
constexpr F32 g = 0.5f;
glClearColor(g, g, g, 1.f);
}
else
@ -983,11 +984,12 @@ void display(bool rebuild, F32 zoom_factor, int subfield, bool for_snapshot)
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("display - 5")
LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
if (gSavedSettings.getBOOL("RenderDepthPrePass"))
static LLCachedControl<bool> render_depth_pre_pass(gSavedSettings, "RenderDepthPrePass", false);
if (render_depth_pre_pass)
{
gGL.setColorMask(false, false);
static const U32 types[] = {
constexpr U32 types[] = {
LLRenderPass::PASS_SIMPLE,
LLRenderPass::PASS_FULLBRIGHT,
LLRenderPass::PASS_SHINY
@ -1201,7 +1203,7 @@ void display_cube_face()
gGL.setColorMask(true, true);
glClearColor(0, 0, 0, 0);
glClearColor(0.f, 0.f, 0.f, 0.f);
gPipeline.generateSunShadow(*LLViewerCamera::getInstance());
glClear(GL_DEPTH_BUFFER_BIT); // | GL_STENCIL_BUFFER_BIT);
@ -1237,7 +1239,7 @@ void display_cube_face()
}
else
{
glClearColor(1, 0, 1, 1);
glClearColor(1.f, 0.f, 1.f, 1.f);
}
gPipeline.mRT->deferredScreen.clear();
@ -1278,11 +1280,12 @@ void render_hud_attachments()
{
LLPipeline::sRenderingHUDs = true;
LLCamera hud_cam = *LLViewerCamera::getInstance();
hud_cam.setOrigin(-1.f,0,0);
hud_cam.setAxes(LLVector3(1,0,0), LLVector3(0,1,0), LLVector3(0,0,1));
hud_cam.setOrigin(-1.f, 0.f, 0.f);
hud_cam.setAxes(LLVector3(1.f, 0.f, 0.f), LLVector3(0.f, 1.f, 0.f), LLVector3(0.f, 0.f, 1.f));
LLViewerCamera::updateFrustumPlanes(hud_cam, true);
bool render_particles = gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES) && gSavedSettings.getBOOL("RenderHUDParticles");
static LLCachedControl<bool> render_hud_particles(gSavedSettings, "RenderHUDParticles", false);
bool render_particles = gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES) && render_hud_particles;
//only render hud objects
gPipeline.pushRenderTypeMask();
@ -1642,10 +1645,11 @@ void render_ui_3d()
stop_glerror();
gUIProgram.bind();
gGL.color4f(1, 1, 1, 1);
gGL.color4f(1.f, 1.f, 1.f, 1.f);
// Coordinate axes
if (gSavedSettings.getBOOL("ShowAxes"))
static LLCachedControl<bool> show_axes(gSavedSettings, "ShowAxes");
if (show_axes())
{
draw_axes();
}
@ -1705,7 +1709,7 @@ void render_ui_2d()
gGL.pushMatrix();
S32 half_width = (gViewerWindow->getWorldViewWidthScaled() / 2);
S32 half_height = (gViewerWindow->getWorldViewHeightScaled() / 2);
gGL.scalef(LLUI::getScaleFactor().mV[0], LLUI::getScaleFactor().mV[1], 1.f);
gGL.scalef(LLUI::getScaleFactor().mV[VX], LLUI::getScaleFactor().mV[VY], 1.f);
gGL.translatef((F32)half_width, (F32)half_height, 0.f);
F32 zoom = gAgentCamera.mHUDCurZoom;
gGL.scalef(zoom,zoom,1.f);
@ -1727,7 +1731,7 @@ void render_ui_2d()
gPipeline.mUIScreen.bindTarget();
gGL.setColorMask(true, true);
{
static const S32 pad = 8;
constexpr S32 pad = 8;
LLView::sDirtyRect.mLeft -= pad;
LLView::sDirtyRect.mRight += pad;
@ -1780,8 +1784,6 @@ void render_ui_2d()
gViewerWindow->draw();
}
// reset current origin for font rendering, in case of tiling render
LLFontGL::sCurOrigin.set(0, 0);
}
@ -1790,7 +1792,7 @@ void render_disconnected_background()
{
gUIProgram.bind();
gGL.color4f(1,1,1,1);
gGL.color4f(1.f, 1.f, 1.f, 1.f);
if (!gDisconnectedImagep && gDisconnected)
{
LL_INFOS() << "Loading last bitmap..." << LL_ENDL;
@ -1830,7 +1832,7 @@ void render_disconnected_background()
raw->expandToPowerOfTwo();
gDisconnectedImagep = LLViewerTextureManager::getLocalTexture(raw.get(), false );
gDisconnectedImagep = LLViewerTextureManager::getLocalTexture(raw.get(), false);
gStartTexture = gDisconnectedImagep;
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
}
@ -1865,6 +1867,5 @@ void render_disconnected_background()
void display_cleanup()
{
gDisconnectedImagep = NULL;
gDisconnectedImagep = nullptr;
}

View File

@ -33,6 +33,7 @@
#include "llfloaterreg.h"
#include "llgl.h"
#include "llrender.h"
#include "lluicolor.h"
#include "v4color.h"
#include "v2math.h"
@ -50,8 +51,8 @@
#include "pipeline.h"
static const U8 OVERLAY_IMG_COMPONENTS = 4;
static const F32 LINE_WIDTH = 0.0625f;
static constexpr U8 OVERLAY_IMG_COMPONENTS = 4;
static constexpr F32 LINE_WIDTH = 0.0625f;
bool LLViewerParcelOverlay::sColorSetInitialized = false;
LLUIColor LLViewerParcelOverlay::sAvailColor;
@ -91,7 +92,7 @@ LLViewerParcelOverlay::LLViewerParcelOverlay(LLViewerRegion* region, F32 region_
// Initialize the GL texture with empty data.
//
// Create the base texture.
U8 *raw = mImageRaw->getData();
U8* raw = mImageRaw->getData();
const S32 COUNT = mParcelGridsPerEdge * mParcelGridsPerEdge * OVERLAY_IMG_COMPONENTS;
for (S32 i = 0; i < COUNT; i++)
{
@ -158,10 +159,10 @@ bool LLViewerParcelOverlay::encroachesOwned(const std::vector<LLBBox>& boxes) co
LLVector3 min = boxes[i].getMinAgent();
LLVector3 max = boxes[i].getMaxAgent();
S32 left = S32(llclamp((min.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1));
S32 right = S32(llclamp((max.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1));
S32 top = S32(llclamp((min.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1));
S32 bottom = S32(llclamp((max.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1));
S32 left = S32(llclamp((min.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1.f));
S32 right = S32(llclamp((max.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1.f));
S32 top = S32(llclamp((min.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1.f));
S32 bottom = S32(llclamp((max.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1.f));
for (S32 row = top; row <= bottom; row++)
{
@ -186,10 +187,10 @@ bool LLViewerParcelOverlay::encroachesOnUnowned(const std::vector<LLBBox>& boxes
LLVector3 min = boxes[i].getMinAgent();
LLVector3 max = boxes[i].getMaxAgent();
S32 left = S32(llclamp((min.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1));
S32 right = S32(llclamp((max.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1));
S32 top = S32(llclamp((min.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1));
S32 bottom = S32(llclamp((max.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1));
S32 left = S32(llclamp((min.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1.f));
S32 right = S32(llclamp((max.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1.f));
S32 top = S32(llclamp((min.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1.f));
S32 bottom = S32(llclamp((max.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1.f));
for (S32 row = top; row <= bottom; row++)
{
@ -223,10 +224,10 @@ bool LLViewerParcelOverlay::encroachesOnNearbyParcel(const std::vector<LLBBox>&
return true;
}
S32 left = S32(llclamp((min.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1));
S32 right = S32(llclamp((max.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1));
S32 bottom = S32(llclamp((min.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1));
S32 top = S32(llclamp((max.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1));
S32 left = S32(llclamp((min.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1.f));
S32 right = S32(llclamp((max.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1.f));
S32 bottom = S32(llclamp((min.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1.f));
S32 top = S32(llclamp((max.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1.f));
const S32 GRIDS_PER_EDGE = mParcelGridsPerEdge;
@ -348,11 +349,11 @@ void LLViewerParcelOverlay::updateOverlayTexture()
const LLColor4U auction = sAuctionColor.get();
// Create the base texture.
U8 *raw = mImageRaw->getData();
U8* raw = mImageRaw->getData();
const S32 COUNT = mParcelGridsPerEdge * mParcelGridsPerEdge;
S32 max = mOverlayTextureIdx + mParcelGridsPerEdge;
if (max > COUNT) max = COUNT;
S32 pixel_index = mOverlayTextureIdx*OVERLAY_IMG_COMPONENTS;
S32 pixel_index = mOverlayTextureIdx * OVERLAY_IMG_COMPONENTS;
S32 i;
for (i = mOverlayTextureIdx; i < max; i++)
{
@ -361,7 +362,7 @@ void LLViewerParcelOverlay::updateOverlayTexture()
U8 r,g,b,a;
// Color stored in low three bits
switch( ownership & 0x7 )
switch (ownership & 0x7)
{
case PARCEL_PUBLIC:
r = avail.mV[VRED];
@ -407,10 +408,10 @@ void LLViewerParcelOverlay::updateOverlayTexture()
break;
}
raw[pixel_index + 0] = (U8)r;
raw[pixel_index + 1] = (U8)g;
raw[pixel_index + 2] = (U8)b;
raw[pixel_index + 3] = (U8)a;
raw[pixel_index + VRED] = (U8)r;
raw[pixel_index + VGREEN] = (U8)g;
raw[pixel_index + VBLUE] = (U8)b;
raw[pixel_index + VALPHA] = (U8)a;
pixel_index += OVERLAY_IMG_COMPONENTS;
}
@ -431,11 +432,10 @@ void LLViewerParcelOverlay::updateOverlayTexture()
}
}
void LLViewerParcelOverlay::uncompressLandOverlay(S32 chunk, U8 *packed_overlay)
void LLViewerParcelOverlay::uncompressLandOverlay(S32 chunk, U8* packed_overlay)
{
// Unpack the message data into the ownership array
S32 size = mParcelGridsPerEdge * mParcelGridsPerEdge;
S32 size = mParcelGridsPerEdge * mParcelGridsPerEdge;
S32 chunk_size = size / PARCEL_OVERLAY_CHUNKS;
memcpy(mOwnership + chunk*chunk_size, packed_overlay, chunk_size); /*Flawfinder: ignore*/
@ -460,7 +460,7 @@ void LLViewerParcelOverlay::updatePropertyLines()
mEdges.clear();
const F32 GRID_STEP = PARCEL_GRID_STEP_METERS;
constexpr F32 GRID_STEP = PARCEL_GRID_STEP_METERS;
const S32 GRIDS_PER_EDGE = mParcelGridsPerEdge;
for (S32 row = 0; row < GRIDS_PER_EDGE; row++)
@ -537,16 +537,16 @@ void LLViewerParcelOverlay::addPropertyLine(F32 start_x, F32 start_y, F32 dx, F3
auto split = [&](const LLVector3& start, F32 x, F32 y, F32 z, F32 part)
{
F32 new_x = start.mV[0] + (x - start.mV[0]) * part;
F32 new_y = start.mV[1] + (y - start.mV[1]) * part;
F32 new_z = start.mV[2] + (z - start.mV[2]) * part;
F32 new_x = start.mV[VX] + (x - start.mV[VX]) * part;
F32 new_y = start.mV[VY] + (y - start.mV[VY]) * part;
F32 new_z = start.mV[VZ] + (z - start.mV[VZ]) * part;
edge.vertices.emplace_back(new_x, new_y, new_z);
};
auto checkForSplit = [&]()
{
const LLVector3& last_outside = edge.vertices.back();
F32 z0 = last_outside.mV[2];
F32 z0 = last_outside.mV[VZ];
F32 z1 = outside_z;
if ((z0 >= water_z && z1 >= water_z) || (z0 < water_z && z1 < water_z))
return;
@ -581,7 +581,7 @@ void LLViewerParcelOverlay::addPropertyLine(F32 start_x, F32 start_y, F32 dx, F3
outside_y += dy * (dy - LINE_WIDTH);
// Middle part, full width
const S32 GRID_STEP = (S32)PARCEL_GRID_STEP_METERS;
constexpr S32 GRID_STEP = (S32)PARCEL_GRID_STEP_METERS;
for (S32 i = 1; i < GRID_STEP; i++)
{
inside_z = land.resolveHeightRegion( inside_x, inside_y );
@ -711,7 +711,7 @@ void LLViewerParcelOverlay::renderPropertyLines()
bool render_hidden = LLSelectMgr::sRenderHiddenSelections && LLFloaterReg::instanceVisible("build");
const F32 PROPERTY_LINE_CLIP_DIST_SQUARED = 256.f * 256.f;
constexpr F32 PROPERTY_LINE_CLIP_DIST_SQUARED = 256.f * 256.f;
for (const Edge& edge : mEdges)
{
@ -744,7 +744,7 @@ void LLViewerParcelOverlay::renderPropertyLines()
else
{
LLVector3 visible = vertex;
visible.mV[2] = water_z;
visible.mV[VZ] = water_z;
gGL.vertex3fv(visible.mV);
}
}
@ -758,7 +758,7 @@ void LLViewerParcelOverlay::renderPropertyLines()
gGL.begin(LLRender::TRIANGLE_STRIP);
LLColor4U color = edge.color;
color.mV[3] /= 4;
color.mV[VALPHA] /= 4;
gGL.color4ubv(color.mV);
for (const LLVector3& vertex : edge.vertices)
@ -792,7 +792,7 @@ void grid_2d_part_lines(const F32 left, const F32 top, const F32 right, const F3
gGL.end();
}
void LLViewerParcelOverlay::renderPropertyLinesOnMinimap(F32 scale_pixels_per_meter, const F32 *parcel_outline_color)
void LLViewerParcelOverlay::renderPropertyLinesOnMinimap(F32 scale_pixels_per_meter, const F32* parcel_outline_color)
{
static LLCachedControl<bool> show(gSavedSettings, "MiniMapShowPropertyLines");
@ -803,8 +803,8 @@ void LLViewerParcelOverlay::renderPropertyLinesOnMinimap(F32 scale_pixels_per_me
LLVector3 origin_agent = mRegion->getOriginAgent();
LLVector3 rel_region_pos = origin_agent - gAgentCamera.getCameraPositionAgent();
F32 region_left = rel_region_pos.mV[0] * scale_pixels_per_meter;
F32 region_bottom = rel_region_pos.mV[1] * scale_pixels_per_meter;
F32 region_left = rel_region_pos.mV[VX] * scale_pixels_per_meter;
F32 region_bottom = rel_region_pos.mV[VY] * scale_pixels_per_meter;
F32 map_parcel_width = PARCEL_GRID_STEP_METERS * scale_pixels_per_meter;
const S32 GRIDS_PER_EDGE = mParcelGridsPerEdge;

View File

@ -34,12 +34,11 @@
#include "llframetimer.h"
#include "lluuid.h"
#include "llviewertexture.h"
#include "llgl.h"
#include "lluicolor.h"
class LLViewerRegion;
class LLVector3;
class LLColor4U;
class LLUIColor;
class LLVector2;
class LLViewerParcelOverlay : public LLGLUpdate
@ -65,19 +64,18 @@ public:
bool isSoundLocal(const LLVector3& pos) const;
bool isBuildCameraAllowed(const LLVector3& pos) const;
F32 getOwnedRatio() const;
// Returns the number of vertices drawn
void renderPropertyLines();
void renderPropertyLinesOnMinimap(F32 scale_pixels_per_meter, const F32* parcel_outline_color);
U8 ownership( const LLVector3& pos) const;
U8 parcelLineFlags( const LLVector3& pos) const;
U8 ownership(const LLVector3& pos) const;
U8 parcelLineFlags(const LLVector3& pos) const;
U8 parcelLineFlags(S32 row, S32 col) const;
// MANIPULATE
void uncompressLandOverlay(S32 chunk, U8 *compressed_overlay);
void uncompressLandOverlay(S32 chunk, U8* compressed_overlay);
// Indicate property lines and overlay texture need to be rebuilt.
void setDirty();
@ -88,8 +86,7 @@ public:
private:
// This is in parcel rows and columns, not grid rows and columns
// Stored in bottom three bits.
U8 ownership(S32 row, S32 col) const
{ return parcelFlags(row, col, (U8)0x7); }
U8 ownership(S32 row, S32 col) const { return parcelFlags(row, col, (U8)0x7); }
U8 parcelFlags(S32 row, S32 col, U8 flags) const;

View File

@ -38,7 +38,6 @@
#include "llregionhandle.h"
#include "llsurface.h"
#include "message.h"
//#include "vmath.h"
#include "v3math.h"
#include "v4math.h"

View File

@ -220,7 +220,16 @@ SimMeasurement<F64Megabytes > SIM_PHYSICS_MEM("physicsmemoryallocated", "", LL
LLTrace::SampleStatHandle<F64Milliseconds > FRAMETIME_JITTER("frametimejitter", "Average delta between successive frame times"),
FRAMETIME("frametime", "Measured frame time"),
SIM_PING("simpingstat");
SIM_PING("simpingstat"),
FRAMETIME_JITTER_99TH("frametimejitter99", "99th percentile of frametime jitter over the last 5 seconds."),
FRAMETIME_JITTER_95TH("frametimejitter95", "99th percentile of frametime jitter over the last 5 seconds."),
FRAMETIME_99TH("frametime99", "99th percentile of frametime over the last 5 seconds."),
FRAMETIME_95TH("frametime95", "99th percentile of frametime over the last 5 seconds."),
FRAMETIME_JITTER_CUMULATIVE("frametimejitcumulative", "Cumulative frametime jitter over the session."),
FRAMETIME_JITTER_STDDEV("frametimejitterstddev", "Standard deviation of frametime jitter in a 5 second period."),
FRAMETIME_STDDEV("frametimestddev", "Standard deviation of frametime in a 5 second period.");
LLTrace::SampleStatHandle<U32> FRAMETIME_JITTER_EVENTS("frametimeevents", "Number of frametime events in the session. Applies when jitter exceeds 10% of the previous frame.");
LLTrace::EventStatHandle<LLUnit<F64, LLUnits::Meters> > AGENT_POSITION_SNAP("agentpositionsnap", "agent position corrections");
@ -264,6 +273,38 @@ void LLViewerStats::resetStats()
getRecording().reset();
}
// Helper for calculating Nth percentile with linear interpolation
template<typename T>
T calcPercentile(const std::vector<T>& sorted, double percent)
{
if (sorted.empty())
return T(0);
double idx = percent * (sorted.size() - 1);
size_t idx_below = static_cast<size_t>(std::floor(idx));
size_t idx_above = static_cast<size_t>(std::ceil(idx));
if (idx_below == idx_above)
return sorted[idx_below];
double weight_above = idx - idx_below;
return sorted[idx_below] * (1.0 - weight_above) + sorted[idx_above] * weight_above;
}
template<typename T>
T calcStddev(const std::vector<T>& values)
{
if (values.size() < 2)
return T(0);
double sum = 0, sq_sum = 0;
for (const auto& v : values)
{
double d = v.value();
sum += d;
sq_sum += d * d;
}
double mean = sum / values.size();
double variance = (sq_sum / values.size()) - (mean * mean);
return T(std::sqrt(variance));
}
void LLViewerStats::updateFrameStats(const F64Seconds time_diff)
{
if (gFrameCount && mLastTimeDiff > (F64Seconds)0.0)
@ -272,8 +313,50 @@ void LLViewerStats::updateFrameStats(const F64Seconds time_diff)
// old stats that were never really used
F64Seconds jit = (F64Seconds)std::fabs((mLastTimeDiff - time_diff));
sample(LLStatViewer::FRAMETIME_JITTER, jit);
}
mTotalFrametimeJitter += jit;
sample(LLStatViewer::FRAMETIME_JITTER_CUMULATIVE, mTotalFrametimeJitter);
static LLCachedControl<F32> frameTimeEventThreshold(gSavedSettings, "StatsFrametimeEventThreshold", 0.1f);
if (time_diff - mLastTimeDiff > mLastTimeDiff * frameTimeEventThreshold())
{
sample(LLStatViewer::FRAMETIME_JITTER_EVENTS, mFrameJitterEvents++);
}
mFrameTimes.push_back(time_diff);
mFrameTimesJitter.push_back(jit);
mLastFrameTimeSample += time_diff;
static LLCachedControl<S32> frameTimeSampleSeconds(gSavedSettings, "StatsFrametimeSampleSeconds", 5);
if (mLastFrameTimeSample >= frameTimeSampleSeconds())
{
std::sort(mFrameTimes.begin(), mFrameTimes.end());
std::sort(mFrameTimesJitter.begin(), mFrameTimesJitter.end());
// Use new helpers for calculations
F64Seconds frame_time_stddev = calcStddev(mFrameTimes);
sample(LLStatViewer::FRAMETIME_STDDEV, frame_time_stddev);
F64Seconds ninety_ninth_percentile = calcPercentile(mFrameTimes, 0.99);
F64Seconds ninety_fifth_percentile = calcPercentile(mFrameTimes, 0.95);
sample(LLStatViewer::FRAMETIME_99TH, ninety_ninth_percentile);
sample(LLStatViewer::FRAMETIME_95TH, ninety_fifth_percentile);
frame_time_stddev = calcStddev(mFrameTimesJitter);
sample(LLStatViewer::FRAMETIME_JITTER_STDDEV, frame_time_stddev);
ninety_ninth_percentile = calcPercentile(mFrameTimesJitter, 0.99);
ninety_fifth_percentile = calcPercentile(mFrameTimesJitter, 0.95);
sample(LLStatViewer::FRAMETIME_JITTER_99TH, ninety_ninth_percentile);
sample(LLStatViewer::FRAMETIME_JITTER_95TH, ninety_fifth_percentile);
mFrameTimes.clear();
mFrameTimesJitter.clear();
mLastFrameTimeSample = F64Seconds(0);
}
}
mLastTimeDiff = time_diff;
}

View File

@ -275,6 +275,13 @@ private:
LLTrace::Recording mRecording;
F64Seconds mLastTimeDiff; // used for time stat updates
F64Seconds mTotalFrametimeJitter;
U32 mFrameJitterEvents;
F64Seconds mLastFrameTimeSample; // used for frame time stats
std::vector<F64Seconds> mFrameTimes; // used for frame time stats
std::vector<F64Seconds> mFrameTimesJitter; // used for frame time jitter stats
};
static const F32 SEND_STATS_PERIOD = 300.0f;

View File

@ -911,6 +911,7 @@ void LLViewerTextureList::updateImageDecodePriority(LLViewerFetchedTexture* imag
bool on_screen = false;
U32 face_count = 0;
U32 max_faces_to_check = 1024;
// get adjusted bias based on image resolution
LLImageGL* img = imagep->getGLTexture();
@ -923,13 +924,15 @@ void LLViewerTextureList::updateImageDecodePriority(LLViewerFetchedTexture* imag
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
for (U32 i = 0; i < LLRender::NUM_TEXTURE_CHANNELS; ++i)
{
for (S32 fi = 0; fi < imagep->getNumFaces(i); ++fi)
face_count += imagep->getNumFaces(i);
S32 faces_to_check = (face_count > max_faces_to_check) ? 0 : imagep->getNumFaces(i);
for (S32 fi = 0; fi < faces_to_check; ++fi)
{
LLFace* face = (*(imagep->getFaceList(i)))[fi];
if (face && face->getViewerObject())
{
++face_count;
F32 radius;
F32 cos_angle_to_view_dir;
@ -992,11 +995,10 @@ void LLViewerTextureList::updateImageDecodePriority(LLViewerFetchedTexture* imag
}
}
if (face_count > 1024)
if (face_count > max_faces_to_check)
{ // this texture is used in so many places we should just boost it and not bother checking its vsize
// this is especially important because the above is not time sliced and can hit multiple ms for a single texture
imagep->setBoostLevel(LLViewerFetchedTexture::BOOST_HIGH);
// Do we ever remove it? This also sets texture nodelete!
max_vsize = MAX_IMAGE_AREA;
}
if (imagep->getType() == LLViewerTexture::LOD_TEXTURE && imagep->getBoostLevel() == LLViewerTexture::BOOST_NONE)
@ -1195,6 +1197,8 @@ F32 LLViewerTextureList::updateImagesLoadingFastCache(F32 max_time)
enditer = iter;
LLViewerFetchedTexture *imagep = *curiter;
imagep->loadFromFastCache();
if (timer.getElapsedTimeF32() > max_time)
break;
}
mFastCacheList.erase(mFastCacheList.begin(), enditer);
return timer.getElapsedTimeF32();
@ -1306,7 +1310,7 @@ void LLViewerTextureList::decodeAllImages(F32 max_time)
LLTimer timer;
//loading from fast cache
updateImagesLoadingFastCache(max_time);
max_time -= updateImagesLoadingFastCache(max_time);
// Update texture stats and priorities
std::vector<LLPointer<LLViewerFetchedTexture> > image_list;

View File

@ -4780,7 +4780,18 @@ void LLViewerWindow::saveImageLocal(LLImageFormatted *image, const snapshot_save
#else
boost::filesystem::path b_path(lastSnapshotDir);
#endif
if (!boost::filesystem::is_directory(b_path))
boost::system::error_code ec;
if (!boost::filesystem::is_directory(b_path, ec) || ec.failed())
{
LLSD args;
args["PATH"] = lastSnapshotDir;
LLNotificationsUtil::add("SnapshotToLocalDirNotExist", args);
resetSnapshotLoc();
failure_cb();
return;
}
boost::filesystem::space_info b_space = boost::filesystem::space(b_path, ec);
if (ec.failed())
{
LLSD args;
args["PATH"] = lastSnapshotDir;
@ -4789,7 +4800,6 @@ void LLViewerWindow::saveImageLocal(LLImageFormatted *image, const snapshot_save
failure_cb();
return;
}
boost::filesystem::space_info b_space = boost::filesystem::space(b_path);
if (b_space.free < image->getDataSize())
{
LLSD args;
@ -4806,6 +4816,8 @@ void LLViewerWindow::saveImageLocal(LLImageFormatted *image, const snapshot_save
LLNotificationsUtil::add("SnapshotToComputerFailed", args);
failure_cb();
// Shouldn't there be a return here?
}
// Look for an unused file name

View File

@ -2643,6 +2643,17 @@ void LLVOVolume::syncMediaData(S32 texture_index, const LLSD &media_data, bool m
}
viewer_media_t media_impl = LLViewerMedia::getInstance()->updateMediaImpl(mep, previous_url, update_from_self);
static LLCachedControl<bool> media_autoplay_huds(gSavedSettings, "MediaAutoPlayHuds", true);
bool was_loaded = media_impl->hasMedia();
if (isHUDAttachment() && media_autoplay_huds && !was_loaded)
{
std::string url = mep->getCurrentURL();
if (media_impl->getCurrentMediaURL() != url)
{
media_impl->navigateTo(url, "", false, true);
}
}
addMediaImpl(media_impl, texture_index) ;
}
else

View File

@ -29,7 +29,7 @@
#include "llwatchdog.h"
#include "llthread.h"
const U32 WATCHDOG_SLEEP_TIME_USEC = 1000000;
constexpr U32 WATCHDOG_SLEEP_TIME_USEC = 1000000U;
// This class runs the watchdog timing thread.
class LLWatchdogTimerThread : public LLThread
@ -51,7 +51,7 @@ public:
mSleepMsecs = 1;
}
/* virtual */ void run()
void run() override
{
while(!mStopping)
{
@ -83,7 +83,7 @@ void LLWatchdogEntry::start()
void LLWatchdogEntry::stop()
{
// this can happen very late in the shutdown sequence
if (! LLWatchdog::wasDeleted())
if (!LLWatchdog::wasDeleted())
{
LLWatchdog::getInstance()->remove(this);
}
@ -117,7 +117,7 @@ void LLWatchdogTimeout::setTimeout(F32 d)
mTimeout = d;
}
void LLWatchdogTimeout::start(const std::string& state)
void LLWatchdogTimeout::start(std::string_view state)
{
if (mTimeout == 0)
{
@ -139,9 +139,9 @@ void LLWatchdogTimeout::stop()
mTimer.stop();
}
void LLWatchdogTimeout::ping(const std::string& state)
void LLWatchdogTimeout::ping(std::string_view state)
{
if(!state.empty())
if (!state.empty())
{
mPingState = state;
}
@ -151,7 +151,7 @@ void LLWatchdogTimeout::ping(const std::string& state)
// LLWatchdog
LLWatchdog::LLWatchdog()
:mSuspectsAccessMutex()
,mTimer(NULL)
,mTimer(nullptr)
,mLastClockCount(0)
{
}
@ -176,7 +176,7 @@ void LLWatchdog::remove(LLWatchdogEntry* e)
void LLWatchdog::init()
{
if(!mSuspectsAccessMutex && !mTimer)
if (!mSuspectsAccessMutex && !mTimer)
{
mSuspectsAccessMutex = new LLMutex();
mTimer = new LLWatchdogTimerThread();
@ -191,17 +191,17 @@ void LLWatchdog::init()
void LLWatchdog::cleanup()
{
if(mTimer)
if (mTimer)
{
mTimer->stop();
delete mTimer;
mTimer = NULL;
mTimer = nullptr;
}
if(mSuspectsAccessMutex)
if (mSuspectsAccessMutex)
{
delete mSuspectsAccessMutex;
mSuspectsAccessMutex = NULL;
mSuspectsAccessMutex = nullptr;
}
mLastClockCount = 0;
@ -214,12 +214,12 @@ void LLWatchdog::run()
// Check the time since the last call to run...
// If the time elapsed is two times greater than the regualr sleep time
// reset the active timeouts.
const U32 TIME_ELAPSED_MULTIPLIER = 2;
constexpr U32 TIME_ELAPSED_MULTIPLIER = 2;
U64 current_time = LLTimer::getTotalTime();
U64 current_run_delta = current_time - mLastClockCount;
mLastClockCount = current_time;
if(current_run_delta > (WATCHDOG_SLEEP_TIME_USEC * TIME_ELAPSED_MULTIPLIER))
if (current_run_delta > (WATCHDOG_SLEEP_TIME_USEC * TIME_ELAPSED_MULTIPLIER))
{
LL_INFOS() << "Watchdog thread delayed: resetting entries." << LL_ENDL;
for (const auto& suspect : mSuspects)
@ -233,7 +233,7 @@ void LLWatchdog::run()
std::find_if(mSuspects.begin(),
mSuspects.end(),
[](const LLWatchdogEntry* suspect){ return ! suspect->isAlive(); });
if(result != mSuspects.end())
if (result != mSuspects.end())
{
// error!!!
if(mTimer)
@ -251,7 +251,7 @@ void LLWatchdog::run()
void LLWatchdog::lockThread()
{
if(mSuspectsAccessMutex != NULL)
if (mSuspectsAccessMutex)
{
mSuspectsAccessMutex->lock();
}
@ -259,7 +259,7 @@ void LLWatchdog::lockThread()
void LLWatchdog::unlockThread()
{
if(mSuspectsAccessMutex != NULL)
if (mSuspectsAccessMutex)
{
mSuspectsAccessMutex->unlock();
}

View File

@ -56,14 +56,14 @@ public:
LLWatchdogTimeout();
virtual ~LLWatchdogTimeout();
/* virtual */ bool isAlive() const;
/* virtual */ void reset();
/* virtual */ void start() { start(""); }
/* virtual */ void stop();
bool isAlive() const override;
void reset() override;
void start() override { start(""); }
void stop() override;
void start(const std::string& state);
void start(std::string_view state);
void setTimeout(F32 d);
void ping(const std::string& state);
void ping(std::string_view state);
const std::string& getState() {return mPingState; }
private:

View File

@ -54,6 +54,38 @@
label="jitter"
decimal_digits="1"
stat="frametimejitter"/>
<stat_bar name="framet_cumulative"
label="jitter cumulative"
decimal_digits="1"
stat="frametimejitcumulative"/>
<stat_bar name="framet_jitter_99th"
label="jitter 99th percentile"
decimal_digits="1"
stat="frametimejitter99"/>
<stat_bar name="framet_jitter_95th"
label="jitter 95th percentile"
decimal_digits="1"
stat="frametimejitter95"/>
<stat_bar name="framet_jitter_stddev"
label="frametime jitter standard deviation"
decimal_digits="1"
stat="frametimejitterstddev"/>
<stat_bar name="framet_99th"
label="frametime 99th percentile"
decimal_digits="1"
stat="frametime99"/>
<stat_bar name="framet_95th"
label="frametime 95th percentile"
decimal_digits="1"
stat="frametime95"/>
<stat_bar name="framet_stddev"
label="frametime standard deviation"
decimal_digits="1"
stat="frametimestddev"/>
<stat_bar name="framet_events"
label="frametime events"
decimal_digits="1"
stat="frametimeevents"/>
<stat_bar name="bandwidth"
label="UDP Data Received"
stat="activemessagedatareceived"

View File

@ -455,7 +455,7 @@
<panel
follows="right|top|bottom"
height="330"
height="235"
top_pad="0"
width="238"
name="layout_panel_4">
@ -532,9 +532,9 @@
width="16" />
<search_editor
follows="top|right"
search_button_visible="false"
search_button_visible="false"
height="22"
text_readonly_color="DkGray"
text_readonly_color="DkGray"
label="Regions by Name"
layout="topleft"
top_delta="-2"
@ -542,10 +542,7 @@
name="location"
select_on_focus="true"
tool_tip="Type the name of a region"
width="152">
<search_editor.commit_callback
function="WMap.Location" />
</search_editor>
width="152"/>
<button
follows="top|right"
height="23"
@ -594,6 +591,13 @@
<scroll_list.commit_callback
function="WMap.SearchResult" />
</scroll_list>
</panel>
<panel
follows="right|bottom"
height="95"
top_pad="0"
width="238"
name="layout_panel_7">
<text
type="string"
length="1"

View File

@ -62,20 +62,9 @@
name="mute_when_minimized"
top_delta="3"
left_pad="5"
width="20" />
<!-- *HACK
After storm-1109 will be fixed: instead of using this text_box, word_wrap should be applied for "mute_when_minimized" check_box's label.-->
<text
follows="top|left"
height="15"
layout="topleft"
left_pad="0"
name="mute_chb_label"
top_delta="-1"
width="150"
wrap="true">
Mute when minimized
</text>
width="20"
label="Mute when minimized"
word_wrap="true"/>
<slider
control_name="AudioLevelUI"
disabled_control="MuteAudio"
@ -321,66 +310,45 @@
left_pad="5"
name="enable_voice_check"
width="110"/>
<!-- -->
<text
type="string"
length="1"
follows="left|top"
layout="topleft"
left="23"
top_delta="22"
top_delta="25"
name="Listen media from"
height="15"
word_wrap="true"
width="112">
Hear media and sounds from:
width="165"
halign="right">
Hear media and sounds from
</text>
<radio_group
<combo_box
control_name="MediaSoundsEarLocation"
follows="left|top"
top_delta="-6"
layout="topleft"
left_pad="10"
width="360"
height="40"
name="media_ear_location">
<radio_item
height="19"
label="Camera position"
follows="left|top"
layout="topleft"
name="0"
width="200"/>
<radio_item
height="19"
follows="left|top"
label="Avatar position"
layout="topleft"
left_delta="0"
name="1"
top_delta ="18"
width="200" />
</radio_group>
<check_box
name="media_show_on_others_btn"
control_name="MediaShowOnOthers"
value="true"
follows="left|top"
layout="topleft"
height="15"
top_pad="8"
tool_tip="Uncheck this to hide media attached to other avatars nearby"
label="Play media attached to other avatars"
left="20"
width="230"/>
left_pad="5"
width="130"
height="23"
top_delta="-4"
name="media_ear_location_combo">
<item
label="Camera position"
name="camera_position"
value="0" />
<item
label="Avatar position"
name="avatar_position"
value="1" />
</combo_box>
<text
follows="left|top"
layout="topleft"
height="15"
left="23"
top_pad="8"
width="120"
name="media_autoplay_label">
width="165"
name="media_autoplay_label"
halign="right">
Auto-play media
</text>
<combo_box
@ -389,10 +357,10 @@
follows="left|top"
layout="topleft"
height="23"
left_pad="-15"
left_delta="170"
top_delta="-4"
name="media_auto_play_combo"
width="115">
width="130">
<item
label="Never"
name="autoplay_disabled"
@ -406,23 +374,106 @@
name="autoplay_ask"
value="2"/>
</combo_box>
<text
follows="left|top"
layout="topleft"
height="15"
left="23"
width="165"
name="media_firstinteract_label"
halign="right">
Media first-interact
</text>
<combo_box
control_name="MediaFirstClickInteract"
enabled_control="AudioStreamingMedia"
follows="left|top"
layout="topleft"
height="23"
left_delta="170"
top_delta="-4"
width="130"
name="media_first_interact_combo"
tool_tip="This setting controls which media (once loaded) does not require a first click to focus before interaction can begin. This allows clicks to be passed directly to media bypassing the focus click requirement. Each option also inherits the previous ones.">
<item
label="Disabled"
name="media_first_click_none"
value="0"/>
<item
label="Worn HUDs only"
name="media_first_click_hud"
value="1"/>
<item
label="Owned objects"
name="media_first_click_own"
value="3"/>
<item
label="Friends' objects"
name="media_first_click_friend"
value="11"/>
<item
label="Group objects"
name="media_first_click_group"
value="15"/>
<item
label="Landowner objects"
name="media_first_click_land"
value="31"/>
<item
label="Anyone's objects"
name="media_first_interact_any"
value="1073741823"/>
<item
label="All MOAP"
name="media_first_click_all"
value="2147483647"/>
</combo_box>
<check_box
name="media_show_on_others_btn"
control_name="MediaShowOnOthers"
enabled_control="AudioStreamingMedia"
value="true"
follows="left|top"
tool_tip="Uncheck this to hide media attached to other avatars nearby"
label="Play media attached to other avatars"
left="23"
width="15"
top_delta="30"
height="15"/>
<check_box
name="media_huds_autoplay"
control_name="MediaAutoPlayHuds"
enabled_control="AudioStreamingMedia"
value="true"
follows="left|top"
layout="topleft"
tool_tip="Uncheck this to make HUDs follow the standard media auto-play setting"
label="Auto-play media attached to your HUD"
left="260"
top_pad="-15"
width="15"
height="15"/>
<text
layout="topleft"
follows="left"
height="15"
left="260"
top_pad="-18"
width="100"
name="noise_suppression_label">
Noise Suppression
width="165"
name="noise_suppression_label"
left="23"
top_delta="22"
halign="right">
Microphone Noise Suppression
</text>
<combo_box
control_name="VoiceNoiseSuppressionLevel"
enabled_control="EnableVoiceChat"
follows="left|top"
layout="topleft"
left_delta="170"
top_delta="-6"
width="130"
height="23"
left_pad="10"
top_pad="-20"
name="noise_suppression_combo"
width="80">
name="noise_suppression_combo">
<item
label="Off"
name="noise_suppression_none"
@ -452,48 +503,44 @@
left="23"
top_delta="30"
name="Listen from"
width="112">
Hear voice from:
width="165"
height="15"
halign="right">
Hear voice from
</text>
<radio_group
<combo_box
enabled_control="EnableVoiceChat"
control_name="VoiceEarLocation"
follows="left|top"
layout="topleft"
left_pad="10"
left_delta="170"
top_delta="-6"
width="360"
height="40"
name="ear_location">
<radio_item
height="19"
label="Camera position"
follows="left|top"
layout="topleft"
name="0"
width="200"/>
<radio_item
height="19"
follows="left|top"
label="Avatar position"
layout="topleft"
left_delta="0"
name="1"
top_delta ="18"
width="200" />
</radio_group>
width="130"
height="23"
name="ear_location_combo">
<item
label="Camera position"
name="camera_position"
value="0" />
<item
label="Avatar position"
name="avatar_position"
value="1" />
</combo_box>
<check_box
control_name="LipSyncEnabled"
enabled_control="EnableVoiceChat"
follows="left|top"
height="15"
label="Move avatar lips when speaking"
layout="topleft"
left="20"
name="enable_lip_sync"
top_pad="10"
top_pad="8"
width="237"/>
<check_box
control_name="VoiceEchoCancellation"
enabled_control="EnableVoiceChat"
height="15"
tool_tip="Check to enable voice echo cancellation"
label="Echo Cancellation"
@ -516,6 +563,7 @@
top_pad="5"/>
<check_box
control_name="VoiceAutomaticGainControl"
enabled_control="EnableVoiceChat"
height="15"
tool_tip="Check to enable automatic gain control"
label="Automatic Gain Control"
@ -537,6 +585,7 @@
left="20"/>
<check_box
control_name="VoiceVisualizerEnabled"
enabled_control="EnableVoiceChat"
height="15"
tool_tip="Check to show voice dot indicator above avatars"
label="Show voice dot above avatars"
@ -547,6 +596,7 @@
width="200"/>
<button
control_name="ShowDeviceSettings"
enabled_control="EnableVoiceChat"
follows="left|top"
height="23"
is_toggle="true"

View File

@ -198,6 +198,26 @@
/>
</layout_panel>
<layout_panel
follows="all"
layout="bottomleft"
left_pad="2"
name="set_to_curr_location_btn_lp"
auto_resize="false"
width="100">
<button
name="set_to_curr_location_btn"
label="Set Location"
tool_tip="Set to Current Location"
left="0"
top="0"
height="23"
width="100"
follows="left|top"
layout="topleft"
/>
</layout_panel>
<layout_panel
follows="all"
layout="topleft"

View File

@ -985,6 +985,19 @@
max_val="10000"
name="gltfTextureScaleV"
width="265" />
<spinner
decimal_digits="1"
follows="left|top"
height="19"
initial_value=""
label="Repeats per meter"
layout="topleft"
label_width="205"
left="10"
max_val="100"
min_val="-100"
name="gltfRptctrl"
width="265" />
<spinner
follows="left|top"
height="19"