# 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.xml
master
Ansariel 2025-05-23 13:13:24 +02:00
commit 355a80ab91
18 changed files with 719 additions and 325 deletions

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -281,10 +281,11 @@ S32 LLImageJ2C::calcDataSizeJ2C(S32 w, S32 h, S32 comp, S32 discard_level, F32 r
S32 height = (h > 0) ? h : 2048; S32 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

View File

@ -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.52MP
}
/**
* Sets the parameters.tcp_rates according to the number of layers and a last tcp_rate value (which equals to the final compression ratio).
*
* Example for 6 layers:
*
* i = 5, parameters.tcp_rates[6 - 1 - 5] = 8.0f * (1 << (5 << 1)) = 8192 // Layer 5 (lowest quality)
* i = 4, parameters.tcp_rates[6 - 1 - 4] = 8.0f * (1 << (4 << 1)) = 2048 // Layer 4
* i = 3, parameters.tcp_rates[6 - 1 - 3] = 8.0f * (1 << (3 << 1)) = 512 // Layer 3
* i = 2, parameters.tcp_rates[6 - 1 - 2] = 8.0f * (1 << (2 << 1)) = 128 // Layer 2
* i = 1, parameters.tcp_rates[6 - 1 - 1] = 8.0f * (1 << (1 << 1)) = 32 // Layer 1
* i = 0, parameters.tcp_rates[6 - 1 - 0] = 8.0f * (1 << (0 << 1)) = 8 // Layer 0 (highest quality)
*
*/
static void set_tcp_rates(opj_cparameters_t* parameters, U32 num_layers = 1, F32 last_tcp_rate = LAST_TCP_RATE)
{
parameters->tcp_numlayers = num_layers;
for (int i = num_layers - 1; i >= 0; i--)
{
parameters->tcp_rates[num_layers - 1 - i] = last_tcp_rate * static_cast<F32>(1 << (i << 1));
}
}
class JPEG2KDecode : public JPEG2KBase class JPEG2KDecode : public JPEG2KBase
{ {
public: public:
@ -433,15 +494,16 @@ public:
opj_set_default_encoder_parameters(&parameters); opj_set_default_encoder_parameters(&parameters);
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(&parameters, 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, &parameters, image)) if (!opj_setup_encoder(encoder, &parameters, 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;

View File

@ -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:

View File

@ -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())

View File

@ -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),

View File

@ -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;

View File

@ -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
{ {

View File

@ -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();

View File

@ -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;
} }

View File

@ -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?

View File

@ -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;

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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);
} }
} }
}
} }
///////////////////////////// /////////////////////////////