Merge branch 'develop' of https://github.com/secondlife/viewer
# Conflicts: # indra/llimagej2coj/llimagej2coj.cpp # indra/newview/llfloaterworldmap.cpp # indra/newview/llfloaterworldmap.h # indra/newview/llviewertexturelist.cpp # indra/newview/skins/default/xui/en/floater_world_map.xmlmaster
commit
355a80ab91
|
|
@ -1,14 +1,23 @@
|
||||||
name: Run QA Test # Runs automated tests on a self-hosted QA machine
|
name: Run QA Test # Runs automated tests on self-hosted QA machines
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_run:
|
workflow_run:
|
||||||
workflows: ["Build"]
|
workflows: ["Build"]
|
||||||
types:
|
types:
|
||||||
- completed
|
- 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'
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: qa-test-run
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
cancel-in-progress: true # Cancels any queued job when a new one starts
|
cancel-in-progress: false # Prevents cancellation of in-progress jobs
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
debug-workflow:
|
debug-workflow:
|
||||||
|
|
@ -26,39 +35,165 @@ jobs:
|
||||||
echo "GitHub Workflow Name: ${{ github.workflow }}"
|
echo "GitHub Workflow Name: ${{ github.workflow }}"
|
||||||
|
|
||||||
install-viewer-and-run-tests:
|
install-viewer-and-run-tests:
|
||||||
runs-on: [self-hosted, qa-machine]
|
strategy:
|
||||||
# Run test only on successful builds of Second_Life_X branches
|
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
|
||||||
|
# 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: >
|
if: >
|
||||||
|
(github.event_name == 'workflow_run' &&
|
||||||
github.event.workflow_run.conclusion == 'success' &&
|
github.event.workflow_run.conclusion == 'success' &&
|
||||||
(
|
startsWith(github.event.workflow_run.head_branch, 'Second_Life')) ||
|
||||||
startsWith(github.event.workflow_run.head_branch, 'Second_Life')
|
github.event_name == 'workflow_dispatch'
|
||||||
)
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Temporarily Allow PowerShell Scripts (Process Scope)
|
# 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: |
|
run: |
|
||||||
Set-ExecutionPolicy RemoteSigned -Scope Process -Force
|
Set-ExecutionPolicy RemoteSigned -Scope Process -Force
|
||||||
|
|
||||||
- name: Verify viewer-sikulix-main Exists
|
- name: Verify viewer-automation-main Exists (Windows)
|
||||||
run: |
|
if: matrix.os == 'windows'
|
||||||
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
|
shell: pwsh
|
||||||
run: |
|
run: |
|
||||||
$BUILD_ID = "${{ github.event.workflow_run.id }}"
|
if (-Not (Test-Path -Path '${{ matrix.install-path }}')) {
|
||||||
$ARTIFACTS_URL = "https://api.github.com/repos/secondlife/viewer/actions/runs/$BUILD_ID/artifacts"
|
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
|
# Fetch the correct artifact URL
|
||||||
$response = Invoke-RestMethod -Headers @{Authorization="token ${{ secrets.GITHUB_TOKEN }}" } -Uri $ARTIFACTS_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
|
$ARTIFACT_NAME = ($response.artifacts | Where-Object { $_.name -eq "${{ matrix.artifact }}" }).archive_download_url
|
||||||
|
|
||||||
if (-Not $ARTIFACT_NAME) {
|
if (-Not $ARTIFACT_NAME) {
|
||||||
Write-Host "❌ Error: Windows-installer artifact not found!"
|
Write-Host "❌ Error: ${{ matrix.artifact }} artifact not found!"
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -74,16 +209,19 @@ jobs:
|
||||||
|
|
||||||
# Ensure download succeeded
|
# Ensure download succeeded
|
||||||
if (-Not (Test-Path $InstallerPath)) {
|
if (-Not (Test-Path $InstallerPath)) {
|
||||||
Write-Host "❌ Error: Failed to download Windows-installer.zip"
|
Write-Host "❌ Error: Failed to download ${{ matrix.artifact }}.zip"
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
- name: Extract Installer & Locate Executable
|
# 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
|
shell: pwsh
|
||||||
run: |
|
run: |
|
||||||
# Explicitly set BUILD_ID again (since it does not appear to persist across steps)
|
$BUILD_ID = "${{ env.BUILD_ID }}"
|
||||||
$BUILD_ID = "${{ github.event.workflow_run.id }}"
|
$ExtractPath = "${{ env.DOWNLOAD_PATH }}"
|
||||||
$ExtractPath = "$env:TEMP\secondlife-build-$BUILD_ID"
|
|
||||||
$InstallerZip = "$ExtractPath\installer.zip"
|
$InstallerZip = "$ExtractPath\installer.zip"
|
||||||
|
|
||||||
# Print paths for debugging
|
# Print paths for debugging
|
||||||
|
|
@ -113,16 +251,19 @@ jobs:
|
||||||
Write-Host "✅ Installer found: $INSTALLER_PATH"
|
Write-Host "✅ Installer found: $INSTALLER_PATH"
|
||||||
echo "INSTALLER_PATH=$INSTALLER_PATH" | Out-File -FilePath $env:GITHUB_ENV -Append
|
echo "INSTALLER_PATH=$INSTALLER_PATH" | Out-File -FilePath $env:GITHUB_ENV -Append
|
||||||
|
|
||||||
- name: Install Second Life Using Task Scheduler (Bypass UAC)
|
- name: Install Second Life (Windows)
|
||||||
|
if: matrix.os == 'windows'
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
run: |
|
run: |
|
||||||
|
# Windows - Use Task Scheduler to bypass UAC
|
||||||
$action = New-ScheduledTaskAction -Execute "${{ env.INSTALLER_PATH }}" -Argument "/S"
|
$action = New-ScheduledTaskAction -Execute "${{ env.INSTALLER_PATH }}" -Argument "/S"
|
||||||
$principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest
|
$principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest
|
||||||
$task = New-ScheduledTask -Action $action -Principal $principal
|
$task = New-ScheduledTask -Action $action -Principal $principal
|
||||||
Register-ScheduledTask -TaskName "SilentSLInstaller" -InputObject $task -Force
|
Register-ScheduledTask -TaskName "SilentSLInstaller" -InputObject $task -Force
|
||||||
Start-ScheduledTask -TaskName "SilentSLInstaller"
|
Start-ScheduledTask -TaskName "SilentSLInstaller"
|
||||||
|
|
||||||
- name: Wait for Installation to Complete
|
- name: Wait for Installation to Complete (Windows)
|
||||||
|
if: matrix.os == 'windows'
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
run: |
|
run: |
|
||||||
Write-Host "Waiting for the Second Life installer to finish..."
|
Write-Host "Waiting for the Second Life installer to finish..."
|
||||||
|
|
@ -133,18 +274,16 @@ jobs:
|
||||||
|
|
||||||
Write-Host "✅ Installation completed!"
|
Write-Host "✅ Installation completed!"
|
||||||
|
|
||||||
- name: Cleanup Task Scheduler Entry
|
- name: Cleanup After Installation (Windows)
|
||||||
|
if: matrix.os == 'windows'
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
run: |
|
run: |
|
||||||
|
# Cleanup Task Scheduler Entry
|
||||||
Unregister-ScheduledTask -TaskName "SilentSLInstaller" -Confirm:$false
|
Unregister-ScheduledTask -TaskName "SilentSLInstaller" -Confirm:$false
|
||||||
Write-Host "✅ Task Scheduler entry removed."
|
Write-Host "✅ Task Scheduler entry removed."
|
||||||
|
|
||||||
- name: Delete Installer ZIP
|
# Delete Installer ZIP
|
||||||
shell: pwsh
|
$DeletePath = "${{ env.DOWNLOAD_PATH }}\installer.zip"
|
||||||
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"
|
Write-Host "Checking if installer ZIP exists: $DeletePath"
|
||||||
|
|
||||||
|
|
@ -156,13 +295,281 @@ jobs:
|
||||||
Write-Host "⚠️ Warning: ZIP file does not exist, skipping deletion."
|
Write-Host "⚠️ Warning: ZIP file does not exist, skipping deletion."
|
||||||
}
|
}
|
||||||
|
|
||||||
- name: Run QA Test Script
|
- name: Run QA Test Script (Windows)
|
||||||
|
if: matrix.os == 'windows'
|
||||||
|
shell: pwsh
|
||||||
run: |
|
run: |
|
||||||
Write-Host "Running QA Test script..."
|
Write-Host "Running QA Test script on Windows runner: ${{ matrix.runner }}..."
|
||||||
python C:\viewer-sikulix-main\runTests.py
|
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
|
# - name: Upload Test Results
|
||||||
# uses: actions/upload-artifact@v3
|
# if: always()
|
||||||
|
# uses: actions/upload-artifact@v4
|
||||||
# with:
|
# with:
|
||||||
# name: test-results
|
# name: test-results-${{ matrix.runner }}
|
||||||
# path: C:\viewer-sikulix-main\regressionTest\test_results.html
|
# path: ${{ matrix.install-path }}/regressionTest/test_results.html
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ repos:
|
||||||
- id: indent-with-spaces
|
- id: indent-with-spaces
|
||||||
files: \.(cpp|c|h|inl|py|glsl|cmake)$
|
files: \.(cpp|c|h|inl|py|glsl|cmake)$
|
||||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
rev: v4.4.0
|
rev: v5.0.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: check-xml
|
- id: check-xml
|
||||||
- id: mixed-line-ending
|
- id: mixed-line-ending
|
||||||
|
|
|
||||||
|
|
@ -114,9 +114,10 @@ std::vector<std::string> LLDir::getFilesInDir(const std::string &dirname)
|
||||||
|
|
||||||
std::vector<std::string> v;
|
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;
|
boost::filesystem::directory_iterator end_iter;
|
||||||
for (boost::filesystem::directory_iterator dir_itr(p);
|
for (boost::filesystem::directory_iterator dir_itr(p);
|
||||||
|
|
|
||||||
|
|
@ -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 height = (h > 0) ? h : 2048;
|
||||||
S32 max_dimension = llmax(width, height); // Find largest dimension
|
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)
|
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 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
|
||||||
S32 totalbytes = (S32) (block_area * max_components * precision); // First block layer computed before loop without compression rate
|
block_area *= llmax(max_layers, 1); // Adjust initial block area by max number of layers
|
||||||
S32 block_layers = 1; // Start at layer 1 since first block layer is computed outside loop
|
S32 totalbytes = (S32) (MIN_LAYER_SIZE * max_components * precision); // Start estimation with a minimum reasonable size
|
||||||
while (block_layers < 6) // Walk five layers for the five discards in JPEG2000
|
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.
|
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
|
totalbytes += (S32) (block_area * max_components * precision * rate); // Add each block layer reduced by assumed compression rate
|
||||||
|
|
|
||||||
|
|
@ -32,8 +32,6 @@
|
||||||
#include "event.h"
|
#include "event.h"
|
||||||
#include "cio.h"
|
#include "cio.h"
|
||||||
|
|
||||||
#define MAX_ENCODED_DISCARD_LEVELS 5
|
|
||||||
|
|
||||||
// Factory function: see declaration in llimagej2c.cpp
|
// Factory function: see declaration in llimagej2c.cpp
|
||||||
LLImageJ2CImpl* fallbackCreateLLImageJ2CImpl()
|
LLImageJ2CImpl* fallbackCreateLLImageJ2CImpl()
|
||||||
{
|
{
|
||||||
|
|
@ -135,73 +133,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)
|
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);
|
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;
|
jpeg_codec->offset = jpeg_codec->size;
|
||||||
// Indicate end of stream (hacky?)
|
return static_cast<OPJ_SIZE_T>(-1); // Indicate EOF
|
||||||
return (OPJ_OFF_T)-1;
|
|
||||||
}
|
}
|
||||||
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);
|
memcpy(buffer, jpeg_codec->buffer + jpeg_codec->offset, to_read);
|
||||||
jpeg_codec->offset += to_read;
|
jpeg_codec->offset += to_read;
|
||||||
|
|
||||||
return to_read;
|
return to_read;
|
||||||
}
|
}
|
||||||
|
|
||||||
static OPJ_SIZE_T opj_write(void * buffer, OPJ_SIZE_T bytes, void* user_data)
|
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);
|
JPEG2KBase* jpeg_codec = static_cast<JPEG2KBase*>(user_data);
|
||||||
OPJ_SIZE_T remainder = jpeg_codec->size - jpeg_codec->offset;
|
OPJ_OFF_T required_offset = jpeg_codec->offset + static_cast<OPJ_OFF_T>(bytes);
|
||||||
if (remainder < 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);
|
U8* new_buffer = (U8*)ll_aligned_malloc_16(new_size);
|
||||||
memcpy(new_buffer, jpeg_codec->buffer, jpeg_codec->offset);
|
if (!new_buffer) return 0; // Allocation failed
|
||||||
U8* old_buffer = jpeg_codec->buffer;
|
|
||||||
|
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;
|
jpeg_codec->buffer = new_buffer;
|
||||||
ll_aligned_free_16(old_buffer);
|
|
||||||
jpeg_codec->size = new_size;
|
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;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
static OPJ_OFF_T opj_skip(OPJ_OFF_T bytes, void* user_data)
|
static OPJ_OFF_T opj_skip(OPJ_OFF_T bytes, void* user_data)
|
||||||
{
|
{
|
||||||
|
llassert(user_data);
|
||||||
JPEG2KBase* jpeg_codec = static_cast<JPEG2KBase*>(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;
|
// Clamp and indicate EOF or error
|
||||||
// Indicate end of stream
|
jpeg_codec->offset = llclamp<OPJ_OFF_T>(new_offset, 0, static_cast<OPJ_OFF_T>(jpeg_codec->size));
|
||||||
return (OPJ_OFF_T)-1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (jpeg_codec->offset < 0)
|
|
||||||
{
|
|
||||||
// Shouldn't be possible?
|
|
||||||
jpeg_codec->offset = 0;
|
|
||||||
return (OPJ_OFF_T)-1;
|
return (OPJ_OFF_T)-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
jpeg_codec->offset = new_offset;
|
||||||
return bytes;
|
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);
|
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;
|
return OPJ_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void opj_free_user_data(void * user_data)
|
static void opj_free_user_data(void * user_data)
|
||||||
{
|
{
|
||||||
|
llassert(user_data);
|
||||||
|
|
||||||
JPEG2KBase* jpeg_codec = static_cast<JPEG2KBase*>(user_data);
|
JPEG2KBase* jpeg_codec = static_cast<JPEG2KBase*>(user_data);
|
||||||
// Don't free, data is managed externally
|
// Don't free, data is managed externally
|
||||||
jpeg_codec->buffer = nullptr;
|
jpeg_codec->buffer = nullptr;
|
||||||
|
|
@ -211,14 +232,54 @@ static void opj_free_user_data(void * user_data)
|
||||||
|
|
||||||
static void opj_free_user_data_write(void * user_data)
|
static void opj_free_user_data_write(void * user_data)
|
||||||
{
|
{
|
||||||
|
llassert(user_data);
|
||||||
|
|
||||||
JPEG2KBase* jpeg_codec = static_cast<JPEG2KBase*>(user_data);
|
JPEG2KBase* jpeg_codec = static_cast<JPEG2KBase*>(user_data);
|
||||||
// Free, data was allocated here
|
// Free, data was allocated here
|
||||||
|
if (jpeg_codec->buffer)
|
||||||
|
{
|
||||||
ll_aligned_free_16(jpeg_codec->buffer);
|
ll_aligned_free_16(jpeg_codec->buffer);
|
||||||
jpeg_codec->buffer = nullptr;
|
jpeg_codec->buffer = nullptr;
|
||||||
|
}
|
||||||
jpeg_codec->size = 0;
|
jpeg_codec->size = 0;
|
||||||
jpeg_codec->offset = 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.5–2MP
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
class JPEG2KDecode : public JPEG2KBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
@ -433,15 +494,16 @@ public:
|
||||||
|
|
||||||
opj_set_default_encoder_parameters(¶meters);
|
opj_set_default_encoder_parameters(¶meters);
|
||||||
parameters.cod_format = OPJ_CODEC_J2K;
|
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)
|
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.irreversible = 0; // should be the default, but, just in case
|
||||||
parameters.tcp_numlayers = 1;
|
parameters.tcp_numlayers = 1;
|
||||||
/* documentation seems to be wrong, should be 0.0f for lossless, not 1.0f
|
/* 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;
|
parameters.tcp_rates[0] = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
@ -496,53 +558,22 @@ public:
|
||||||
|
|
||||||
encoder = opj_create_compress(OPJ_CODEC_J2K);
|
encoder = opj_create_compress(OPJ_CODEC_J2K);
|
||||||
|
|
||||||
parameters.tcp_mct = (image->numcomps >= 3) ? 1 : 0;
|
parameters.tcp_mct = (image->numcomps >= 3) ? 1 : 0; // no color transform for RGBA images
|
||||||
parameters.cod_format = OPJ_CODEC_J2K;
|
|
||||||
parameters.prog_order = OPJ_RLCP;
|
|
||||||
parameters.cp_disto_alloc = 1;
|
|
||||||
|
|
||||||
// if not lossless compression, computes tcp_numlayers and max_cs_size depending on the image dimensions
|
// 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
|
// computes a number of layers
|
||||||
U32 surface = rawImageIn.getWidth() * rawImageIn.getHeight();
|
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;
|
// gets the necessary number of layers
|
||||||
parameters.tcp_rates[nb_layers - 1] = (U32)(1.f / DEFAULT_COMPRESSION_RATE); // 1:8 by default
|
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
|
// fills parameters.tcp_rates and updates parameters.tcp_numlayers
|
||||||
U32 max_cs_size = (U32)(surface * image->numcomps * DEFAULT_COMPRESSION_RATE);
|
set_tcp_rates(¶meters, nb_layers, LAST_TCP_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]));
|
|
||||||
}
|
|
||||||
|
|
||||||
//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, ¶meters, image))
|
if (!opj_setup_encoder(encoder, ¶meters, image))
|
||||||
|
|
@ -582,7 +613,7 @@ public:
|
||||||
opj_stream_destroy(stream);
|
opj_stream_destroy(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
stream = opj_stream_create(data_size_guess, false);
|
stream = opj_stream_create(data_size_guess, OPJ_FALSE);
|
||||||
if (!stream)
|
if (!stream)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -623,16 +654,15 @@ public:
|
||||||
|
|
||||||
void setImage(const LLImageRaw& raw)
|
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 numcomps = raw.getComponents();
|
||||||
S32 width = raw.getWidth();
|
S32 width = raw.getWidth();
|
||||||
S32 height = raw.getHeight();
|
S32 height = raw.getHeight();
|
||||||
|
|
||||||
|
std::vector<opj_image_cmptparm_t> cmptparm(numcomps);
|
||||||
|
|
||||||
for (S32 c = 0; c < numcomps; c++)
|
for (S32 c = 0; c < numcomps; c++)
|
||||||
{
|
{
|
||||||
cmptparm[c].prec = 8;
|
cmptparm[c].prec = 8; // replaces .bpp
|
||||||
cmptparm[c].sgnd = 0;
|
cmptparm[c].sgnd = 0;
|
||||||
cmptparm[c].dx = parameters.subsampling_dx;
|
cmptparm[c].dx = parameters.subsampling_dx;
|
||||||
cmptparm[c].dy = parameters.subsampling_dy;
|
cmptparm[c].dy = parameters.subsampling_dy;
|
||||||
|
|
@ -640,7 +670,7 @@ public:
|
||||||
cmptparm[c].h = height;
|
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->x1 = width;
|
||||||
image->y1 = height;
|
image->y1 = height;
|
||||||
|
|
@ -652,7 +682,7 @@ public:
|
||||||
{
|
{
|
||||||
for (S32 x = 0; x < width; x++)
|
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++)
|
for (S32 c = 0; c < numcomps; c++)
|
||||||
{
|
{
|
||||||
image->comps[c].data[i] = *pixel;
|
image->comps[c].data[i] = *pixel;
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,8 @@
|
||||||
|
|
||||||
#include "llimagej2c.h"
|
#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
|
class LLImageJ2COJ : public LLImageJ2CImpl
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
||||||
|
|
@ -1109,7 +1109,7 @@ void LLScrollListCtrl::deleteItems(const LLSD& sd)
|
||||||
void LLScrollListCtrl::deleteSelectedItems()
|
void LLScrollListCtrl::deleteSelectedItems()
|
||||||
{
|
{
|
||||||
item_list::iterator iter;
|
item_list::iterator iter;
|
||||||
for (iter = mItemList.begin(); iter < mItemList.end(); )
|
for (iter = mItemList.begin(); iter != mItemList.end(); )
|
||||||
{
|
{
|
||||||
LLScrollListItem* itemp = *iter;
|
LLScrollListItem* itemp = *iter;
|
||||||
if (itemp->getSelected())
|
if (itemp->getSelected())
|
||||||
|
|
|
||||||
|
|
@ -112,7 +112,6 @@ LLWindow::LLWindow(LLWindowCallbacks* callbacks, bool fullscreen, U32 flags)
|
||||||
mFullscreen(fullscreen),
|
mFullscreen(fullscreen),
|
||||||
mFullscreenWidth(0),
|
mFullscreenWidth(0),
|
||||||
mFullscreenHeight(0),
|
mFullscreenHeight(0),
|
||||||
mFullscreenBits(0),
|
|
||||||
mFullscreenRefresh(0),
|
mFullscreenRefresh(0),
|
||||||
mSupportedResolutions(NULL),
|
mSupportedResolutions(NULL),
|
||||||
mNumSupportedResolutions(0),
|
mNumSupportedResolutions(0),
|
||||||
|
|
|
||||||
|
|
@ -224,7 +224,6 @@ protected:
|
||||||
bool mFullscreen;
|
bool mFullscreen;
|
||||||
S32 mFullscreenWidth;
|
S32 mFullscreenWidth;
|
||||||
S32 mFullscreenHeight;
|
S32 mFullscreenHeight;
|
||||||
S32 mFullscreenBits;
|
|
||||||
S32 mFullscreenRefresh;
|
S32 mFullscreenRefresh;
|
||||||
LLWindowResolution* mSupportedResolutions;
|
LLWindowResolution* mSupportedResolutions;
|
||||||
S32 mNumSupportedResolutions;
|
S32 mNumSupportedResolutions;
|
||||||
|
|
|
||||||
|
|
@ -704,8 +704,7 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dev_mode.dmPelsWidth == width &&
|
if (dev_mode.dmPelsWidth == width &&
|
||||||
dev_mode.dmPelsHeight == height &&
|
dev_mode.dmPelsHeight == height)
|
||||||
dev_mode.dmBitsPerPel == BITS_PER_PIXEL)
|
|
||||||
{
|
{
|
||||||
success = true;
|
success = true;
|
||||||
if ((dev_mode.dmDisplayFrequency - current_refresh)
|
if ((dev_mode.dmDisplayFrequency - current_refresh)
|
||||||
|
|
@ -745,7 +744,7 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
|
||||||
// If we found a good resolution, use it.
|
// If we found a good resolution, use it.
|
||||||
if (success)
|
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
|
// Keep a copy of the actual current device mode in case we minimize
|
||||||
|
|
@ -758,7 +757,6 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
|
||||||
mFullscreen = true;
|
mFullscreen = true;
|
||||||
mFullscreenWidth = dev_mode.dmPelsWidth;
|
mFullscreenWidth = dev_mode.dmPelsWidth;
|
||||||
mFullscreenHeight = dev_mode.dmPelsHeight;
|
mFullscreenHeight = dev_mode.dmPelsHeight;
|
||||||
mFullscreenBits = dev_mode.dmBitsPerPel;
|
|
||||||
mFullscreenRefresh = dev_mode.dmDisplayFrequency;
|
mFullscreenRefresh = dev_mode.dmDisplayFrequency;
|
||||||
|
|
||||||
LL_INFOS("Window") << "Running at " << dev_mode.dmPelsWidth
|
LL_INFOS("Window") << "Running at " << dev_mode.dmPelsWidth
|
||||||
|
|
@ -772,7 +770,6 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
|
||||||
mFullscreen = false;
|
mFullscreen = false;
|
||||||
mFullscreenWidth = -1;
|
mFullscreenWidth = -1;
|
||||||
mFullscreenHeight = -1;
|
mFullscreenHeight = -1;
|
||||||
mFullscreenBits = -1;
|
|
||||||
mFullscreenRefresh = -1;
|
mFullscreenRefresh = -1;
|
||||||
|
|
||||||
std::map<std::string,std::string> args;
|
std::map<std::string,std::string> args;
|
||||||
|
|
@ -1195,7 +1192,7 @@ bool LLWindowWin32::switchContext(bool fullscreen, const LLCoordScreen& size, bo
|
||||||
// If we found a good resolution, use it.
|
// If we found a good resolution, use it.
|
||||||
if (success)
|
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
|
// Keep a copy of the actual current device mode in case we minimize
|
||||||
|
|
@ -1207,7 +1204,6 @@ bool LLWindowWin32::switchContext(bool fullscreen, const LLCoordScreen& size, bo
|
||||||
mFullscreen = true;
|
mFullscreen = true;
|
||||||
mFullscreenWidth = dev_mode.dmPelsWidth;
|
mFullscreenWidth = dev_mode.dmPelsWidth;
|
||||||
mFullscreenHeight = dev_mode.dmPelsHeight;
|
mFullscreenHeight = dev_mode.dmPelsHeight;
|
||||||
mFullscreenBits = dev_mode.dmBitsPerPel;
|
|
||||||
mFullscreenRefresh = dev_mode.dmDisplayFrequency;
|
mFullscreenRefresh = dev_mode.dmDisplayFrequency;
|
||||||
|
|
||||||
LL_INFOS("Window") << "Running at " << dev_mode.dmPelsWidth
|
LL_INFOS("Window") << "Running at " << dev_mode.dmPelsWidth
|
||||||
|
|
@ -1233,7 +1229,6 @@ bool LLWindowWin32::switchContext(bool fullscreen, const LLCoordScreen& size, bo
|
||||||
mFullscreen = false;
|
mFullscreen = false;
|
||||||
mFullscreenWidth = -1;
|
mFullscreenWidth = -1;
|
||||||
mFullscreenHeight = -1;
|
mFullscreenHeight = -1;
|
||||||
mFullscreenBits = -1;
|
|
||||||
mFullscreenRefresh = -1;
|
mFullscreenRefresh = -1;
|
||||||
|
|
||||||
LL_INFOS("Window") << "Unable to run fullscreen at " << width << "x" << height << LL_ENDL;
|
LL_INFOS("Window") << "Unable to run fullscreen at " << width << "x" << height << LL_ENDL;
|
||||||
|
|
@ -3650,7 +3645,7 @@ F32 LLWindowWin32::getPixelAspectRatio()
|
||||||
|
|
||||||
// Change display resolution. Returns true if successful.
|
// Change display resolution. Returns true if successful.
|
||||||
// protected
|
// protected
|
||||||
bool LLWindowWin32::setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh)
|
bool LLWindowWin32::setDisplayResolution(S32 width, S32 height, S32 refresh)
|
||||||
{
|
{
|
||||||
DEVMODE dev_mode;
|
DEVMODE dev_mode;
|
||||||
::ZeroMemory(&dev_mode, sizeof(DEVMODE));
|
::ZeroMemory(&dev_mode, sizeof(DEVMODE));
|
||||||
|
|
@ -3662,7 +3657,6 @@ bool LLWindowWin32::setDisplayResolution(S32 width, S32 height, S32 bits, S32 re
|
||||||
{
|
{
|
||||||
if (dev_mode.dmPelsWidth == width &&
|
if (dev_mode.dmPelsWidth == width &&
|
||||||
dev_mode.dmPelsHeight == height &&
|
dev_mode.dmPelsHeight == height &&
|
||||||
dev_mode.dmBitsPerPel == bits &&
|
|
||||||
dev_mode.dmDisplayFrequency == refresh )
|
dev_mode.dmDisplayFrequency == refresh )
|
||||||
{
|
{
|
||||||
// ...display mode identical, do nothing
|
// ...display mode identical, do nothing
|
||||||
|
|
@ -3674,9 +3668,8 @@ bool LLWindowWin32::setDisplayResolution(S32 width, S32 height, S32 bits, S32 re
|
||||||
dev_mode.dmSize = sizeof(dev_mode);
|
dev_mode.dmSize = sizeof(dev_mode);
|
||||||
dev_mode.dmPelsWidth = width;
|
dev_mode.dmPelsWidth = width;
|
||||||
dev_mode.dmPelsHeight = height;
|
dev_mode.dmPelsHeight = height;
|
||||||
dev_mode.dmBitsPerPel = bits;
|
|
||||||
dev_mode.dmDisplayFrequency = refresh;
|
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.
|
// CDS_FULLSCREEN indicates that this is a temporary change to the device mode.
|
||||||
LONG cds_result = ChangeDisplaySettings(&dev_mode, CDS_FULLSCREEN);
|
LONG cds_result = ChangeDisplaySettings(&dev_mode, CDS_FULLSCREEN);
|
||||||
|
|
@ -3686,7 +3679,7 @@ bool LLWindowWin32::setDisplayResolution(S32 width, S32 height, S32 bits, S32 re
|
||||||
if (!success)
|
if (!success)
|
||||||
{
|
{
|
||||||
LL_WARNS("Window") << "setDisplayResolution failed, "
|
LL_WARNS("Window") << "setDisplayResolution failed, "
|
||||||
<< width << "x" << height << "x" << bits << " @ " << refresh << LL_ENDL;
|
<< width << "x" << height << " @ " << refresh << LL_ENDL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
|
|
@ -3697,7 +3690,7 @@ bool LLWindowWin32::setFullscreenResolution()
|
||||||
{
|
{
|
||||||
if (mFullscreen)
|
if (mFullscreen)
|
||||||
{
|
{
|
||||||
return setDisplayResolution( mFullscreenWidth, mFullscreenHeight, mFullscreenBits, mFullscreenRefresh);
|
return setDisplayResolution( mFullscreenWidth, mFullscreenHeight, mFullscreenRefresh);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -153,7 +153,7 @@ protected:
|
||||||
virtual LLSD getNativeKeyData();
|
virtual LLSD getNativeKeyData();
|
||||||
|
|
||||||
// Changes display resolution. Returns true if successful
|
// 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.
|
// Go back to last fullscreen display resolution.
|
||||||
bool setFullscreenResolution();
|
bool setFullscreenResolution();
|
||||||
|
|
|
||||||
|
|
@ -849,7 +849,7 @@ void LLFloaterModelPreview::onLODParamCommit(S32 lod, bool enforce_tri_limit)
|
||||||
mModelPreview->onLODGLODParamCommit(lod, enforce_tri_limit);
|
mModelPreview->onLODGLODParamCommit(lod, enforce_tri_limit);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LL_ERRS() << "Only supposed to be called to generate models" << LL_ENDL;
|
LL_ERRS() << "Only supposed to be called to generate models, val: " << mode << LL_ENDL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -345,9 +345,6 @@ LLFloaterWorldMap::LLFloaterWorldMap(const LLSD& key)
|
||||||
mSetToUserPosition(true),
|
mSetToUserPosition(true),
|
||||||
mTrackedLocation(0.0,0.0,0.0),
|
mTrackedLocation(0.0,0.0,0.0),
|
||||||
mTrackedStatus(LLTracker::TRACKING_NOTHING),
|
mTrackedStatus(LLTracker::TRACKING_NOTHING),
|
||||||
mListFriendCombo(nullptr),
|
|
||||||
mListLandmarkCombo(nullptr),
|
|
||||||
mListSearchResults(nullptr),
|
|
||||||
mParcelInfoObserver(nullptr),
|
mParcelInfoObserver(nullptr),
|
||||||
mShowParcelInfo(false)
|
mShowParcelInfo(false)
|
||||||
{
|
{
|
||||||
|
|
@ -410,24 +407,22 @@ bool LLFloaterWorldMap::postBuild()
|
||||||
mTeleportCoordSpinZ = getChild<LLSpinCtrl>("teleport_coordinate_z");
|
mTeleportCoordSpinZ = getChild<LLSpinCtrl>("teleport_coordinate_z");
|
||||||
// </FS>
|
// </FS>
|
||||||
|
|
||||||
LLComboBox *avatar_combo = getChild<LLComboBox>("friend combo");
|
mFriendCombo = getChild<LLComboBox>("friend combo");
|
||||||
avatar_combo->selectFirstItem();
|
mFriendCombo->selectFirstItem();
|
||||||
avatar_combo->setPrearrangeCallback( boost::bind(&LLFloaterWorldMap::onAvatarComboPrearrange, this) );
|
mFriendCombo->setPrearrangeCallback(boost::bind(&LLFloaterWorldMap::onAvatarComboPrearrange, this));
|
||||||
avatar_combo->setTextChangedCallback( boost::bind(&LLFloaterWorldMap::onComboTextEntry, this) );
|
mFriendCombo->setTextChangedCallback(boost::bind(&LLFloaterWorldMap::onComboTextEntry, this));
|
||||||
mListFriendCombo = dynamic_cast<LLCtrlListInterface *>(avatar_combo);
|
|
||||||
|
|
||||||
mLocationEditor = getChild<LLSearchEditor>("location");
|
mLocationEditor = getChild<LLSearchEditor>("location");
|
||||||
mLocationEditor->setFocusChangedCallback(boost::bind(&LLFloaterWorldMap::onLocationFocusChanged, this, _1));
|
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));
|
mSearchResults = getChild<LLScrollListCtrl>("search_results");
|
||||||
mListSearchResults = childGetListInterface("search_results");
|
mSearchResults->setDoubleClickCallback(boost::bind(&LLFloaterWorldMap::onClickTeleportBtn, this));
|
||||||
|
|
||||||
LLComboBox *landmark_combo = getChild<LLComboBox>( "landmark combo");
|
mLandmarkCombo = getChild<LLComboBox>("landmark combo");
|
||||||
landmark_combo->selectFirstItem();
|
mLandmarkCombo->selectFirstItem();
|
||||||
landmark_combo->setPrearrangeCallback( boost::bind(&LLFloaterWorldMap::onLandmarkComboPrearrange, this) );
|
mLandmarkCombo->setPrearrangeCallback(boost::bind(&LLFloaterWorldMap::onLandmarkComboPrearrange, this));
|
||||||
landmark_combo->setTextChangedCallback( boost::bind(&LLFloaterWorldMap::onComboTextEntry, this) );
|
mLandmarkCombo->setTextChangedCallback(boost::bind(&LLFloaterWorldMap::onComboTextEntry, this));
|
||||||
mListLandmarkCombo = dynamic_cast<LLCtrlListInterface *>(landmark_combo);
|
|
||||||
|
|
||||||
mZoomSlider = getChild<LLSliderCtrl>("zoom slider");
|
mZoomSlider = getChild<LLSliderCtrl>("zoom slider");
|
||||||
F32 slider_zoom = mMapView->getZoom();
|
F32 slider_zoom = mMapView->getZoom();
|
||||||
|
|
@ -662,7 +657,6 @@ void LLFloaterWorldMap::draw()
|
||||||
// (!rlv_handler_t::isEnabled()) || !(gRlvHandler.hasBehaviour(RLV_BHVR_TPLM) && gRlvHandler.hasBehaviour(RLV_BHVR_TPLOC)));
|
// (!rlv_handler_t::isEnabled()) || !(gRlvHandler.hasBehaviour(RLV_BHVR_TPLM) && gRlvHandler.hasBehaviour(RLV_BHVR_TPLOC)));
|
||||||
//// [/RLVa:KB]
|
//// [/RLVa:KB]
|
||||||
mTeleportButton->setEnabled((bool)tracking_status);
|
mTeleportButton->setEnabled((bool)tracking_status);
|
||||||
//clear_btn->setEnabled((bool)tracking_status);
|
|
||||||
mShowDestinationButton->setEnabled((bool)tracking_status || LLWorldMap::getInstance()->isTracking());
|
mShowDestinationButton->setEnabled((bool)tracking_status || LLWorldMap::getInstance()->isTracking());
|
||||||
mCopySlurlButton->setEnabled((mSLURL.isValid()) );
|
mCopySlurlButton->setEnabled((mSLURL.isValid()) );
|
||||||
mGoHomeButton->setEnabled((!rlv_handler_t::isEnabled()) || !(gRlvHandler.hasBehaviour(RLV_BHVR_TPLM) && gRlvHandler.hasBehaviour(RLV_BHVR_TPLOC)));
|
mGoHomeButton->setEnabled((!rlv_handler_t::isEnabled()) || !(gRlvHandler.hasBehaviour(RLV_BHVR_TPLM) && gRlvHandler.hasBehaviour(RLV_BHVR_TPLOC)));
|
||||||
|
|
@ -758,19 +752,17 @@ 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;
|
mShowParcelInfo = false;
|
||||||
LLCtrlSelectionInterface *iface = childGetSelectionInterface("friend combo");
|
|
||||||
if (!iface) return;
|
|
||||||
|
|
||||||
buildAvatarIDList();
|
buildAvatarIDList();
|
||||||
if(iface->setCurrentByID(avatar_id) || gAgent.isGodlike())
|
if (mFriendCombo->setCurrentByID(avatar_id) || gAgent.isGodlike())
|
||||||
{
|
{
|
||||||
// *HACK: Adjust Z values automatically for liaisons & gods so
|
// *HACK: Adjust Z values automatically for liaisons & gods so
|
||||||
// they swoop down when they click on the map. Requested
|
// they swoop down when they click on the map. Requested
|
||||||
// convenience.
|
// convenience.
|
||||||
if(gAgent.isGodlike())
|
if (gAgent.isGodlike())
|
||||||
{
|
{
|
||||||
mTeleportCoordSpinZ->setValue(LLSD(200.f));
|
mTeleportCoordSpinZ->setValue(LLSD(200.f));
|
||||||
}
|
}
|
||||||
|
|
@ -790,43 +782,36 @@ void LLFloaterWorldMap::trackAvatar( const LLUUID& avatar_id, const std::string&
|
||||||
mTrackCtrlsPanel->setDefaultBtn(mTeleportButton);
|
mTrackCtrlsPanel->setDefaultBtn(mTeleportButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLFloaterWorldMap::trackLandmark( const LLUUID& landmark_item_id )
|
void LLFloaterWorldMap::trackLandmark(const LLUUID& landmark_item_id)
|
||||||
{
|
{
|
||||||
mShowParcelInfo = false;
|
mShowParcelInfo = false;
|
||||||
LLCtrlSelectionInterface *iface = childGetSelectionInterface("landmark combo");
|
|
||||||
if (!iface) return;
|
|
||||||
|
|
||||||
buildLandmarkIDLists();
|
buildLandmarkIDLists();
|
||||||
bool found = false;
|
bool found = false;
|
||||||
S32 idx;
|
S32 idx;
|
||||||
for (idx = 0; idx < mLandmarkItemIDList.size(); idx++)
|
for (idx = 0; idx < mLandmarkItemIDList.size(); idx++)
|
||||||
{
|
{
|
||||||
if ( mLandmarkItemIDList.at(idx) == landmark_item_id)
|
if (mLandmarkItemIDList.at(idx) == landmark_item_id)
|
||||||
{
|
{
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (found && iface->setCurrentByID( landmark_item_id ) )
|
if (found && mLandmarkCombo->setCurrentByID(landmark_item_id))
|
||||||
{
|
{
|
||||||
LLUUID asset_id = mLandmarkAssetIDList.at( idx );
|
LLUUID asset_id = mLandmarkAssetIDList.at(idx);
|
||||||
std::string name;
|
std::string name = mLandmarkCombo->getSimple();
|
||||||
LLComboBox* combo = getChild<LLComboBox>( "landmark combo");
|
|
||||||
if (combo) name = combo->getSimple();
|
|
||||||
mTrackedStatus = LLTracker::TRACKING_LANDMARK;
|
mTrackedStatus = LLTracker::TRACKING_LANDMARK;
|
||||||
LLTracker::trackLandmark(mLandmarkAssetIDList.at( idx ), // assetID
|
LLTracker::trackLandmark(mLandmarkAssetIDList.at(idx), // assetID
|
||||||
mLandmarkItemIDList.at( idx ), // itemID
|
mLandmarkItemIDList.at(idx), // itemID
|
||||||
name); // name
|
name); // name
|
||||||
|
|
||||||
if( asset_id != sHomeID )
|
if (asset_id != sHomeID)
|
||||||
{
|
{
|
||||||
// start the download process
|
// 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
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -1198,14 +1183,11 @@ void LLFloaterWorldMap::friendsChanged()
|
||||||
LLAvatarTracker& t = LLAvatarTracker::instance();
|
LLAvatarTracker& t = LLAvatarTracker::instance();
|
||||||
const LLUUID& avatar_id = t.getAvatarID();
|
const LLUUID& avatar_id = t.getAvatarID();
|
||||||
buildAvatarIDList();
|
buildAvatarIDList();
|
||||||
if(avatar_id.notNull())
|
if (avatar_id.notNull())
|
||||||
{
|
{
|
||||||
LLCtrlSelectionInterface *iface = childGetSelectionInterface("friend combo");
|
|
||||||
const LLRelationship* buddy_info = t.getBuddyInfo(avatar_id);
|
const LLRelationship* buddy_info = t.getBuddyInfo(avatar_id);
|
||||||
if(!iface ||
|
if (!mFriendCombo->setCurrentByID(avatar_id) ||
|
||||||
!iface->setCurrentByID(avatar_id) ||
|
(buddy_info && !buddy_info->isRightGrantedFrom(LLRelationship::GRANT_MAP_LOCATION)) || gAgent.isGodlike())
|
||||||
(buddy_info && !buddy_info->isRightGrantedFrom(LLRelationship::GRANT_MAP_LOCATION)) ||
|
|
||||||
gAgent.isGodlike())
|
|
||||||
{
|
{
|
||||||
LLTracker::stopTracking(false);
|
LLTracker::stopTracking(false);
|
||||||
}
|
}
|
||||||
|
|
@ -1215,15 +1197,12 @@ void LLFloaterWorldMap::friendsChanged()
|
||||||
// No longer really builds a list. Instead, just updates mAvatarCombo.
|
// No longer really builds a list. Instead, just updates mAvatarCombo.
|
||||||
void LLFloaterWorldMap::buildAvatarIDList()
|
void LLFloaterWorldMap::buildAvatarIDList()
|
||||||
{
|
{
|
||||||
LLCtrlListInterface *list = mListFriendCombo;
|
|
||||||
if (!list) return;
|
|
||||||
|
|
||||||
// Delete all but the "None" entry
|
// Delete all but the "None" entry
|
||||||
S32 list_size = list->getItemCount();
|
S32 list_size = mFriendCombo->getItemCount();
|
||||||
if (list_size > 1)
|
if (list_size > 1)
|
||||||
{
|
{
|
||||||
list->selectItemRange(1, -1);
|
mFriendCombo->selectItemRange(1, -1);
|
||||||
list->operateOnSelection(LLCtrlListInterface::OP_DELETE);
|
mFriendCombo->operateOnSelection(LLCtrlListInterface::OP_DELETE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get all of the calling cards for avatar that are currently online
|
// Get all of the calling cards for avatar that are currently online
|
||||||
|
|
@ -1234,38 +1213,35 @@ void LLFloaterWorldMap::buildAvatarIDList()
|
||||||
it = collector.mMappable.begin();
|
it = collector.mMappable.begin();
|
||||||
end = collector.mMappable.end();
|
end = collector.mMappable.end();
|
||||||
// <FS:Ansariel> Sort friend list alphabetically
|
// <FS:Ansariel> Sort friend list alphabetically
|
||||||
//for( ; it != end; ++it)
|
//for(; it != end; ++it)
|
||||||
//{
|
//{
|
||||||
// list->addSimpleElement((*it).second, ADD_BOTTOM, (*it).first);
|
// mFriendCombo->addSimpleElement((*it).second, ADD_BOTTOM, (*it).first);
|
||||||
//}
|
//}
|
||||||
|
|
||||||
std::multimap<std::string, LLUUID> buddymap;
|
std::multimap<std::string, LLUUID> buddymap;
|
||||||
for( ; it != end; ++it)
|
for(; it != end; ++it)
|
||||||
{
|
{
|
||||||
buddymap.insert(std::make_pair((*it).second, (*it).first));
|
buddymap.insert(std::make_pair((*it).second, (*it).first));
|
||||||
}
|
}
|
||||||
for (std::multimap<std::string, LLUUID>::iterator bit = buddymap.begin(); bit != buddymap.end(); ++bit)
|
for (std::multimap<std::string, LLUUID>::iterator bit = buddymap.begin(); bit != buddymap.end(); ++bit)
|
||||||
{
|
{
|
||||||
list->addSimpleElement((*bit).first, ADD_BOTTOM, (*bit).second);
|
mFriendCombo->addSimpleElement((*bit).first, ADD_BOTTOM, (*bit).second);
|
||||||
}
|
}
|
||||||
// </FS:Ansariel>
|
// </FS:Ansariel>
|
||||||
|
|
||||||
list->setCurrentByID( LLAvatarTracker::instance().getAvatarID() );
|
mFriendCombo->setCurrentByID(LLAvatarTracker::instance().getAvatarID());
|
||||||
list->selectFirstItem();
|
mFriendCombo->selectFirstItem();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void LLFloaterWorldMap::buildLandmarkIDLists()
|
void LLFloaterWorldMap::buildLandmarkIDLists()
|
||||||
{
|
{
|
||||||
LLCtrlListInterface *list = mListLandmarkCombo;
|
|
||||||
if (!list) return;
|
|
||||||
|
|
||||||
// Delete all but the "None" entry
|
// Delete all but the "None" entry
|
||||||
S32 list_size = list->getItemCount();
|
S32 list_size = mLandmarkCombo->getItemCount();
|
||||||
if (list_size > 1)
|
if (list_size > 1)
|
||||||
{
|
{
|
||||||
list->selectItemRange(1, -1);
|
mLandmarkCombo->selectItemRange(1, -1);
|
||||||
list->operateOnSelection(LLCtrlListInterface::OP_DELETE);
|
mLandmarkCombo->operateOnSelection(LLCtrlListInterface::OP_DELETE);
|
||||||
}
|
}
|
||||||
|
|
||||||
mLandmarkItemIDList.clear();
|
mLandmarkItemIDList.clear();
|
||||||
|
|
@ -1312,13 +1288,13 @@ void LLFloaterWorldMap::buildLandmarkIDLists()
|
||||||
}
|
}
|
||||||
// </FS:Ansariel>
|
// </FS:Ansariel>
|
||||||
|
|
||||||
list->addSimpleElement(item->getName(), ADD_BOTTOM, item->getUUID());
|
mLandmarkCombo->addSimpleElement(item->getName(), ADD_BOTTOM, item->getUUID());
|
||||||
|
|
||||||
mLandmarkAssetIDList.push_back( item->getAssetUUID() );
|
mLandmarkAssetIDList.push_back( item->getAssetUUID() );
|
||||||
mLandmarkItemIDList.push_back( item->getUUID() );
|
mLandmarkItemIDList.push_back( item->getUUID() );
|
||||||
}
|
}
|
||||||
|
|
||||||
list->selectFirstItem();
|
mLandmarkCombo->selectFirstItem();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1336,10 +1312,9 @@ F32 LLFloaterWorldMap::getDistanceToDestination(const LLVector3d &destination,
|
||||||
|
|
||||||
void LLFloaterWorldMap::clearLocationSelection(bool clear_ui, bool dest_reached)
|
void LLFloaterWorldMap::clearLocationSelection(bool clear_ui, bool dest_reached)
|
||||||
{
|
{
|
||||||
LLCtrlListInterface *list = mListSearchResults;
|
if (!dest_reached || (mSearchResults->getItemCount() == 1))
|
||||||
if (list && (!dest_reached || (list->getItemCount() == 1)))
|
|
||||||
{
|
{
|
||||||
list->operateOnAll(LLCtrlListInterface::OP_DELETE);
|
mSearchResults->operateOnAll(LLCtrlListInterface::OP_DELETE);
|
||||||
}
|
}
|
||||||
LLWorldMap::getInstance()->cancelTracking();
|
LLWorldMap::getInstance()->cancelTracking();
|
||||||
mCompletingRegionName = "";
|
mCompletingRegionName = "";
|
||||||
|
|
@ -1350,11 +1325,7 @@ void LLFloaterWorldMap::clearLandmarkSelection(bool clear_ui)
|
||||||
{
|
{
|
||||||
if (clear_ui || !childHasKeyboardFocus("landmark combo"))
|
if (clear_ui || !childHasKeyboardFocus("landmark combo"))
|
||||||
{
|
{
|
||||||
LLCtrlListInterface *list = mListLandmarkCombo;
|
mLandmarkCombo->selectByValue("None");
|
||||||
if (list)
|
|
||||||
{
|
|
||||||
list->selectByValue( "None" );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1364,10 +1335,9 @@ void LLFloaterWorldMap::clearAvatarSelection(bool clear_ui)
|
||||||
if (clear_ui || !childHasKeyboardFocus("friend combo"))
|
if (clear_ui || !childHasKeyboardFocus("friend combo"))
|
||||||
{
|
{
|
||||||
mTrackedStatus = LLTracker::TRACKING_NOTHING;
|
mTrackedStatus = LLTracker::TRACKING_NOTHING;
|
||||||
LLCtrlListInterface *list = mListFriendCombo;
|
if (mFriendCombo->getSelectedValue().asString() != "None")
|
||||||
if (list && list->getSelectedValue().asString() != "None")
|
|
||||||
{
|
{
|
||||||
list->selectByValue( "None" );
|
mFriendCombo->selectByValue("None");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1423,25 +1393,21 @@ void LLFloaterWorldMap::onGoHome()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void LLFloaterWorldMap::onLandmarkComboPrearrange( )
|
void LLFloaterWorldMap::onLandmarkComboPrearrange()
|
||||||
{
|
{
|
||||||
if( mIsClosing )
|
if (mIsClosing)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
LLCtrlListInterface *list = mListLandmarkCombo;
|
LLUUID current_choice = mLandmarkCombo->getCurrentID();
|
||||||
if (!list) return;
|
|
||||||
|
|
||||||
LLUUID current_choice = list->getCurrentID();
|
|
||||||
|
|
||||||
buildLandmarkIDLists();
|
buildLandmarkIDLists();
|
||||||
|
|
||||||
if( current_choice.isNull() || !list->setCurrentByID( current_choice ) )
|
if (current_choice.isNull() || !mLandmarkCombo->setCurrentByID(current_choice))
|
||||||
{
|
{
|
||||||
LLTracker::stopTracking(false);
|
LLTracker::stopTracking(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLFloaterWorldMap::onComboTextEntry()
|
void LLFloaterWorldMap::onComboTextEntry()
|
||||||
|
|
@ -1461,33 +1427,28 @@ void LLFloaterWorldMap::onSearchTextEntry( )
|
||||||
|
|
||||||
void LLFloaterWorldMap::onLandmarkComboCommit()
|
void LLFloaterWorldMap::onLandmarkComboCommit()
|
||||||
{
|
{
|
||||||
if( mIsClosing )
|
if (mIsClosing)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
LLCtrlListInterface *list = mListLandmarkCombo;
|
|
||||||
if (!list) return;
|
|
||||||
|
|
||||||
LLUUID asset_id;
|
LLUUID asset_id;
|
||||||
LLUUID item_id = list->getCurrentID();
|
LLUUID item_id = mLandmarkCombo->getCurrentID();
|
||||||
|
|
||||||
LLTracker::stopTracking(false);
|
LLTracker::stopTracking(false);
|
||||||
|
|
||||||
//RN: stopTracking() clears current combobox selection, need to reassert it here
|
// RN: stopTracking() clears current combobox selection, need to reassert it here
|
||||||
list->setCurrentByID(item_id);
|
mLandmarkCombo->setCurrentByID(item_id);
|
||||||
|
|
||||||
if( item_id.isNull() )
|
if (item_id.isNull()) {}
|
||||||
{
|
else if (item_id == sHomeID)
|
||||||
}
|
|
||||||
else if( item_id == sHomeID )
|
|
||||||
{
|
{
|
||||||
asset_id = sHomeID;
|
asset_id = sHomeID;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LLInventoryItem* item = gInventory.getItem( item_id );
|
LLInventoryItem* item = gInventory.getItem(item_id);
|
||||||
if( item )
|
if (item)
|
||||||
{
|
{
|
||||||
asset_id = item->getAssetUUID();
|
asset_id = item->getAssetUUID();
|
||||||
}
|
}
|
||||||
|
|
@ -1498,34 +1459,31 @@ void LLFloaterWorldMap::onLandmarkComboCommit()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trackLandmark( item_id);
|
trackLandmark(item_id);
|
||||||
onShowTargetBtn();
|
onShowTargetBtn();
|
||||||
|
|
||||||
// Reset to user postion if nothing is tracked
|
// Reset to user postion if nothing is tracked
|
||||||
mSetToUserPosition = ( LLTracker::getTrackingStatus() == LLTracker::TRACKING_NOTHING );
|
mSetToUserPosition = (LLTracker::getTrackingStatus() == LLTracker::TRACKING_NOTHING);
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
void LLFloaterWorldMap::onAvatarComboPrearrange( )
|
void LLFloaterWorldMap::onAvatarComboPrearrange()
|
||||||
{
|
{
|
||||||
if( mIsClosing )
|
if (mIsClosing)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
LLCtrlListInterface *list = mListFriendCombo;
|
|
||||||
if (!list) return;
|
|
||||||
|
|
||||||
LLUUID current_choice;
|
LLUUID current_choice;
|
||||||
|
|
||||||
if( LLAvatarTracker::instance().haveTrackingInfo() )
|
if (LLAvatarTracker::instance().haveTrackingInfo())
|
||||||
{
|
{
|
||||||
current_choice = LLAvatarTracker::instance().getAvatarID();
|
current_choice = LLAvatarTracker::instance().getAvatarID();
|
||||||
}
|
}
|
||||||
|
|
||||||
buildAvatarIDList();
|
buildAvatarIDList();
|
||||||
|
|
||||||
if( !list->setCurrentByID( current_choice ) || current_choice.isNull() )
|
if (!mFriendCombo->setCurrentByID(current_choice) || current_choice.isNull())
|
||||||
{
|
{
|
||||||
LLTracker::stopTracking(false);
|
LLTracker::stopTracking(false);
|
||||||
}
|
}
|
||||||
|
|
@ -1533,26 +1491,21 @@ void LLFloaterWorldMap::onAvatarComboPrearrange( )
|
||||||
|
|
||||||
void LLFloaterWorldMap::onAvatarComboCommit()
|
void LLFloaterWorldMap::onAvatarComboCommit()
|
||||||
{
|
{
|
||||||
if( mIsClosing )
|
if (mIsClosing)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
LLCtrlListInterface *list = mListFriendCombo;
|
const LLUUID& new_avatar_id = mFriendCombo->getCurrentID();
|
||||||
if (!list) return;
|
|
||||||
|
|
||||||
const LLUUID& new_avatar_id = list->getCurrentID();
|
|
||||||
if (new_avatar_id.notNull())
|
if (new_avatar_id.notNull())
|
||||||
{
|
{
|
||||||
std::string name;
|
std::string name = mFriendCombo->getSimple();
|
||||||
LLComboBox* combo = getChild<LLComboBox>("friend combo");
|
|
||||||
if (combo) name = combo->getSimple();
|
|
||||||
trackAvatar(new_avatar_id, name);
|
trackAvatar(new_avatar_id, name);
|
||||||
onShowTargetBtn();
|
onShowTargetBtn();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{ // Reset to user postion if nothing is tracked
|
{ // Reset to user postion if nothing is tracked
|
||||||
mSetToUserPosition = ( LLTracker::getTrackingStatus() == LLTracker::TRACKING_NOTHING );
|
mSetToUserPosition = (LLTracker::getTrackingStatus() == LLTracker::TRACKING_NOTHING);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1685,8 +1638,9 @@ void LLFloaterWorldMap::onCopySLURL()
|
||||||
|
|
||||||
// std::string image_name = getString(toggle_collapse ? "expand_icon" : "collapse_icon");
|
// std::string image_name = getString(toggle_collapse ? "expand_icon" : "collapse_icon");
|
||||||
// std::string tooltip = getString(toggle_collapse ? "expand_tooltip" : "collapse_tooltip");
|
// std::string tooltip = getString(toggle_collapse ? "expand_tooltip" : "collapse_tooltip");
|
||||||
// getChild<LLIconCtrl>("expand_collapse_icon")->setImage(LLUI::getUIImage(image_name));
|
// LLIconCtrl* expandCollapseIcon = getChild<LLIconCtrl>("expand_collapse_icon");
|
||||||
// getChild<LLIconCtrl>("expand_collapse_icon")->setToolTip(tooltip);
|
// expandCollapseIcon->setImage(LLUI::getUIImage(image_name));
|
||||||
|
// expandCollapseIcon->setToolTip(tooltip);
|
||||||
// getChild<LLPanel>("expand_btn_panel")->setToolTip(tooltip);
|
// getChild<LLPanel>("expand_btn_panel")->setToolTip(tooltip);
|
||||||
//}
|
//}
|
||||||
// </FS:Ansariel>
|
// </FS:Ansariel>
|
||||||
|
|
@ -1911,9 +1865,9 @@ void LLFloaterWorldMap::teleportToAvatar()
|
||||||
|
|
||||||
void LLFloaterWorldMap::flyToAvatar()
|
void LLFloaterWorldMap::flyToAvatar()
|
||||||
{
|
{
|
||||||
if( LLAvatarTracker::instance().haveTrackingInfo() )
|
if (LLAvatarTracker::instance().haveTrackingInfo())
|
||||||
{
|
{
|
||||||
gAgent.startAutoPilotGlobal( LLAvatarTracker::instance().getGlobalPos() );
|
gAgent.startAutoPilotGlobal(LLAvatarTracker::instance().getGlobalPos());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1924,8 +1878,7 @@ void LLFloaterWorldMap::updateSims(bool found_null_sim)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
LLScrollListCtrl *list = getChild<LLScrollListCtrl>("search_results");
|
mSearchResults->operateOnAll(LLCtrlListInterface::OP_DELETE);
|
||||||
list->operateOnAll(LLCtrlListInterface::OP_DELETE);
|
|
||||||
|
|
||||||
// auto name_length = mCompletingRegionName.length(); // <FS:Beq/> FIRE-23591 support map search partial matches (Patch by Kevin Cozens)
|
// auto name_length = mCompletingRegionName.length(); // <FS:Beq/> FIRE-23591 support map search partial matches (Patch by Kevin Cozens)
|
||||||
|
|
||||||
|
|
@ -1955,7 +1908,7 @@ void LLFloaterWorldMap::updateSims(bool found_null_sim)
|
||||||
value["id"] = info->getName();
|
value["id"] = info->getName();
|
||||||
value["columns"][0]["column"] = "sim_name";
|
value["columns"][0]["column"] = "sim_name";
|
||||||
value["columns"][0]["value"] = info->getName();
|
value["columns"][0]["value"] = info->getName();
|
||||||
list->addElement(value);
|
mSearchResults->addElement(value);
|
||||||
num_results++;
|
num_results++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1968,26 +1921,26 @@ void LLFloaterWorldMap::updateSims(bool found_null_sim)
|
||||||
if (num_results > 0)
|
if (num_results > 0)
|
||||||
{
|
{
|
||||||
// Ansariel: Let's sort the list to make it more user-friendly
|
// Ansariel: Let's sort the list to make it more user-friendly
|
||||||
list->sortByColumn("sim_name", true);
|
mSearchResults->sortByColumn("sim_name", true);
|
||||||
|
|
||||||
// if match found, highlight it and go
|
// if match found, highlight it and go
|
||||||
if (!match.isUndefined())
|
if (!match.isUndefined())
|
||||||
{
|
{
|
||||||
list->selectByValue(match);
|
mSearchResults->selectByValue(match);
|
||||||
}
|
}
|
||||||
// else select first found item
|
// else select first found item
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
list->selectFirstItem();
|
mSearchResults->selectFirstItem();
|
||||||
}
|
}
|
||||||
getChild<LLUICtrl>("search_results")->setFocus(true);
|
mSearchResults->setFocus(true);
|
||||||
onCommitSearchResult();
|
onCommitSearchResult();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// if we found nothing, say "none"
|
// if we found nothing, say "none"
|
||||||
list->setCommentText(LLTrans::getString("worldmap_results_none_found"));
|
mSearchResults->setCommentText(LLTrans::getString("worldmap_results_none_found"));
|
||||||
list->operateOnAll(LLCtrlListInterface::OP_DESELECT);
|
mSearchResults->operateOnAll(LLCtrlListInterface::OP_DESELECT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2001,11 +1954,7 @@ void LLFloaterWorldMap::onTeleportFinished()
|
||||||
|
|
||||||
void LLFloaterWorldMap::onCommitSearchResult()
|
void LLFloaterWorldMap::onCommitSearchResult()
|
||||||
{
|
{
|
||||||
LLCtrlListInterface *list = mListSearchResults;
|
std::string sim_name = mSearchResults->getSelectedValue().asString();
|
||||||
if (!list) return;
|
|
||||||
|
|
||||||
LLSD selected_value = list->getSelectedValue();
|
|
||||||
std::string sim_name = selected_value.asString();
|
|
||||||
if (sim_name.empty())
|
if (sim_name.empty())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
|
@ -2021,7 +1970,7 @@ void LLFloaterWorldMap::onCommitSearchResult()
|
||||||
{
|
{
|
||||||
LLVector3d pos_global = info->getGlobalOrigin();
|
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);
|
LLVector3 pos_local(SIM_COORD_DEFAULT, SIM_COORD_DEFAULT, 0.0f);
|
||||||
|
|
||||||
// Did this value come from a trackURL() request?
|
// Did this value come from a trackURL() request?
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,8 @@ class LLCheckBoxCtrl;
|
||||||
class LLSliderCtrl;
|
class LLSliderCtrl;
|
||||||
class LLSpinCtrl;
|
class LLSpinCtrl;
|
||||||
class LLSearchEditor;
|
class LLSearchEditor;
|
||||||
|
class LLComboBox;
|
||||||
|
class LLScrollListCtrl;
|
||||||
|
|
||||||
class LLWorldMapParcelInfoObserver : public LLRemoteParcelInfoObserver
|
class LLWorldMapParcelInfoObserver : public LLRemoteParcelInfoObserver
|
||||||
{
|
{
|
||||||
|
|
@ -224,10 +226,6 @@ private:
|
||||||
LLUUID mTrackedAvatarID;
|
LLUUID mTrackedAvatarID;
|
||||||
LLSLURL mSLURL;
|
LLSLURL mSLURL;
|
||||||
|
|
||||||
LLCtrlListInterface * mListFriendCombo;
|
|
||||||
LLCtrlListInterface * mListLandmarkCombo;
|
|
||||||
LLCtrlListInterface * mListSearchResults;
|
|
||||||
|
|
||||||
LLButton* mTeleportButton = nullptr;
|
LLButton* mTeleportButton = nullptr;
|
||||||
LLButton* mShowDestinationButton = nullptr;
|
LLButton* mShowDestinationButton = nullptr;
|
||||||
LLButton* mCopySlurlButton = nullptr;
|
LLButton* mCopySlurlButton = nullptr;
|
||||||
|
|
@ -259,6 +257,11 @@ private:
|
||||||
|
|
||||||
LLSliderCtrl* mZoomSlider = nullptr;
|
LLSliderCtrl* mZoomSlider = nullptr;
|
||||||
|
|
||||||
|
LLComboBox* mLandmarkCombo = nullptr;
|
||||||
|
LLComboBox* mFriendCombo = nullptr;
|
||||||
|
|
||||||
|
LLScrollListCtrl* mSearchResults = nullptr;
|
||||||
|
|
||||||
LLPanel* mTrackCtrlsPanel = nullptr;
|
LLPanel* mTrackCtrlsPanel = nullptr;
|
||||||
|
|
||||||
boost::signals2::connection mTeleportFinishConnection;
|
boost::signals2::connection mTeleportFinishConnection;
|
||||||
|
|
|
||||||
|
|
@ -311,10 +311,6 @@ void LLHUDText::renderText()
|
||||||
}
|
}
|
||||||
|
|
||||||
text_color = segment_iter->mColor;
|
text_color = segment_iter->mColor;
|
||||||
if (mOnHUDAttachment)
|
|
||||||
{
|
|
||||||
text_color = linearColor4(text_color);
|
|
||||||
}
|
|
||||||
text_color.mV[VALPHA] *= alpha_factor;
|
text_color.mV[VALPHA] *= alpha_factor;
|
||||||
// <FS:minerjr> [FIRE-35019] Add LLHUDNameTag background to floating text and hover highlights
|
// <FS:minerjr> [FIRE-35019] Add LLHUDNameTag background to floating text and hover highlights
|
||||||
// If the text object is highlighted and use hover highlight is enabled, then reset the alpha factor (1.0f)
|
// If the text object is highlighted and use hover highlight is enabled, then reset the alpha factor (1.0f)
|
||||||
|
|
|
||||||
|
|
@ -1100,6 +1100,7 @@ void LLViewerTextureList::updateImageDecodePriority(LLViewerFetchedTexture* imag
|
||||||
bool on_screen = false;
|
bool on_screen = false;
|
||||||
|
|
||||||
U32 face_count = 0;
|
U32 face_count = 0;
|
||||||
|
U32 max_faces_to_check = 1024;
|
||||||
|
|
||||||
// get adjusted bias based on image resolution
|
// get adjusted bias based on image resolution
|
||||||
LLImageGL* img = imagep->getGLTexture();
|
LLImageGL* img = imagep->getGLTexture();
|
||||||
|
|
@ -1142,13 +1143,15 @@ void LLViewerTextureList::updateImageDecodePriority(LLViewerFetchedTexture* imag
|
||||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
|
||||||
for (U32 i = 0; i < LLRender::NUM_TEXTURE_CHANNELS; ++i)
|
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];
|
LLFace* face = (*(imagep->getFaceList(i)))[fi];
|
||||||
|
|
||||||
if (face && face->getViewerObject())
|
if (face && face->getViewerObject())
|
||||||
{
|
{
|
||||||
++face_count;
|
|
||||||
// <FS:minerjr> [FIRE-35081] Blurry prims not changing with graphics settings
|
// <FS:minerjr> [FIRE-35081] Blurry prims not changing with graphics settings
|
||||||
// No longer needed as we no longer re-calculate the face's virtual texture size, we use it directly from the face
|
// No longer needed as we no longer re-calculate the face's virtual texture size, we use it directly from the face
|
||||||
//F32 radius;
|
//F32 radius;
|
||||||
|
|
@ -1259,14 +1262,13 @@ void LLViewerTextureList::updateImageDecodePriority(LLViewerFetchedTexture* imag
|
||||||
on_screen = bool(on_screen_count);
|
on_screen = bool(on_screen_count);
|
||||||
imagep->setCloseToCamera(close_to_camera > 0.0f ? 1.0f : 0.0f);
|
imagep->setCloseToCamera(close_to_camera > 0.0f ? 1.0f : 0.0f);
|
||||||
|
|
||||||
//if (face_count > 1024)
|
//if (face_count > max_faces_to_check)
|
||||||
// Add check for if the image is animated to boost to high as well
|
// Add check for if the image is animated to boost to high as well
|
||||||
if (face_count > 1024 || animated != 0)
|
if (face_count > max_faces_to_check || animated != 0)
|
||||||
// </FS:minerjr> [FIRE-35081]
|
// </FS:minerjr> [FIRE-35081]
|
||||||
{ // this texture is used in so many places we should just boost it and not bother checking its vsize
|
{ // 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
|
// 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);
|
max_vsize = MAX_IMAGE_AREA;
|
||||||
// Do we ever remove it? This also sets texture nodelete!
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (imagep->getType() == LLViewerTexture::LOD_TEXTURE && imagep->getBoostLevel() == LLViewerTexture::BOOST_NONE)
|
if (imagep->getType() == LLViewerTexture::LOD_TEXTURE && imagep->getBoostLevel() == LLViewerTexture::BOOST_NONE)
|
||||||
|
|
|
||||||
|
|
@ -5888,7 +5888,18 @@ void LLViewerWindow::saveImageLocal(LLImageFormatted *image, const snapshot_save
|
||||||
#else
|
#else
|
||||||
boost::filesystem::path b_path(lastSnapshotDir);
|
boost::filesystem::path b_path(lastSnapshotDir);
|
||||||
#endif
|
#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;
|
LLSD args;
|
||||||
args["PATH"] = lastSnapshotDir;
|
args["PATH"] = lastSnapshotDir;
|
||||||
|
|
@ -5897,7 +5908,6 @@ void LLViewerWindow::saveImageLocal(LLImageFormatted *image, const snapshot_save
|
||||||
failure_cb();
|
failure_cb();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
boost::filesystem::space_info b_space = boost::filesystem::space(b_path);
|
|
||||||
if (b_space.free < image->getDataSize())
|
if (b_space.free < image->getDataSize())
|
||||||
{
|
{
|
||||||
LLSD args;
|
LLSD args;
|
||||||
|
|
@ -5914,6 +5924,8 @@ void LLViewerWindow::saveImageLocal(LLImageFormatted *image, const snapshot_save
|
||||||
LLNotificationsUtil::add("SnapshotToComputerFailed", args);
|
LLNotificationsUtil::add("SnapshotToComputerFailed", args);
|
||||||
|
|
||||||
failure_cb();
|
failure_cb();
|
||||||
|
|
||||||
|
// Shouldn't there be a return here?
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look for an unused file name
|
// Look for an unused file name
|
||||||
|
|
|
||||||
|
|
@ -985,7 +985,10 @@ void LLWebRTCVoiceClient::updatePosition(void)
|
||||||
LLWebRTCVoiceClient::participantStatePtr_t participant = findParticipantByID("Estate", gAgentID);
|
LLWebRTCVoiceClient::participantStatePtr_t participant = findParticipantByID("Estate", gAgentID);
|
||||||
if(participant)
|
if(participant)
|
||||||
{
|
{
|
||||||
participant->mRegion = gAgent.getRegion()->getRegionID();
|
if (participant->mRegion != region->getRegionID()) {
|
||||||
|
participant->mRegion = region->getRegionID();
|
||||||
|
setMuteMic(mMuteMic);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3106,8 +3109,6 @@ LLVoiceWebRTCSpatialConnection::~LLVoiceWebRTCSpatialConnection()
|
||||||
|
|
||||||
void LLVoiceWebRTCSpatialConnection::setMuteMic(bool muted)
|
void LLVoiceWebRTCSpatialConnection::setMuteMic(bool muted)
|
||||||
{
|
{
|
||||||
if (mMuted != muted)
|
|
||||||
{
|
|
||||||
mMuted = muted;
|
mMuted = muted;
|
||||||
if (mWebRTCAudioInterface)
|
if (mWebRTCAudioInterface)
|
||||||
{
|
{
|
||||||
|
|
@ -3124,7 +3125,6 @@ void LLVoiceWebRTCSpatialConnection::setMuteMic(bool muted)
|
||||||
mWebRTCAudioInterface->setMute(true);
|
mWebRTCAudioInterface->setMute(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////
|
/////////////////////////////
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue