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:
|
||||
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'
|
||||
|
||||
concurrency:
|
||||
group: qa-test-run
|
||||
cancel-in-progress: true # Cancels any queued job when a new one starts
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: false # Prevents cancellation of in-progress jobs
|
||||
|
||||
jobs:
|
||||
debug-workflow:
|
||||
|
|
@ -26,39 +35,165 @@ jobs:
|
|||
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
|
||||
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
|
||||
# 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')
|
||||
)
|
||||
startsWith(github.event.workflow_run.head_branch, 'Second_Life')) ||
|
||||
github.event_name == 'workflow_dispatch'
|
||||
|
||||
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: |
|
||||
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
|
||||
- name: Verify viewer-automation-main Exists (Windows)
|
||||
if: matrix.os == 'windows'
|
||||
shell: pwsh
|
||||
run: |
|
||||
$BUILD_ID = "${{ github.event.workflow_run.id }}"
|
||||
$ARTIFACTS_URL = "https://api.github.com/repos/secondlife/viewer/actions/runs/$BUILD_ID/artifacts"
|
||||
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 "Windows-installer" }).archive_download_url
|
||||
$ARTIFACT_NAME = ($response.artifacts | Where-Object { $_.name -eq "${{ matrix.artifact }}" }).archive_download_url
|
||||
|
||||
if (-Not $ARTIFACT_NAME) {
|
||||
Write-Host "❌ Error: Windows-installer artifact not found!"
|
||||
Write-Host "❌ Error: ${{ matrix.artifact }} artifact not found!"
|
||||
exit 1
|
||||
}
|
||||
|
||||
|
|
@ -74,16 +209,19 @@ jobs:
|
|||
|
||||
# Ensure download succeeded
|
||||
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
|
||||
}
|
||||
|
||||
- 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
|
||||
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"
|
||||
$BUILD_ID = "${{ env.BUILD_ID }}"
|
||||
$ExtractPath = "${{ env.DOWNLOAD_PATH }}"
|
||||
$InstallerZip = "$ExtractPath\installer.zip"
|
||||
|
||||
# Print paths for debugging
|
||||
|
|
@ -113,16 +251,19 @@ jobs:
|
|||
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)
|
||||
- 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
|
||||
- name: Wait for Installation to Complete (Windows)
|
||||
if: matrix.os == 'windows'
|
||||
shell: pwsh
|
||||
run: |
|
||||
Write-Host "Waiting for the Second Life installer to finish..."
|
||||
|
|
@ -133,18 +274,16 @@ jobs:
|
|||
|
||||
Write-Host "✅ Installation completed!"
|
||||
|
||||
- name: Cleanup Task Scheduler Entry
|
||||
- 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."
|
||||
|
||||
- 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"
|
||||
# Delete Installer ZIP
|
||||
$DeletePath = "${{ env.DOWNLOAD_PATH }}\installer.zip"
|
||||
|
||||
Write-Host "Checking if installer ZIP exists: $DeletePath"
|
||||
|
||||
|
|
@ -156,13 +295,281 @@ jobs:
|
|||
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: |
|
||||
Write-Host "Running QA Test script..."
|
||||
python C:\viewer-sikulix-main\runTests.py
|
||||
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
|
||||
# uses: actions/upload-artifact@v3
|
||||
# if: always()
|
||||
# uses: actions/upload-artifact@v4
|
||||
# with:
|
||||
# name: test-results
|
||||
# path: C:\viewer-sikulix-main\regressionTest\test_results.html
|
||||
# name: test-results-${{ matrix.runner }}
|
||||
# path: ${{ matrix.install-path }}/regressionTest/test_results.html
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -114,9 +114,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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
{
|
||||
|
|
@ -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)
|
||||
{
|
||||
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;
|
||||
|
|
@ -211,14 +232,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
|
||||
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.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
|
||||
{
|
||||
public:
|
||||
|
|
@ -433,15 +494,16 @@ public:
|
|||
|
||||
opj_set_default_encoder_parameters(¶meters);
|
||||
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;
|
||||
}
|
||||
|
|
@ -496,53 +558,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(¶meters, 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, ¶meters, image))
|
||||
|
|
@ -582,7 +613,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;
|
||||
|
|
@ -623,16 +654,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();
|
||||
|
||||
std::vector<opj_image_cmptparm_t> cmptparm(numcomps);
|
||||
|
||||
for (S32 c = 0; c < numcomps; c++)
|
||||
{
|
||||
cmptparm[c].prec = 8;
|
||||
cmptparm[c].prec = 8; // replaces .bpp
|
||||
cmptparm[c].sgnd = 0;
|
||||
cmptparm[c].dx = parameters.subsampling_dx;
|
||||
cmptparm[c].dy = parameters.subsampling_dy;
|
||||
|
|
@ -640,7 +670,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;
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -1109,7 +1109,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())
|
||||
|
|
|
|||
|
|
@ -112,7 +112,6 @@ LLWindow::LLWindow(LLWindowCallbacks* callbacks, bool fullscreen, U32 flags)
|
|||
mFullscreen(fullscreen),
|
||||
mFullscreenWidth(0),
|
||||
mFullscreenHeight(0),
|
||||
mFullscreenBits(0),
|
||||
mFullscreenRefresh(0),
|
||||
mSupportedResolutions(NULL),
|
||||
mNumSupportedResolutions(0),
|
||||
|
|
|
|||
|
|
@ -224,7 +224,6 @@ protected:
|
|||
bool mFullscreen;
|
||||
S32 mFullscreenWidth;
|
||||
S32 mFullscreenHeight;
|
||||
S32 mFullscreenBits;
|
||||
S32 mFullscreenRefresh;
|
||||
LLWindowResolution* mSupportedResolutions;
|
||||
S32 mNumSupportedResolutions;
|
||||
|
|
|
|||
|
|
@ -704,8 +704,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)
|
||||
|
|
@ -745,7 +744,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
|
||||
|
|
@ -758,7 +757,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
|
||||
|
|
@ -772,7 +770,6 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
|
|||
mFullscreen = false;
|
||||
mFullscreenWidth = -1;
|
||||
mFullscreenHeight = -1;
|
||||
mFullscreenBits = -1;
|
||||
mFullscreenRefresh = -1;
|
||||
|
||||
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 (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
|
||||
|
|
@ -1207,7 +1204,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
|
||||
|
|
@ -1233,7 +1229,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;
|
||||
|
|
@ -3650,7 +3645,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));
|
||||
|
|
@ -3662,7 +3657,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
|
||||
|
|
@ -3674,9 +3668,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);
|
||||
|
|
@ -3686,7 +3679,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;
|
||||
|
|
@ -3697,7 +3690,7 @@ bool LLWindowWin32::setFullscreenResolution()
|
|||
{
|
||||
if (mFullscreen)
|
||||
{
|
||||
return setDisplayResolution( mFullscreenWidth, mFullscreenHeight, mFullscreenBits, mFullscreenRefresh);
|
||||
return setDisplayResolution( mFullscreenWidth, mFullscreenHeight, mFullscreenRefresh);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -153,7 +153,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();
|
||||
|
|
|
|||
|
|
@ -849,7 +849,7 @@ void LLFloaterModelPreview::onLODParamCommit(S32 lod, bool enforce_tri_limit)
|
|||
mModelPreview->onLODGLODParamCommit(lod, enforce_tri_limit);
|
||||
break;
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -345,9 +345,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)
|
||||
{
|
||||
|
|
@ -410,24 +407,22 @@ bool LLFloaterWorldMap::postBuild()
|
|||
mTeleportCoordSpinZ = getChild<LLSpinCtrl>("teleport_coordinate_z");
|
||||
// </FS>
|
||||
|
||||
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));
|
||||
|
||||
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();
|
||||
|
|
@ -662,7 +657,6 @@ void LLFloaterWorldMap::draw()
|
|||
// (!rlv_handler_t::isEnabled()) || !(gRlvHandler.hasBehaviour(RLV_BHVR_TPLM) && gRlvHandler.hasBehaviour(RLV_BHVR_TPLOC)));
|
||||
//// [/RLVa:KB]
|
||||
mTeleportButton->setEnabled((bool)tracking_status);
|
||||
//clear_btn->setEnabled((bool)tracking_status);
|
||||
mShowDestinationButton->setEnabled((bool)tracking_status || LLWorldMap::getInstance()->isTracking());
|
||||
mCopySlurlButton->setEnabled((mSLURL.isValid()) );
|
||||
mGoHomeButton->setEnabled((!rlv_handler_t::isEnabled()) || !(gRlvHandler.hasBehaviour(RLV_BHVR_TPLM) && gRlvHandler.hasBehaviour(RLV_BHVR_TPLOC)));
|
||||
|
|
@ -761,11 +755,9 @@ void LLFloaterWorldMap::requestParcelInfo(const LLVector3d& pos_global, const LL
|
|||
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
|
||||
|
|
@ -793,8 +785,6 @@ void LLFloaterWorldMap::trackAvatar( const LLUUID& avatar_id, const std::string&
|
|||
void LLFloaterWorldMap::trackLandmark(const LLUUID& landmark_item_id)
|
||||
{
|
||||
mShowParcelInfo = false;
|
||||
LLCtrlSelectionInterface *iface = childGetSelectionInterface("landmark combo");
|
||||
if (!iface) return;
|
||||
|
||||
buildLandmarkIDLists();
|
||||
bool found = false;
|
||||
|
|
@ -808,12 +798,10 @@ void LLFloaterWorldMap::trackLandmark( const LLUUID& landmark_item_id )
|
|||
}
|
||||
}
|
||||
|
||||
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();
|
||||
std::string name = mLandmarkCombo->getSimple();
|
||||
mTrackedStatus = LLTracker::TRACKING_LANDMARK;
|
||||
LLTracker::trackLandmark(mLandmarkAssetIDList.at(idx), // assetID
|
||||
mLandmarkItemIDList.at(idx), // itemID
|
||||
|
|
@ -824,9 +812,6 @@ void LLFloaterWorldMap::trackLandmark( const LLUUID& landmark_item_id )
|
|||
// start the download process
|
||||
gLandmarkList.getAsset(asset_id);
|
||||
}
|
||||
|
||||
// We have to download both region info and landmark data, so set busy. JC
|
||||
// getWindow()->incBusyCount();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1200,12 +1185,9 @@ void LLFloaterWorldMap::friendsChanged()
|
|||
buildAvatarIDList();
|
||||
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);
|
||||
}
|
||||
|
|
@ -1215,15 +1197,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
|
||||
|
|
@ -1236,7 +1215,7 @@ void LLFloaterWorldMap::buildAvatarIDList()
|
|||
// <FS:Ansariel> Sort friend list alphabetically
|
||||
//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;
|
||||
|
|
@ -1246,26 +1225,23 @@ void LLFloaterWorldMap::buildAvatarIDList()
|
|||
}
|
||||
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>
|
||||
|
||||
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();
|
||||
|
|
@ -1312,13 +1288,13 @@ void LLFloaterWorldMap::buildLandmarkIDLists()
|
|||
}
|
||||
// </FS:Ansariel>
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1336,10 +1312,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 = "";
|
||||
|
|
@ -1350,11 +1325,7 @@ void LLFloaterWorldMap::clearLandmarkSelection(bool clear_ui)
|
|||
{
|
||||
if (clear_ui || !childHasKeyboardFocus("landmark combo"))
|
||||
{
|
||||
LLCtrlListInterface *list = mListLandmarkCombo;
|
||||
if (list)
|
||||
{
|
||||
list->selectByValue( "None" );
|
||||
}
|
||||
mLandmarkCombo->selectByValue("None");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1364,10 +1335,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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1430,18 +1400,14 @@ void LLFloaterWorldMap::onLandmarkComboPrearrange( )
|
|||
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()
|
||||
|
|
@ -1466,20 +1432,15 @@ void LLFloaterWorldMap::onLandmarkComboCommit()
|
|||
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);
|
||||
mLandmarkCombo->setCurrentByID(item_id);
|
||||
|
||||
if( item_id.isNull() )
|
||||
{
|
||||
}
|
||||
if (item_id.isNull()) {}
|
||||
else if (item_id == sHomeID)
|
||||
{
|
||||
asset_id = sHomeID;
|
||||
|
|
@ -1513,9 +1474,6 @@ void LLFloaterWorldMap::onAvatarComboPrearrange( )
|
|||
return;
|
||||
}
|
||||
|
||||
LLCtrlListInterface *list = mListFriendCombo;
|
||||
if (!list) return;
|
||||
|
||||
LLUUID current_choice;
|
||||
|
||||
if (LLAvatarTracker::instance().haveTrackingInfo())
|
||||
|
|
@ -1525,7 +1483,7 @@ void LLFloaterWorldMap::onAvatarComboPrearrange( )
|
|||
|
||||
buildAvatarIDList();
|
||||
|
||||
if( !list->setCurrentByID( current_choice ) || current_choice.isNull() )
|
||||
if (!mFriendCombo->setCurrentByID(current_choice) || current_choice.isNull())
|
||||
{
|
||||
LLTracker::stopTracking(false);
|
||||
}
|
||||
|
|
@ -1538,15 +1496,10 @@ void LLFloaterWorldMap::onAvatarComboCommit()
|
|||
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();
|
||||
}
|
||||
|
|
@ -1685,8 +1638,9 @@ void LLFloaterWorldMap::onCopySLURL()
|
|||
|
||||
// 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);
|
||||
//}
|
||||
// </FS:Ansariel>
|
||||
|
|
@ -1924,8 +1878,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(); // <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["columns"][0]["column"] = "sim_name";
|
||||
value["columns"][0]["value"] = info->getName();
|
||||
list->addElement(value);
|
||||
mSearchResults->addElement(value);
|
||||
num_results++;
|
||||
}
|
||||
}
|
||||
|
|
@ -1968,26 +1921,26 @@ void LLFloaterWorldMap::updateSims(bool found_null_sim)
|
|||
if (num_results > 0)
|
||||
{
|
||||
// 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.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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2001,11 +1954,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;
|
||||
|
|
@ -2021,7 +1970,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?
|
||||
|
|
|
|||
|
|
@ -54,6 +54,8 @@ class LLCheckBoxCtrl;
|
|||
class LLSliderCtrl;
|
||||
class LLSpinCtrl;
|
||||
class LLSearchEditor;
|
||||
class LLComboBox;
|
||||
class LLScrollListCtrl;
|
||||
|
||||
class LLWorldMapParcelInfoObserver : public LLRemoteParcelInfoObserver
|
||||
{
|
||||
|
|
@ -224,10 +226,6 @@ private:
|
|||
LLUUID mTrackedAvatarID;
|
||||
LLSLURL mSLURL;
|
||||
|
||||
LLCtrlListInterface * mListFriendCombo;
|
||||
LLCtrlListInterface * mListLandmarkCombo;
|
||||
LLCtrlListInterface * mListSearchResults;
|
||||
|
||||
LLButton* mTeleportButton = nullptr;
|
||||
LLButton* mShowDestinationButton = nullptr;
|
||||
LLButton* mCopySlurlButton = nullptr;
|
||||
|
|
@ -259,6 +257,11 @@ private:
|
|||
|
||||
LLSliderCtrl* mZoomSlider = nullptr;
|
||||
|
||||
LLComboBox* mLandmarkCombo = nullptr;
|
||||
LLComboBox* mFriendCombo = nullptr;
|
||||
|
||||
LLScrollListCtrl* mSearchResults = nullptr;
|
||||
|
||||
LLPanel* mTrackCtrlsPanel = nullptr;
|
||||
|
||||
boost::signals2::connection mTeleportFinishConnection;
|
||||
|
|
|
|||
|
|
@ -311,10 +311,6 @@ void LLHUDText::renderText()
|
|||
}
|
||||
|
||||
text_color = segment_iter->mColor;
|
||||
if (mOnHUDAttachment)
|
||||
{
|
||||
text_color = linearColor4(text_color);
|
||||
}
|
||||
text_color.mV[VALPHA] *= alpha_factor;
|
||||
// <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)
|
||||
|
|
|
|||
|
|
@ -1100,6 +1100,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();
|
||||
|
|
@ -1142,13 +1143,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;
|
||||
// <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
|
||||
//F32 radius;
|
||||
|
|
@ -1259,14 +1262,13 @@ void LLViewerTextureList::updateImageDecodePriority(LLViewerFetchedTexture* imag
|
|||
on_screen = bool(on_screen_count);
|
||||
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
|
||||
if (face_count > 1024 || animated != 0)
|
||||
if (face_count > max_faces_to_check || animated != 0)
|
||||
// </FS:minerjr> [FIRE-35081]
|
||||
{ // 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)
|
||||
|
|
|
|||
|
|
@ -5888,7 +5888,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;
|
||||
|
|
@ -5897,7 +5908,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;
|
||||
|
|
@ -5914,6 +5924,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
|
||||
|
|
|
|||
|
|
@ -985,7 +985,10 @@ void LLWebRTCVoiceClient::updatePosition(void)
|
|||
LLWebRTCVoiceClient::participantStatePtr_t participant = findParticipantByID("Estate", gAgentID);
|
||||
if(participant)
|
||||
{
|
||||
participant->mRegion = gAgent.getRegion()->getRegionID();
|
||||
if (participant->mRegion != region->getRegionID()) {
|
||||
participant->mRegion = region->getRegionID();
|
||||
setMuteMic(mMuteMic);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3105,8 +3108,6 @@ LLVoiceWebRTCSpatialConnection::~LLVoiceWebRTCSpatialConnection()
|
|||
}
|
||||
|
||||
void LLVoiceWebRTCSpatialConnection::setMuteMic(bool muted)
|
||||
{
|
||||
if (mMuted != muted)
|
||||
{
|
||||
mMuted = muted;
|
||||
if (mWebRTCAudioInterface)
|
||||
|
|
@ -3125,7 +3126,6 @@ void LLVoiceWebRTCSpatialConnection::setMuteMic(bool muted)
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////
|
||||
// WebRTC Spatial Connection
|
||||
|
|
|
|||
Loading…
Reference in New Issue