Compare commits

..
1 Commits
Author SHA1 Message Date
Clifford Yapp acd957aec3 Use Tk-native display selection across graphical tools
DISPLAY is an X11 connection setting, but MGED treated any inherited
value as an explicit Tk screen. Unix-like shells on Windows can export
placeholders, causing native Tk child windows and display managers to
fail even though Tk initialized successfully.

Let Tk select its platform backend and canonical screen when no -d
option is given. Preserve explicit X11 selection by applying DISPLAY
only for Tk initialization, restore the caller environment for Win32
and Aqua, and reject unsupported native screen requests clearly.

Use the initialized Tk screen for WGL and Tk software rendering, and
stop assigning X11 defaults to offscreen or Qt contexts. Remove the
same synthetic DISPLAY assumptions from MGED and Archer scripts so
Archer, RtWizard, BRLMan, and Tk ISST follow consistent startup rules.
2026-10-02 14:54:31 -04:00
64 changed files with 434 additions and 2398 deletions
+2 -44
View File
@@ -384,7 +384,7 @@ jobs:
osx:
name: macOS Clang
needs: [linux]
runs-on: macos-15
runs-on: macos-14
strategy:
fail-fast: true
steps:
@@ -403,7 +403,7 @@ jobs:
- name: Prepare bext dependencies
uses: ./brlcad/.github/actions/prepare-bext
with:
platform-channel: macos-15-${{ runner.arch }}-release
platform-channel: macos-14-${{ runner.arch }}-release
source-dir: ${{ github.workspace }}/brlcad
output-dir: ${{ runner.temp }}/bext_output
build-type: Release
@@ -447,45 +447,3 @@ jobs:
export PATH=$GITHUB_WORKSPACE:$PATH
make package
working-directory: ${{ github.workspace }}/build_osx
# BRL-CAD's STABLE branch is intended to represent the most recent
# SHA1 that has successfully passed our primary tests on our CI
# platforms. This job is intended to execute that update if the
# prior tasks succeed. It's "needs" section should contain every
# test that is not already the dependency of another tests.
# sync-stable-branch:
# name: Sync STABLE branch
# runs-on: ubuntu-latest
# needs: [archives, componentbext, windows_std_tools, osx]
# # This job should only run on a successful push to the main branch
# if: github.ref == 'refs/heads/main' && github.event_name == 'push'
# steps:
# # 1. Generate a short-lived token using the GitHub App
# - name: Generate GitHub App Token
# id: generate_token
# uses: tibdex/github-app-token@v2
# with:
# app_id: ${{ secrets.STABLESYNC_APP_ID }}
# private_key: ${{ secrets.STABLESYNC_APP_PRIVATE_KEY }}
# # 2. Checkout the repository using the App Token
# - name: Checkout Code
# uses: actions/checkout@v4
# with:
# token: ${{ steps.generate_token.outputs.token }}
# fetch-depth: 0 # Fetches all history to safely move branches
# # 3. Securely update and push the STABLE branch pointer
# - name: Update STABLE Branch Pointer
# run: |
# # Configure Git to identify as the GitHub Actions bot
# git config --global user.name "github-actions[bot]"
# git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
# echo "Updating STABLE branch to point to the latest successfully CI tested main SHA: ${{ github.sha }}"
# # Force the local STABLE branch to point directly to the current main SHA
# git branch -f STABLE ${{ github.sha }}
# # Push the updated stable branch reference securely back to origin
# git push origin STABLE --force
+22 -353
View File
@@ -15,24 +15,16 @@ on:
schedule:
- cron: '0 3 * * *' # daily at 03:00 UTC
workflow_dispatch:
inputs:
branch:
description: 'The branch ref to run the conditional jobs on (e.g., refs/heads/pgo)'
required: true
default: 'refs/heads/main'
type: string
env:
DEBIAN_FRONTEND: noninteractive
CLANG_VERSION: 18
jobs:
linux_bext:
name: Linux - BRL-CAD bext build
runs-on: &ubuntu_runner ubuntu-24.04 # Define the ubuntu runner anchor here
runs-on: ubuntu-latest
strategy:
fail-fast: true
env:
DEBIAN_FRONTEND: noninteractive
steps:
- name: Setup - CMake
uses: lukka/get-cmake@latest
@@ -185,7 +177,7 @@ jobs:
osx_bext:
name: macOS - BRL-CAD bext build
needs: [linux_bext]
runs-on: macos-15
runs-on: macos-14
strategy:
fail-fast: true
if: ${{ !cancelled() }}
@@ -233,13 +225,12 @@ jobs:
linux_static:
name: Clang Static Analyser
needs: [linux_bext]
runs-on: *ubuntu_runner # Use the ubuntu runner alias
runs-on: ubuntu-24.04
strategy:
fail-fast: true
if: |
!cancelled() &&
(github.event_name == 'workflow_dispatch' && github.ref == inputs.branch ||
github.event_name == 'schedule' && github.ref == 'refs/heads/main')
env:
DEBIAN_FRONTEND: noninteractive
if: ${{ !cancelled() && github.ref == 'refs/heads/main' }}
steps:
- name: Setup - CMake
uses: lukka/get-cmake@latest
@@ -248,19 +239,19 @@ jobs:
- name: Clang Static Analyzer Setup
run: |
sudo apt-get update
sudo apt-get install -y clang-${{ env.CLANG_VERSION }} clang-tools-${{ env.CLANG_VERSION }}
sudo apt-get install clang-18 clang-tools-18
# Install X/OpenGL dev pkgs
sudo apt-get install -y xserver-xorg-dev libx11-dev libxi-dev libxext-dev libglu1-mesa-dev libfontconfig-dev
sudo apt-get install xserver-xorg-dev libx11-dev libxi-dev libxext-dev libglu1-mesa-dev libfontconfig-dev
# Install tools
sudo apt-get install -y astyle re2c xsltproc libxml2-utils
sudo apt-get install astyle re2c xsltproc libxml2-utils
# Install dependency dev pkgs
sudo apt-get install -y zlib1g-dev libpng-dev libjpeg-dev libtiff-dev libeigen3-dev libgdal-dev libassimp-dev libopencv-dev tcl-dev tk-dev
sudo apt-get install zlib1g-dev libpng-dev libjpeg-dev libtiff-dev libeigen3-dev libgdal-dev libassimp-dev libopencv-dev tcl-dev tk-dev
# Install XCB/OpenGL dev pkgs for Qt - see:
# https://wiki.qt.io/Building_Qt_6_from_Git
# https://doc.qt.io/qt-6/linux-requirements.html
sudo apt-get install -y libfontconfig1-dev libfreetype6-dev libx11-dev libx11-xcb-dev libxext-dev libxfixes-dev libxi-dev libxrender-dev libxcb1-dev libxcb-cursor-dev libxcb-glx0-dev libxcb-keysyms1-dev libxcb-image0-dev libxcb-shm0-dev libxcb-icccm4-dev libxcb-sync-dev libxcb-xfixes0-dev libxcb-shape0-dev libxcb-randr0-dev libxcb-render-util0-dev libxcb-util-dev libxcb-xinerama0-dev libxcb-xkb-dev libxcb-xinput-dev libxcb-xrm-dev libxkbcommon-dev libxkbcommon-x11-dev
sudo apt-get install -y libgl-dev
sudo apt-get install -y libinput-dev
sudo apt-get install libfontconfig1-dev libfreetype6-dev libx11-dev libx11-xcb-dev libxext-dev libxfixes-dev libxi-dev libxrender-dev libxcb1-dev libxcb-cursor-dev libxcb-glx0-dev libxcb-keysyms1-dev libxcb-image0-dev libxcb-shm0-dev libxcb-icccm4-dev libxcb-sync-dev libxcb-xfixes0-dev libxcb-shape0-dev libxcb-randr0-dev libxcb-render-util0-dev libxcb-util-dev libxcb-xinerama0-dev libxcb-xkb-dev libxcb-xinput-dev libxcb-xrm-dev libxkbcommon-dev libxkbcommon-x11-dev
sudo apt-get install libgl-dev
sudo apt-get install libinput-dev # Cleanup
- name: Checkout
uses: actions/checkout@v6
@@ -270,7 +261,7 @@ jobs:
- name: Prepare bext dependencies
uses: ./brlcad/.github/actions/prepare-bext
with:
platform-channel: ubuntu-*ubuntu_version-${{ runner.arch }}-release
platform-channel: ubuntu-24.04-${{ runner.arch }}-release
source-dir: ${{ github.workspace }}/brlcad
output-dir: ${{ runner.temp }}/bext_output
build-type: Release
@@ -287,7 +278,7 @@ jobs:
env:
BRLCAD_EXT_DIR: ${{ runner.temp }}/bext_output
run: |
# The script will now receive the version number and find the tools itself
export PATH=$GITHUB_WORKSPACE:/usr/share/clang/scan-build-18/bin:/usr/share/clang/scan-build-18/libexec:$PATH
cp $GITHUB_WORKSPACE/brlcad/misc/clang-static-analyzer-run.sh .
./clang-static-analyzer-run.sh
working-directory: ${{ github.workspace }}/brlcad/build_clangstatic
@@ -299,339 +290,17 @@ jobs:
html2text scan-reports-all/*/index.html
working-directory: ${{ github.workspace }}/brlcad/build_clangstatic
linux_pgo:
name: GCC Profile-Guided Optimization
needs: [linux_bext]
runs-on: *ubuntu_runner # Use the ubuntu runner alias
timeout-minutes: 180
strategy:
fail-fast: true
env:
CMAKE_BUILD_PARALLEL_LEVEL: "2"
PGO_PATH: ${{ github.workspace }}/pgo-profile
PGO_BENCHMARK_TARGETS: >-
rt pixcmp benchmark_cp BENCHMARK_PIX_cp PIX_LOG_cp
bldg391.g m35.g moss.g sphflake.g star.g world.g
PGO_TRAINING_TARGETS: >-
havoc.g Generic_Twin.g NIST_MBE_PMI_2.g
PGO_TRAINING_SIZE: "512"
PGO_TRAINING_AZIMUTH: "35"
PGO_TRAINING_ELEVATION: "25"
PGO_BENCHMARK_TIMEFRAME: "8"
PGO_BENCHMARK_MAXTIME: "60"
PGO_BENCHMARK_AVERAGE: "3"
PGO_BENCHMARK_DEVIATION: "3"
PGO_MIN_SPEEDUP: "1.0"
if: |
!cancelled() &&
(github.event_name == 'workflow_dispatch' && github.ref == inputs.branch ||
github.event_name == 'schedule' && github.ref == 'refs/heads/main')
steps:
- name: Setup - CMake
uses: lukka/get-cmake@latest
- name: Install apt dependencies
run: |
sudo apt-get update
# Install X/OpenGL dev pkgs
sudo apt-get install xserver-xorg-dev libx11-dev libxi-dev libxext-dev libglu1-mesa-dev libfontconfig-dev
# Install tools
sudo apt-get install astyle re2c xsltproc libxml2-utils
# Install dependency dev pkgs
sudo apt-get install zlib1g-dev libpng-dev libjpeg-dev libtiff-dev libeigen3-dev libgdal-dev libassimp-dev libopencv-dev tcl-dev tk-dev
# Install XCB/OpenGL dev pkgs for a fallback bext build
sudo apt-get install libfontconfig1-dev libfreetype6-dev libx11-dev libx11-xcb-dev libxext-dev libxfixes-dev libxi-dev libxrender-dev libxcb1-dev libxcb-cursor-dev libxcb-glx0-dev libxcb-keysyms1-dev libxcb-image0-dev libxcb-shm0-dev libxcb-icccm4-dev libxcb-sync-dev libxcb-xfixes0-dev libxcb-shape0-dev libxcb-randr0-dev libxcb-render-util0-dev libxcb-util-dev libxcb-xinerama0-dev libxcb-xkb-dev libxcb-xinput-dev libxcb-xrm-dev libxkbcommon-dev libxkbcommon-x11-dev
sudo apt-get install libgl-dev libinput-dev
- name: Checkout
uses: actions/checkout@v6
with:
path: brlcad
- name: Prepare bext dependencies
uses: ./brlcad/.github/actions/prepare-bext
with:
platform-channel: ubuntu-*ubuntu_version-${{ runner.arch }}-release
source-dir: ${{ github.workspace }}/brlcad
output-dir: ${{ runner.temp }}/bext_output
build-type: Release
artifact-token: ${{ secrets.BEXT_ARTIFACT_TOKEN }}
- name: Directory setup
run: |
set -euo pipefail
cmake -E make_directory $HOME/.cache/BRL-CAD
if [[ -e "$PGO_PATH" ]]; then
echo "::error::PGO profile path unexpectedly exists before the generation build"
exit 1
fi
- name: Configure baseline build
run: |
cmake -S brlcad -B build_pgo_baseline -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
-DBUILD_TESTING=ON \
-DBRLCAD_EXT_DIR=${{ runner.temp }}/bext_output \
-DBRLCAD_ENABLE_QT=OFF \
-DBRLCAD_ENABLE_STEP=ON \
-DBRLCAD_ENABLE_STRICT=ON
- name: Build baseline
run: cmake --build build_pgo_baseline --target $PGO_BENCHMARK_TARGETS
- name: Configure profile-generation build
run: |
cmake -S brlcad -B build_pgo -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
-DBUILD_TESTING=ON \
-DBRLCAD_EXT_DIR=${{ runner.temp }}/bext_output \
-DBRLCAD_ENABLE_QT=OFF \
-DBRLCAD_ENABLE_STEP=ON \
-DBRLCAD_ENABLE_STRICT=ON \
-DBRLCAD_PGO=ON
grep -q -- '-fprofile-generate=' build_pgo/compile_commands.json
- name: Build profile-generation binaries
run: cmake --build build_pgo --target $PGO_BENCHMARK_TARGETS $PGO_TRAINING_TARGETS
- name: Generate profile data
run: |
cmake \
-DPGO_MODE=TRAIN \
-DPGO_BUILD_DIR="$GITHUB_WORKSPACE/build_pgo" \
-DPGO_RESULTS_DIR="$GITHUB_WORKSPACE/pgo-training" \
-DPGO_PROFILE_DIR="$PGO_PATH" \
-DPGO_TIMEFRAME="$PGO_BENCHMARK_TIMEFRAME" \
-DPGO_MAXTIME="$PGO_BENCHMARK_MAXTIME" \
-DPGO_AVERAGE="$PGO_BENCHMARK_AVERAGE" \
-DPGO_DEVIATION="$PGO_BENCHMARK_DEVIATION" \
-DPGO_TRAINING_SIZE="$PGO_TRAINING_SIZE" \
-DPGO_TRAINING_AZIMUTH="$PGO_TRAINING_AZIMUTH" \
-DPGO_TRAINING_ELEVATION="$PGO_TRAINING_ELEVATION" \
-P brlcad/misc/CMake/scripts/pgo_benchmark.cmake
- name: Configure profile-use build
run: |
# GCC incorporates the build path into profile filenames, so both
# compilation passes must use the same build directory.
cmake -E rm -rf build_pgo
cmake -S brlcad -B build_pgo -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
-DBUILD_TESTING=ON \
-DBRLCAD_EXT_DIR=${{ runner.temp }}/bext_output \
-DBRLCAD_ENABLE_QT=OFF \
-DBRLCAD_ENABLE_STEP=ON \
-DBRLCAD_ENABLE_STRICT=ON \
-DBRLCAD_PGO=ON
grep -q -- '-fprofile-use=' build_pgo/compile_commands.json
- name: Build profile-guided binaries
run: cmake --build build_pgo --target $PGO_BENCHMARK_TARGETS
- name: Benchmark and compare profile-guided build
run: |
cmake \
-DPGO_MODE=COMPARE \
-DPGO_BASELINE_BUILD_DIR="$GITHUB_WORKSPACE/build_pgo_baseline" \
-DPGO_OPTIMIZED_BUILD_DIR="$GITHUB_WORKSPACE/build_pgo" \
-DPGO_RESULTS_DIR="$GITHUB_WORKSPACE/pgo-results" \
-DPGO_TIMEFRAME="$PGO_BENCHMARK_TIMEFRAME" \
-DPGO_MAXTIME="$PGO_BENCHMARK_MAXTIME" \
-DPGO_AVERAGE="$PGO_BENCHMARK_AVERAGE" \
-DPGO_DEVIATION="$PGO_BENCHMARK_DEVIATION" \
-DPGO_MIN_SPEEDUP="$PGO_MIN_SPEEDUP" \
-P brlcad/misc/CMake/scripts/pgo_benchmark.cmake
windows_pgo:
name: MSVC Profile-Guided Optimization
needs: [windows_bext]
runs-on: windows-latest
timeout-minutes: 180
strategy:
fail-fast: true
env:
CMAKE_BUILD_PARALLEL_LEVEL: "2"
PGO_BENCHMARK_TARGETS: >-
rt pixcmp benchmark_cp BENCHMARK_PIX_cp PIX_LOG_cp
bldg391.g m35.g moss.g sphflake.g star.g world.g
PGO_TRAINING_TARGETS: >-
havoc.g Generic_Twin.g NIST_MBE_PMI_2.g
PGO_TRAINING_SIZE: "512"
PGO_TRAINING_AZIMUTH: "35"
PGO_TRAINING_ELEVATION: "25"
PGO_BENCHMARK_TIMEFRAME: "8"
PGO_BENCHMARK_MAXTIME: "60"
PGO_BENCHMARK_AVERAGE: "3"
PGO_BENCHMARK_DEVIATION: "3"
PGO_MIN_SPEEDUP: "1.0"
if: |
!cancelled() &&
(github.event_name == 'workflow_dispatch' && github.ref == inputs.branch ||
github.event_name == 'schedule' && github.ref == 'refs/heads/main')
steps:
- name: Setup - CMake
uses: lukka/get-cmake@latest
- name: Add msbuild to PATH
uses: microsoft/setup-msbuild@v3
- name: Add cl.exe to PATH
uses: ilammy/msvc-dev-cmd@v1
- name: Checkout
uses: actions/checkout@v6
with:
path: brlcad
- name: Prepare bext dependencies
uses: ./brlcad/.github/actions/prepare-bext
with:
platform-channel: windows-2025-${{ runner.arch }}-release
source-dir: ${{ github.workspace }}/brlcad
output-dir: ${{ runner.temp }}/bext_output
build-type: Release
artifact-token: ${{ secrets.BEXT_ARTIFACT_TOKEN }}
- name: Set up PGO paths
shell: pwsh
run: |
# Short build roots keep STEP-generated paths below Windows MAX_PATH.
$paths = @{
PGO_PATH = Join-Path $env:RUNNER_TEMP 'pgo-d'
PGO_BASELINE_BUILD_DIR = Join-Path $env:RUNNER_TEMP 'pgo-b'
PGO_GENERATE_BUILD_DIR = Join-Path $env:RUNNER_TEMP 'pgo-g'
PGO_OPTIMIZED_BUILD_DIR = Join-Path $env:RUNNER_TEMP 'pgo-u'
PGO_TRAINING_RESULTS_DIR = Join-Path $env:RUNNER_TEMP 'pgo-t'
PGO_RESULTS_DIR = Join-Path $env:RUNNER_TEMP 'pgo-r'
}
if (Test-Path -LiteralPath $paths.PGO_PATH) {
throw "PGO profile path unexpectedly exists before the generation build: $($paths.PGO_PATH)"
}
foreach ($path in $paths.GetEnumerator()) {
Add-Content -Path $env:GITHUB_ENV -Value "$($path.Key)=$($path.Value)"
}
- name: Configure baseline build
shell: pwsh
run: |
cmake -S brlcad -B "$env:PGO_BASELINE_BUILD_DIR" -G Ninja `
-DCMAKE_C_COMPILER=cl.exe `
-DCMAKE_CXX_COMPILER=cl.exe `
-DCMAKE_BUILD_TYPE=Release `
-DBUILD_TESTING=ON `
"-DBRLCAD_EXT_DIR=${{ runner.temp }}/bext_output" `
-DBRLCAD_ENABLE_QT=OFF `
-DBRLCAD_ENABLE_STEP=ON `
-DBRLCAD_ENABLE_STRICT=ON
- name: Build baseline
shell: pwsh
run: |
$targets = $env:PGO_BENCHMARK_TARGETS -split '\s+'
$arguments = @('--build', $env:PGO_BASELINE_BUILD_DIR, '--target') + $targets
cmake @arguments
- name: Configure profile-generation build
shell: pwsh
run: |
cmake -S brlcad -B "$env:PGO_GENERATE_BUILD_DIR" -G Ninja `
-DCMAKE_C_COMPILER=cl.exe `
-DCMAKE_CXX_COMPILER=cl.exe `
-DCMAKE_BUILD_TYPE=Release `
-DBUILD_TESTING=ON `
"-DBRLCAD_EXT_DIR=${{ runner.temp }}/bext_output" `
-DBRLCAD_ENABLE_QT=OFF `
-DBRLCAD_ENABLE_STEP=ON `
-DBRLCAD_ENABLE_STRICT=ON `
-DBRLCAD_PGO=ON
if ($LASTEXITCODE -ne 0) {
exit $LASTEXITCODE
}
if (-not (Select-String -Path "$env:PGO_GENERATE_BUILD_DIR/build.ninja" -SimpleMatch '/GENPROFILE:PGD=' -Quiet)) {
throw 'The profile-generation build does not contain /GENPROFILE.'
}
- name: Build profile-generation binaries
shell: pwsh
run: |
$targets = ($env:PGO_BENCHMARK_TARGETS + ' ' + $env:PGO_TRAINING_TARGETS) -split '\s+'
$arguments = @('--build', $env:PGO_GENERATE_BUILD_DIR, '--target') + $targets
cmake @arguments
- name: Generate profile data
shell: pwsh
run: |
cmake `
-DPGO_MODE=TRAIN `
"-DPGO_BUILD_DIR=$env:PGO_GENERATE_BUILD_DIR" `
"-DPGO_RESULTS_DIR=$env:PGO_TRAINING_RESULTS_DIR" `
"-DPGO_PROFILE_DIR=$env:PGO_PATH" `
"-DPGO_TIMEFRAME=$env:PGO_BENCHMARK_TIMEFRAME" `
"-DPGO_MAXTIME=$env:PGO_BENCHMARK_MAXTIME" `
"-DPGO_AVERAGE=$env:PGO_BENCHMARK_AVERAGE" `
"-DPGO_DEVIATION=$env:PGO_BENCHMARK_DEVIATION" `
"-DPGO_TRAINING_SIZE=$env:PGO_TRAINING_SIZE" `
"-DPGO_TRAINING_AZIMUTH=$env:PGO_TRAINING_AZIMUTH" `
"-DPGO_TRAINING_ELEVATION=$env:PGO_TRAINING_ELEVATION" `
-P brlcad/misc/CMake/scripts/pgo_benchmark.cmake
- name: Configure profile-use build
shell: pwsh
run: |
cmake -S brlcad -B "$env:PGO_OPTIMIZED_BUILD_DIR" -G Ninja `
-DCMAKE_C_COMPILER=cl.exe `
-DCMAKE_CXX_COMPILER=cl.exe `
-DCMAKE_BUILD_TYPE=Release `
-DBUILD_TESTING=ON `
"-DBRLCAD_EXT_DIR=${{ runner.temp }}/bext_output" `
-DBRLCAD_ENABLE_QT=OFF `
-DBRLCAD_ENABLE_STEP=ON `
-DBRLCAD_ENABLE_STRICT=ON `
-DBRLCAD_PGO=ON
if ($LASTEXITCODE -ne 0) {
exit $LASTEXITCODE
}
if (-not (Select-String -Path "$env:PGO_OPTIMIZED_BUILD_DIR/build.ninja" -SimpleMatch '/USEPROFILE:PGD=' -Quiet)) {
throw 'The profile-use build does not contain /USEPROFILE.'
}
- name: Build profile-guided binaries
shell: pwsh
run: |
$targets = $env:PGO_BENCHMARK_TARGETS -split '\s+'
$arguments = @('--build', $env:PGO_OPTIMIZED_BUILD_DIR, '--target') + $targets
cmake @arguments
- name: Benchmark and compare profile-guided build
shell: pwsh
run: |
cmake `
-DPGO_MODE=COMPARE `
"-DPGO_BASELINE_BUILD_DIR=$env:PGO_BASELINE_BUILD_DIR" `
"-DPGO_OPTIMIZED_BUILD_DIR=$env:PGO_OPTIMIZED_BUILD_DIR" `
"-DPGO_RESULTS_DIR=$env:PGO_RESULTS_DIR" `
"-DPGO_TIMEFRAME=$env:PGO_BENCHMARK_TIMEFRAME" `
"-DPGO_MAXTIME=$env:PGO_BENCHMARK_MAXTIME" `
"-DPGO_AVERAGE=$env:PGO_BENCHMARK_AVERAGE" `
"-DPGO_DEVIATION=$env:PGO_BENCHMARK_DEVIATION" `
"-DPGO_MIN_SPEEDUP=$env:PGO_MIN_SPEEDUP" `
-P brlcad/misc/CMake/scripts/pgo_benchmark.cmake
# See https://app.codecov.io/gh/BRL-CAD/brlcad for analysis results
linux_cov:
name: LCOV Coverage testing
needs: [linux_bext]
runs-on: *ubuntu_runner # Use the ubuntu runner alias
runs-on: ubuntu-24.04
strategy:
fail-fast: true
if: |
!cancelled() &&
(github.event_name == 'workflow_dispatch' && github.ref == inputs.branch ||
github.event_name == 'schedule' && github.ref == 'refs/heads/main')
env:
DEBIAN_FRONTEND: noninteractive
if: ${{ !cancelled() && github.ref == 'refs/heads/main' }}
steps:
- name: Setup - CMake
uses: lukka/get-cmake@latest
@@ -662,7 +331,7 @@ jobs:
- name: Prepare bext dependencies
uses: ./brlcad/.github/actions/prepare-bext
with:
platform-channel: ubuntu-*ubuntu_version-${{ runner.arch }}-release
platform-channel: ubuntu-24.04-${{ runner.arch }}-release
source-dir: ${{ github.workspace }}/brlcad
output-dir: ${{ runner.temp }}/bext_output
build-type: Release
+10 -109
View File
@@ -231,7 +231,7 @@ set(CMAKE_FIND_USE_PACKAGE_REGISTRY FALSE)
# Prepare to manage and build BRL-CAD's external dependencies. Specifies a
# specific commit hash to use in the 'bext' repository.
include(BRLCAD_ExternalDeps)
brlcad_bext_init(5ccf9b577dbccef244e2fea7e2741027f0c83555)
brlcad_bext_init(0682795bcfe34644c17e5a4bdd0225c76f6bdc98)
#---------------------------------------------------------------------
# Define various utilities.
@@ -352,10 +352,9 @@ set(CMAKE_SKIP_BUILD_RPATH FALSE)
# it should only be set to the installation value when actually installed.
set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
# Installed runtime paths are defined explicitly below. Do not append
# directories discovered on the build host, since those paths may not exist
# or may resolve to unrelated libraries on the installed system.
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH FALSE)
# Add the automatically determined parts of the RPATH which point to
# directories outside the build tree to the install RPATH
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
# The following logic is what allows binaries to run successfully in the build
# directory AND install directory.
@@ -1338,90 +1337,6 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
brlcad_deferred_define("BRLCAD_HAS_BIG_STACK 1")
endif()
# Profile-Guided Optimization uses a shared profile location for both compiler
# families. A path that does not exist selects the instrumentation pass; an
# existing path selects the profile-use pass in a fresh build tree.
if("$ENV{PGO_PATH}" STREQUAL "")
set(BRLCAD_PGO_PATH "${CMAKE_BINARY_DIR}/profiling")
else()
file(TO_CMAKE_PATH "$ENV{PGO_PATH}" BRLCAD_PGO_PATH)
endif()
# MSVC creates one profile database per linked image. The target-dependent
# generator expression gives every executable and DLL a distinct database,
# while /GL also covers code contributed through object and static libraries.
if(MSVC AND BRLCAD_PGO)
if(DEFINED BRLCAD_MSVC_PGO_PHASE)
if(NOT "${BRLCAD_MSVC_PGO_PATH}" STREQUAL "${BRLCAD_PGO_PATH}")
message(
FATAL_ERROR
"PGO_PATH changed from '${BRLCAD_MSVC_PGO_PATH}' to '${BRLCAD_PGO_PATH}'. "
"Use a fresh build directory when changing PGO phases or profile locations."
)
endif()
elseif(EXISTS "${BRLCAD_PGO_PATH}")
set(BRLCAD_MSVC_PGO_PHASE USE)
else()
set(BRLCAD_MSVC_PGO_PHASE GENERATE)
endif()
if(NOT BRLCAD_MSVC_PGO_PHASE MATCHES "^(GENERATE|USE)$")
message(FATAL_ERROR "Invalid internal MSVC PGO phase '${BRLCAD_MSVC_PGO_PHASE}'")
endif()
set(BRLCAD_MSVC_PGO_PHASE "${BRLCAD_MSVC_PGO_PHASE}" CACHE INTERNAL "MSVC PGO build phase" FORCE)
set(BRLCAD_MSVC_PGO_PATH "${BRLCAD_PGO_PATH}" CACHE INTERNAL "MSVC PGO profile path" FORCE)
if(BRLCAD_MSVC_PGO_PHASE STREQUAL "GENERATE")
# link.exe requires the PGD parent directory to exist before it links the
# instrumented image. Cache the phase above so an in-place CMake rerun
# does not mistake this newly created directory for completed profiles.
file(MAKE_DIRECTORY "${BRLCAD_PGO_PATH}")
set(_brlcad_msvc_pgo_link_mode GENPROFILE)
message(
STATUS
"MSVC PGO generation enabled; set VCPROFILE_PATH=${BRLCAD_PGO_PATH} while running training workloads"
)
distclean("${BRLCAD_PGO_PATH}")
else()
message(STATUS "MSVC PGO profile use enabled from ${BRLCAD_PGO_PATH}")
endif()
add_compile_options("$<$<COMPILE_LANGUAGE:C,CXX>:/GL>")
add_link_options(/LTCG)
if(_brlcad_msvc_pgo_link_mode)
add_link_options(
"/${_brlcad_msvc_pgo_link_mode}:PGD=${BRLCAD_PGO_PATH}/$<TARGET_PROPERTY:NAME>.pgd"
)
endif()
unset(_brlcad_msvc_pgo_link_mode)
endif()
# Apply profile-use only to images exercised during training. link.exe emits
# C4961 for an untrained PGD, and strict builds promote that warning to an
# error during LTCG. The generation pass names PGC files after the target's
# PGD, so this check also works when OUTPUT_NAME changes the binary name.
function(_BRLCAD_MSVC_PGO_APPLY_PROFILES directory)
get_property(_brlcad_pgo_targets DIRECTORY "${directory}" PROPERTY BUILDSYSTEM_TARGETS)
foreach(_brlcad_pgo_target IN LISTS _brlcad_pgo_targets)
get_target_property(_brlcad_pgo_target_type ${_brlcad_pgo_target} TYPE)
if(_brlcad_pgo_target_type MATCHES "^(EXECUTABLE|SHARED_LIBRARY|MODULE_LIBRARY)$")
set(_brlcad_pgo_database "${BRLCAD_PGO_PATH}/${_brlcad_pgo_target}.pgd")
file(GLOB _brlcad_pgo_counts LIST_DIRECTORIES FALSE "${BRLCAD_PGO_PATH}/${_brlcad_pgo_target}![0-9]*.pgc")
if(EXISTS "${_brlcad_pgo_database}" AND _brlcad_pgo_counts)
target_link_options(${_brlcad_pgo_target} PRIVATE "/USEPROFILE:PGD=${_brlcad_pgo_database}")
set_property(GLOBAL APPEND PROPERTY BRLCAD_MSVC_PGO_TRAINED_TARGETS ${_brlcad_pgo_target})
endif()
unset(_brlcad_pgo_counts)
unset(_brlcad_pgo_database)
endif()
endforeach()
get_property(_brlcad_pgo_subdirectories DIRECTORY "${directory}" PROPERTY SUBDIRECTORIES)
foreach(_brlcad_pgo_subdirectory IN LISTS _brlcad_pgo_subdirectories)
_brlcad_msvc_pgo_apply_profiles("${_brlcad_pgo_subdirectory}")
endforeach()
endfunction()
# The following tests are almost entirely for gcc/llvm style flags, so
# we don't unnecessarily slow down the Windows build.
if(NOT MSVC)
@@ -1484,6 +1399,11 @@ if(NOT MSVC)
# variable set to a temp folder
set(pgo_flags_found "")
if("$ENV{PGO_PATH}" STREQUAL "")
set(BRLCAD_PGO_PATH "${CMAKE_BINARY_DIR}/profiling")
else(NOT "$ENV{PGO_PATH}" STREQUAL "")
set(BRLCAD_PGO_PATH "$ENV{PGO_PATH}")
endif("$ENV{PGO_PATH}" STREQUAL "")
if(BRLCAD_PGO AND NOT EXISTS "${BRLCAD_PGO_PATH}")
if("${CMAKE_C_FLAGS}" MATCHES ".*fprofile-use.*")
@@ -1529,8 +1449,7 @@ if(NOT MSVC)
# gcc-style USE
if("${pgo_flags_found}" STREQUAL "")
cmake_push_check_state()
set(flags "fprofile-use=\"${BRLCAD_PGO_PATH}\" -Wno-error=coverage-mismatch")
string(APPEND flags " -Wno-error=missing-profile -fprofile-correction")
set(flags "fprofile-use=\"${BRLCAD_PGO_PATH}\" -Wno-error=coverage-mismatch -fprofile-correction")
set(CMAKE_REQUIRED_FLAGS "-${flags}")
check_c_flag("${flags}" GROUPS OPTIMIZE_C_FLAGS VARS pgo_flags_found)
check_cxx_flag("${flags}" GROUPS OPTIMIZE_CXX_FLAGS)
@@ -3053,24 +2972,6 @@ verbose_add_subdirectory("" doc)
# NOTE: misc/tools is added separately (earlier)
verbose_add_subdirectory("" misc)
if(MSVC AND BRLCAD_PGO AND BRLCAD_MSVC_PGO_PHASE STREQUAL "USE")
set_property(GLOBAL PROPERTY BRLCAD_MSVC_PGO_TRAINED_TARGETS)
_brlcad_msvc_pgo_apply_profiles("${CMAKE_SOURCE_DIR}")
get_property(_brlcad_msvc_pgo_targets GLOBAL PROPERTY BRLCAD_MSVC_PGO_TRAINED_TARGETS)
list(LENGTH _brlcad_msvc_pgo_targets _brlcad_msvc_pgo_target_count)
if(_brlcad_msvc_pgo_target_count EQUAL 0)
message(
FATAL_ERROR
"No MSVC PGO counter files were found in ${BRLCAD_PGO_PATH}. "
"Set VCPROFILE_PATH to that directory while running the training workloads "
"before configuring the profile-use build."
)
endif()
message(STATUS "MSVC PGO will use training data for ${_brlcad_msvc_pgo_target_count} linked targets")
unset(_brlcad_msvc_pgo_target_count)
unset(_brlcad_msvc_pgo_targets)
endif()
#------------------------------------------------------------------------------
# CMake package configuration files for modern find_package(BRLCAD CONFIG)
#
+48 -85
View File
@@ -10,108 +10,82 @@ descriptive text that emphasizes or further describes significant
changes made. See document footer for additional details.
----------------------------------------------------------------------
--- 2026-10-0X Release 7.46.0 ---
--- 20XX-XX-XX Release 7.46.0 ---
----------------------------------------------------------------------
This release expands geometry conversion and improves modeling
reliability. STEP support adds AP203e2, AP214, and AP242
import/export, native CSG round trips, and AP242 product and
manufacturing information (PMI) import. IGES and JT conversion is
expanded, and new OpenSCAD CSG import/export tools are available.
Facetization is more reliable, NMG solid ray tracing is 10-20 times
faster, CSG ray tracing is faster, and BoT, DSP, and point-cloud ray
intersections are corrected. MGED gains numerous fixes to primitive,
sketch, and combination editing, drawing, dialogs, and preferences.
New tools support object nesting with arrange, building generation
with mkbuilding, annotation editing, and primitive repair. Geometry
analysis, image utilities, Windows support, documentation, and bundled
dependencies also receive substantial updates.
* corrected Archer logic for saving window size - Cliff Yapp
* fixed inside BoT rays, DSP surface normals, PNTS bounds - Cliff Yapp
* improved mged fallback HTML manual viewer - Cliff Yapp
* fixed gqa undefined densities and exit status - Chris McGregor
* added ARBN support to the mged inside command - Cliff Yapp
* improved HYP neck-ratio labels and BoT face selection - Cliff Yapp
* fixed mged view panning, edit rotation, & ray queries - Cliff Yapp
* preserved ARB, CLINE, TGC, & extrusion geometry edits - Cliff Yapp
* restored mged command prompt focus at GUI startup - Cliff Yapp
* new documentation on geometry representation schemes - Sean Morrison
* improved pixscale & bwscale scaling and image piping - Sean Morrison
* restored pixdiff behavior on .pix, added -b for .bw - Sean Morrison
* improved facetize fallback methods and reliability - Cliff Yapp
* updated mged and Archer for Tcl 8.6.18 and Itcl/Itk 4 - Cliff Yapp
* updated MGED and Archer for Tcl 8.6.18 and Itcl/Itk 4 - Cliff Yapp
* fixed writes to fileless geometry databases - Cliff Yapp
* fixed nastran-g handling of large property IDs - Rupesh, Cliff Yapp
* fixed dxf-g invalid polyface idx crash - Meghna45-code, Cliff Yapp
* fixed dxf-g invalid polyface index crashes - Meghna45-code, Cliff Yapp
* fixed Archer primitive editors under Itcl 4 - Cliff Yapp
* fixed Archer shutdown menu cleanup errors - Cliff Yapp
* fixed MGED Build Pattern dialog under Itcl 4 - Cliff Yapp
* fixed TclCAD framebuffer listing and deletion - Cliff Yapp
* fixed mged Build Pattern progress updates - Cliff Yapp
* fixed mged search -exec reentry and Ctrl-C crashes - Cliff Yapp
* fixed mged asynchronous commands and clone progress - Cliff Yapp
* accelerated large and repeated mged path drawing - Cliff Yapp
* fixed MGED Build Pattern progress updates - Cliff Yapp
* fixed MGED search -exec reentry and Ctrl-C crashes - Cliff Yapp
* fixed MGED asynchronous commands and clone progress - Cliff Yapp
* accelerated large and repeated MGED path drawing - Cliff Yapp
* fixed ARB7 inside solid construction - Cliff Yapp
* fixed direct ARB face and edge-direction editing - Cliff Yapp
* fixed rtwizard startup with framebuffer contention - Cliff Yapp
* fixed Archer annotation line display updates - Cliff Yapp
* fixed Archer sketch scale drift in non-mm databases - Cliff Yapp
* fixed toggle arrow callbacks during setup - Cliff Yapp
* fixed Tcl dialogs with multi-word titles and msgs - Cliff Yapp
* fixed Tcl dialogs with multi-word titles and messages - Cliff Yapp
* fixed Archer Tank Wizard gun generation - Cliff Yapp
* fixed mged and Archer sketch arc tangency editing - Cliff Yapp
* fixed MGED and Archer sketch arc tangency editing - Cliff Yapp
* fixed Archer ARB4 point 3 editing - Cliff Yapp
* fixed ARB4 storage from make and mk_arb4 - Cliff Yapp
* fixed ARB4 and ARB6 center point calculations - Cliff Yapp
* fixed concurrent mged and rtwizard framebuffer use - Cliff Yapp
* fixed mged ShotVis editing and reload failures - Cliff Yapp
* fixed concurrent MGED and rtwizard framebuffer use - Cliff Yapp
* fixed MGED ShotVis editing and reload failures - Cliff Yapp
* fixed Tcl widget geometry and selection defects - Cliff Yapp
* fixed mged BoT editor property handling - Cliff Yapp
* fixed mged LOD dialog and adaptive BoT wireframes - Cliff Yapp
* fixed mged Plot, PostScript, and manual launch tools - Cliff Yapp
* fixed mged Overlap Tool multi-object result handling - Cliff Yapp
* fixed MGED BoT editor property handling - Cliff Yapp
* fixed MGED LOD dialog and adaptive BoT wireframes - Cliff Yapp
* fixed MGED Plot, PostScript, and manual launch tools - Cliff Yapp
* fixed MGED Overlap Tool multi-object result handling - Cliff Yapp
* eliminated 16-fold redundant gchecker grid analysis - Cliff Yapp
* fixed submodel transforms & relative database paths - Sean Morrison
* fixed Archer tree handling for names with spaces - Cliff Yapp
* fixed Archer tree handling for object names with spaces - Cliff Yapp
* fixed RtWizard multi-object edge occlusion handling - Cliff Yapp
* fixed RtWizard title, About, and preference handling - Cliff Yapp
* fixed mged startup file false legacy-syntax warnings - Cliff Yapp
* fixed mged saved-view deletion and collaboration sync - Cliff Yapp
* fixed mged font preferences apply and persistence - Cliff Yapp
* fixed MGED startup file false legacy-syntax warnings - Cliff Yapp
* fixed MGED saved-view deletion and collaboration sync - Cliff Yapp
* fixed MGED font preferences apply and persistence - Cliff Yapp
* fixed Archer combination edits changing Boolean trees - Cliff Yapp
* fixed Archer command-line help startup crash - Cliff Yapp
* fixed mged Geometry Browser menu and close behavior - Cliff Yapp
* fixed mged collaboration view unshare crash - Cliff Yapp
* added override for Archer's preference file location - Cliff Yapp
* fixed MGED Geometry Browser menu and close behavior - Cliff Yapp
* fixed MGED collaboration view unshare crash - Cliff Yapp
* added an override for Archer's preference file location - Cliff Yapp
* fixed embedded Archer display and mode menus - Cliff Yapp
* added Archer -h and --help command-line options - Cliff Yapp
* fixed Archer Help opening the documentation menu - Sean Morrison
* added arrange nest command for packing db objects - Sean Morrison
* added mkbuilding for parametric/OSM/CityJSON models - Sean Morrison
* improved fallback methodologies for facetize pipeline - Cliff Yapp
* improved facetize pipeline robustness - Cliff Yapp
* added arrange nest command for packing database objects - Sean Morrison
* new mkbuilding tool for parametric/OSM/CityJSON models - Sean Morrison
* cross-platform BINUNIF and DSP byte-order handling - Sean Morrison
* improved several cv default behaviors (s,32,64,n) - Sean Morrison
* improved several cv default behaviors (s, 32, 64, n) - Sean Morrison
* fixed invalid bot handling bug applying matrices - Sean Morrison
* improved glTF import robustness via gcv - Sean Morrison
* fixed bot dump glTF/GLB export; -F is now rejected - Cliff Yapp
* faster NMG solid ray tracing (10-20x faster) - Sean Morrison
* preserved prim colors in shaded BoT and B-Rep drawing - Cliff Yapp
* preserved B-Rep attrs through in-place geometry edits - Cliff Yapp
* fixed gcv filter arguments w/ one-character values - Cliff Yapp
* preserved primitive colors in shaded BoT and B-Rep drawing - Cliff Yapp
* preserved B-Rep attributes through in-place geometry edits - Cliff Yapp
* fixed gcv filter arguments containing one-character values - Cliff Yapp
* improved iges-g importer robustness - Cliff Yapp
* expanded g-iges native CSG and B-Rep export support - Cliff Yapp
* added IGES import and export support to gcv - Cliff Yapp
* rt -b query option now supports a single value idx - Sean Morrison
* rt -b query option now supports a single value index - Sean Morrison
* fixed .dpix file format portability and icv support - Sean Morrison
* expanded pixscale support for piped image data - Sean Morrison
* fixed HYP volume and ARBN totals reported by analyze - Cliff Yapp
* fixed VOL data-file lookup and missing-data errors - Chris McGregor
* corrected rtarea sampling/exposed-area calculations - Cliff Yapp
* corrected rtarea sampling and exposed-area calculations - Cliff Yapp
* bot split now groups results and preserves mesh data - Cliff Yapp
* bot decimate now preserves nrmls, UVs, and plate data - Cliff Yapp
* bot decimate now preserves normals, UVs, and plate data - Cliff Yapp
* added raytracing support for annotation objects - Cliff Yapp
* fixed Windows subprocess quoting and empty arguments - Cliff Yapp
* fixed mged X embedded framebuffer display manager crash - Cliff Yapp
* fixed Windows drive-letter path handling - Cliff Yapp
* fixed MGED X embedded framebuffer display manager crash - Cliff Yapp
* added annotate command for managing annotation objects - Cliff Yapp
* added repair command for supported invalid primitives - Cliff Yapp
* changed default new-region material code from 1 to 0 - Keith Bowman
@@ -133,34 +107,26 @@ dependencies also receive substantial updates.
* added option validation to image & framebuffer tools - Sean Morrison
* added contributor, API, command, & raytracing guides - Sean Morrison
* added and updated command and library manual pages - Sean Morrison
* added pnts write -f xyz export option - Chris McGregor
* fixed mged ARB5 point editing - Cliff Yapp
* fixed mged gqa and rtcheck stale overlap plots - Cliff Yapp
* fixed procedural tree generator crashes - Sean Morrison, Cliff Yapp
* added gaia Earth models with day/dusk/night textures - Sean Morrison
* fixed fbcolor ramps & Windows input - Cliff Yapp, Sean Morrison
* added parashot gravity trajectory path generator - Sean Morrison
* added metaball pnt scaling (via metaball_move_pnt) - Sean Morrison
* added metaball point scaling (via metaball_move_pnt) - Sean Morrison
* all raytracing apps now report object prep failures - Sean Morrison
* improved fast4-g robustness and error reporting - Cliff Yapp
* improved robustness of g-vrml plate mode handling - Cliff Yapp
* added support for tick drawing on mged model axis - Cliff Yapp
* fixed MGED ARB5 point, pipe, and sketch editing - Cliff Yapp
* added pnts write -f xyz export option - Chris McGregor
* added support for tick drawing on MGED model axis - Cliff Yapp
* added naca456 left and paired wing generation - Cliff Yapp
* added patch-g -j option, specify object thicknesses - Sean Morrison
* corrected bwstat median and input error handling - Sean Morrison
* fixed fbcolor color ramp bug drawing the last color - Sean Morrison
* fixed gist -Q quick preview option - Sean Morrison
* rt preserves eye_pt setting in command scripts - Sean Morrison
* removed trailing whitespace from nirt output - Sean Morrison
* rt -l8 heat graphs now measure CPU time - Sean Morrison
* documented gqa centroid & moments of inertia options - Sean Morrison
* pixdiff now calculates pixel differences on bw files - Sean Morrison
* fixed bwcrop single-axis crops & pixembed edge fill - Sean Morrison
* fixed bwcrop single-axis crops and pixembed edge fill - Sean Morrison
* fixed isize in non-mm databases - Josh Baker
* fixed metaball adjust clearing points on errors - Sean Morrison
* fixed benchmark+pixcmp correctness validation bug - Sean Morrison
* fixed mged gqa option and value parsing - Sean Morrison
* improved gist hierarchy overflow rendering - Chris McGregor
* fixed rtxray -o grayscale/BW output - Sean Morrison
* fbhelp writes help to stdout and rest to stderr - Sean Morrison
* FB now supports /dev/stdout and /dev/stderr devices - Sean Morrison
* fixed mged rt -C + -o background color to file bug - Sean Morrison
@@ -169,7 +135,7 @@ dependencies also receive substantial updates.
* added rtsil -o support for bw output - Sean Morrison
* added cutting plane animation generation to rtwizard - Cliff Yapp
* fixed pixdiff bug on Windows - Sean Morrison
* fixed mged startup window placement on Windows - Chris McGregor
* fixed MGED startup window placement on Windows - Chris McGregor
* fixed pixborder utility right-side edge bug - Sean Morrison
* fixed 'wavelet' image processing tool on Windows - Sean Morrison
* quieted mged killtree spurious lookup failure output - Sean Morrison
@@ -180,16 +146,14 @@ dependencies also receive substantial updates.
* new doc guide, a visual overview of BRL-CAD objects - Sean Morrison
* improved triangle quality produced by bot remesh - Cliff Yapp
* updated numerous manpage command references - Josh Baker
* fixed submodel paths relative to parent databases - Sean Morrison
* improved performance making huge combinations - Sean Morrison
* added PNTS get, adjust, form, & g2asc/asc2g support - Chris McGregor
* fixed ANNOT get, adjust, & g2asc/asc2g support - Chris McGregor
* added make -t primitive type listing - Chris McGregor
* added gcv import conversion support for vrml/wrl 1.0 - Sean Morrison
* fixed gcv appending to existing geometry databases - Sean Morrison
* added CSS names, hex, HSL/HSV to libbu color parsing - Sean Morrison
* improved OpenNURBS B-Rep import and adjustment safety - Cliff Yapp
* improved Debian application menus/MIME associations - Jordi Sayol
* updated Tcl/Tk dependency to v8.6.18 using bundled Itcl - Cliff Yapp
* improved Debian application menus and MIME associations - Jordi Sayol
* updated Clipper2 dependency to v1.5.4 - Cliff Yapp
* updated Eigen dependency to v5.0.1 - Cliff Yapp
* updated GDAL dependency to v3.13.3 - Cliff Yapp
@@ -201,6 +165,7 @@ dependencies also receive substantial updates.
* updated OpenNURBS dependency to v8.34.26223.11001 - Cliff Yapp
* updated PROJ dependency to v9.8.1 - Cliff Yapp
* updated PoissonRecon dependency to v18.75 - Cliff Yapp
* updated Tcl/Tk dependency to v8.6.18, using bundled Itcl - Cliff Yapp
* updated libjpeg-turbo dependency to v3.2.0 - Cliff Yapp
* updated libosmesa dependency to SHA1 bfa90de - Cliff Yapp
* updated libpng dependency to v1.6.58 - Cliff Yapp
@@ -309,7 +274,7 @@ and extensively improving existing docs.
* added metadata-aware image diff & nirt analysis - Cliff Yapp
* added basic PNTS point-cloud ray tracing - Sean Morrison
* improved nirt behavior in Windows bash consoles - Cliff Yapp
* added g2asc/asc2g support for DSP and EBM - Sean Morrison
* added g2asc/asc2g support for PNTS, DSP, and EBM - Sean Morrison
* updated gct mesh decimation dependency to mmesh - Cliff Yapp
* added procedural wing, propeller & tree generators - Cliff Yapp
* added ISO tire dimensions & named tread presets - Cliff Yapp
@@ -581,7 +546,6 @@ for more information.
----------------------------------------------------------------------
--- 2023-11-06 Release 7.38.0 ---
----------------------------------------------------------------------
This major release of BRL-CAD introduces significant improvements to
the robustness of the facetize command by leveraging the Manifold
library for boolean evaluation of meshes. Facetization is an operation
@@ -620,7 +584,6 @@ processing high level assemblies in BRL-CAD's example geometry files:
----------------------------------------------------------------------
--- 2023-07-26 Release 7.36.0 ---
----------------------------------------------------------------------
This major release of BRL-CAD introduces significant updates to
geometry conversion support. The update includes modernization for
NURBS importing and interaction, BoT manipulation, and incorporates
+1 -1
View File
@@ -1,5 +1,5 @@
BRL-CAD
Release 7.46.0
Release 7.44.2
http://brlcad.org/
BRL-CAD is a powerful cross-platform open source combinatorial
+9
View File
@@ -2668,6 +2668,15 @@ DOCUMENTATION
Comparison of how BRL-CAD overlaps feature-wise with various
major commercial CAD systems.
* Solid Geometry Representation Comparisons
Describe the implications, tradeoffs, and conversion issues
involved when converting between different geometry
representations. Includes describing implicit geometry,
explicit polygonal boundary representations, explicit spline
surface representations, volumetric models, wireframes,
boolean operations, feature edit operations, and parametric
modeling.
* BRL-CAD Open Source
An overview of how BRL-CAD is organized as an open source
project and community describing the developer meritocracy,
-62
View File
@@ -20,7 +20,6 @@ set(
procedural_geometry.adoc
projection_shader.adoc
renderer_showcase.adoc
solid_geometry_comparison.adoc
taxonomy.adoc
tire.adoc
)
@@ -228,17 +227,6 @@ set(
images/renderer_gallery_rthide.png
images/renderer_gallery_rtdepth.png
images/renderer_gallery_rtxray.png
images/solid_rep_csg.png
images/solid_rep_brep_boolean.png
images/solid_rep_brep_evaluated.png
images/solid_rep_polygonal_boolean.png
images/solid_rep_nmg.png
images/solid_rep_bot.png
images/solid_rep_revolve.png
images/solid_rep_voxel_cells.png
images/solid_rep_volume.png
images/solid_rep_point_cloud.png
images/solid_rep_wireframe.png
images/adrt_castle_path.png
images/adrt_castle_rt.png
images/adrt_castle_rt_ao.png
@@ -421,54 +409,6 @@ if(
set_target_properties(renderer-gallery-snapshot PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD 1)
endif()
# Solid geometry comparison -- opt-in regeneration of committed snapshots.
#
# The article and solid_rep_*.png images are normal committed documentation.
# This target rebuilds the common pawn, derives each representation with the
# built tools, and refreshes the images for review.
option(
BRLCAD_GENERATE_SOLID_REPRESENTATION_COMPARISON
"Regenerate the solid geometry representation comparison snapshots"
OFF
)
if(
BRLCAD_GENERATE_SOLID_REPRESENTATION_COMPARISON
AND TARGET mged
AND TARGET rt
AND TARGET g-voxel
AND TARGET asc2pix
AND TARGET fbclear
AND TARGET plot3-fb
AND TARGET fb-png
)
add_custom_target(
solid-representation-comparison-snapshot
COMMAND
${CMAKE_COMMAND}
-DMGED=$<TARGET_FILE:mged>
-DRT=$<TARGET_FILE:rt>
-DGVOXEL=$<TARGET_FILE:g-voxel>
-DASC2PIX=$<TARGET_FILE:asc2pix>
-DFBCLEAR=$<TARGET_FILE:fbclear>
-DPLOT3FB=$<TARGET_FILE:plot3-fb>
-DFBPNG=$<TARGET_FILE:fb-png>
-DMODEL_SCRIPT=${CMAKE_CURRENT_SOURCE_DIR}/solid_geometry_comparison/create_pawn.tcl
-DIMGDIR=${CMAKE_CURRENT_SOURCE_DIR}/images
-DWORKDIR=${CMAKE_CURRENT_BINARY_DIR}/solid_representation_comparison_work
-DSIZE=512
-P ${CMAKE_CURRENT_SOURCE_DIR}/solid_geometry_comparison/generate_comparison.cmake
DEPENDS mged rt g-voxel asc2pix fbclear plot3-fb fb-png
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Regenerating solid geometry representation comparison snapshots"
VERBATIM
USES_TERMINAL
)
set_target_properties(
solid-representation-comparison-snapshot
PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD 1
)
endif()
# ADRT path-tracing gallery -- opt-in regeneration of the committed snapshot.
#
# Like the galleries above, the adrt_pathtrace.adoc article is hand-written and
@@ -524,8 +464,6 @@ cmakefiles(
gallery/generate_gallery.cmake
renderer_gallery/renderer_gallery_manifest.cmake
renderer_gallery/generate_renderer_gallery.cmake
solid_geometry_comparison/create_pawn.tcl
solid_geometry_comparison/generate_comparison.cmake
adrt_gallery/generate_adrt_gallery.cmake
gallery/inputs/pipe.stdin
gallery/inputs/wire.stdin
Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

@@ -1,294 +0,0 @@
= Solid Geometry Representation Comparisons
:doctype: article
:toc:
:toclevels: 2
The same shape can be stored in very different ways. This comparison uses a
purpose-built chess pawn to show which information BRL-CAD retains, evaluates,
or samples when moving among its principal geometry representations. It is a
guide to semantics and conversion choices, not a claim that one representation
is universally best.
== Common model and method
The reference pawn is a region containing seven overlapping ellipsoids. Their
union is non-trivial enough to exercise curved surfaces, overlapping interiors,
and several component boundaries while remaining reliable across the
conversions shown here. The sketch-and-revolve version independently follows
the same nominal profile; it is not an exact conversion of the seven-piece CSG
model.
Every shaded image uses the same orthographic view, 512x512 image size,
material, and single-threaded renderer. The wireframe uses the same view and
image size. The faceting and sampling settings are intentionally coarse enough
to remain visible. A similar silhouette therefore does not mean that two
database objects have the same structure or numerical boundary.
NOTE: This article and its images are a committed snapshot. Developers can
regenerate the figures from built BRL-CAD tools by configuring with
`-DBRLCAD_GENERATE_SOLID_REPRESENTATION_COMPARISON=ON` and building the
`solid-representation-comparison-snapshot` target.
== At a glance
[cols="2,2,1,2,4",options="header"]
|===
|Form
|BRL-CAD storage
|Solid?
|Boolean state
|Editing and conversion consequences
|Analytic CSG
|Seven `ell` leaves in a combination
|Yes
|Retained
|Compact primitive parameters and tree edits preserve construction intent.
|B-rep tree
|Closed `brep` leaves in a combination
|Yes
|Retained
|NURBS surfaces and trims replace analytic leaves, but the assembly tree remains.
|Evaluated B-rep
|One closed `brep`
|Yes
|Evaluated
|Direct face, edge, trim, and control-point editing is possible; original
features and hierarchy are gone.
|Polygonal tree
|Solid-mode `bot` leaves in a combination
|Yes
|Retained
|Leaf tessellation is approximate, but components and their union tree remain
independently replaceable.
|Evaluated NMG
|One `nmg`
|Yes
|Evaluated
|Stores explicit, topology-rich polygonal boundaries and can record
non-manifold relationships.
|Evaluated triangle mesh
|One solid-mode `bot`
|Yes
|Evaluated
|Portable triangle connectivity, but curved geometry and construction history
have been sampled away.
|Sketch and revolve
|One `sketch` referenced by one `revolve`
|Yes
|Not needed here
|The profile, axis, and sweep angle are compact, meaningful parameters.
|Voxel cells
|A region containing many `arb8` boxes
|Yes (sampled)
|Cell union retained
|Individual cells are ordinary CSG geometry; size grows rapidly as cells
shrink.
|Sampled volume
|A file-backed `vol` scalar grid
|Yes (thresholded)
|None
|Compact regular-grid occupancy; resolution and threshold determine the boundary.
|Point cloud
|One `pnts` object with positions and normals
|No pawn interior
|None
|Useful as measured or sampled evidence, but it has no inherent connected
boundary or inside/outside rule.
|Wireframe
|Derived line display of the CSG object
|No
|Uses source tree
|A view-dependent drawing aid, not an independent solid representation.
|===
"Solid" in this table means that the stored object supplies usable
inside/outside semantics for the pawn. An arbitrary B-rep or mesh is not
automatically a solid: its boundary must be closed and consistently oriented.
The point size used to render `pnts` makes each sample a small sphere, but those
spheres do not reconstruct the pawn interior. A wireframe likewise does not
become a solid merely because its curves appear closed in one view.
== Implicit and parametric forms
[cols="1,1"]
[%noheader]
|===
|image:images/solid_rep_csg.png[Analytic CSG pawn,512]
|image:images/solid_rep_revolve.png[Sketch and revolve pawn,512]
|*Analytic CSG.* Native primitives retain their equations and dimensions; the
region evaluates their union during ray tracing.
|*Sketch plus revolve.* A closed line-segment profile is swept through 360
degrees. The stepped profile is intentional and remains editable in two
dimensions.
|===
Analytic CSG is an implicit representation: intersections with ideal primitive
surfaces are computed as needed rather than read from a stored boundary mesh.
It is usually the most compact form here and makes edits such as changing the
head radius or stem proportions direct. Its Boolean hierarchy also records why the
shape was assembled.
`sketch` plus `revolve` is another procedural, parameterized description. It
works especially well for an axisymmetric part, although a sketch with only
line segments produces conical and cylindrical bands rather than the pawn's
original ellipsoidal surfaces. BRL-CAD supports primitive parameters, placement
matrices, sketches, and sweeps; that should not be confused with a general
constraint solver or an associative feature-history system.
== Spline boundary representations
[cols="1,1"]
[%noheader]
|===
|image:images/solid_rep_brep_boolean.png[B-rep leaves with Boolean tree,512]
|image:images/solid_rep_brep_evaluated.png[Single evaluated B-rep,512]
|*B-rep with Booleans.* Each analytic leaf becomes a closed B-rep whose
boundaries are trimmed NURBS surfaces. The original union tree is retained.
|*B-rep without Booleans.* Boolean evaluation produces one explicit boundary;
operand identities and the construction tree no longer exist as editable
features.
|===
A B-rep stores faces, trims, edges, vertices, and their topology explicitly.
Rational NURBS can represent the source quadrics exactly as surfaces, but that
does not make every CSG-to-B-rep conversion exact: intersections, trimming,
topology classification, and repair use numerical tolerances. Keeping a tree
of B-rep leaves isolates conversion to each primitive and retains high-level
editing. Evaluating the tree yields a more self-contained boundary for
exchange and face-level work, at the cost of that history. This snapshot's
evaluated result passes both `brep ... valid` and `brep ... solid`; conversion
results should be checked rather than assumed to be closed.
== Polygonal boundaries
[cols="1,1,1"]
[%noheader]
|===
|image:images/solid_rep_polygonal_boolean.png[BoT leaves with Boolean tree,512]
|image:images/solid_rep_nmg.png[Evaluated NMG pawn,512]
|image:images/solid_rep_bot.png[Evaluated BoT pawn,512]
|*Polygonal with Booleans.* Each leaf is independently tessellated to a BoT,
then placed in the original union tree.
|*Evaluated NMG.* One non-manifold geometry object records the evaluated
polygonal boundary and its richer topology.
|*Evaluated triangle mesh.* One solid, counter-clockwise BoT stores 982
vertices and 1,960 triangular faces in this snapshot.
|===
All three images expose the same coarse tessellation. Their similar appearance
hides an important distinction: the first still has seven editable operands,
whereas the NMG and single BoT are evaluated results. NMG can represent
polygonal faces and non-manifold adjacency; BoT faces are triangles only.
Neither recreates analytic curvature when converted back. Finer tessellation
reduces visible error but increases storage and processing cost.
== Sampled forms
[cols="1,1,1"]
[%noheader]
|===
|image:images/solid_rep_voxel_cells.png[Pawn represented by CSG voxel cells,512]
|image:images/solid_rep_volume.png[Pawn represented by a VOL grid,512]
|image:images/solid_rep_point_cloud.png[Pawn represented by surface points,512]
|*Explicit voxel cells.* `voxelize` tests 3 mm cells and creates a CSG union of
699 boxes for cells exceeding the occupancy threshold.
|*Sampled volume.* `g-voxel` samples a 2 mm grid; a file-backed `vol` interprets
the resulting 17x17x30 byte array through an occupancy window.
|*Point cloud.* `pnts gen` samples the analytic surface on a 2 mm grid. Small
rendered spheres make the otherwise zero-area sample locations visible.
|===
The two voxel images are deliberately separate. The `voxelize` command emits
ordinary box primitives and a combination, while `vol` reads scalar samples on
a regular grid and derives a threshold boundary at ray-trace time. Both are
volumetric approximations whose accuracy, memory, and feature size depend on
cell spacing. A point cloud samples only the surface and has no connectivity;
surface reconstruction requires additional assumptions and may invent or omit
geometry.
== Wireframe display
image::images/solid_rep_wireframe.png[Wireframe display of the analytic CSG pawn,512]
This wireframe is a view-plane plot of MGED's unevaluated display of the
analytic CSG pawn; hidden lines are not removed. Wireframes are useful for
selection, orientation, and seeing component curves, but they are ambiguous:
curves alone do not say which side is material, which loops bound faces, or
which surfaces enclose volume. Keep the solid that generated the display
rather than treating the drawing as an equivalent conversion target.
== Conversion and editing consequences
A conversion command is not an equivalence guarantee. Before replacing source
data, check at least these effects:
* *Tolerance and resolution:* B-rep Boolean evaluation uses intersection and
topology tolerances; tessellation uses chord and angular tolerances; voxels
and points use sample spacing and thresholds. Each can erase a feature
smaller than its controlling tolerance.
* *Construction intent:* evaluating a Boolean tree discards operand identity,
primitive parameters, and ordering. Converting leaves while retaining the
tree keeps more of that intent.
* *Topology:* a visually plausible B-rep or mesh may contain gaps, duplicate
faces, self-intersections, or inconsistent orientation. Validate closure
and ray behavior, not only a shaded image.
* *Attributes:* collapsing a hierarchy may change where region identifiers,
materials, colors, and other attributes reside. Verify them separately
from geometry.
* *Round trips:* CSG to mesh to B-rep does not recover the original equations;
points to a surface requires reconstruction; resampling a volume compounds
discretization. Retain the highest-level trustworthy source.
For parameter changes and repeated design work, prefer analytic primitives,
sketch sweeps, and preserved combination trees. Prefer a validated B-rep when
trimmed-surface topology or exchange requires it. Use NMG for topology-rich
polygonal processing and BoT for triangle-oriented interchange or algorithms.
Use voxels for occupancy operations and point clouds for measured or sampled
data, not as silent substitutes for a watertight solid.
BRL-CAD also supports specialized forms such as DSP height fields, EBM
extrusions, ARS surfaces, metaballs, and legacy `poly` and `bspline` objects.
They are not shown as interchangeable pawn encodings: DSP and EBM are
domain-specific, metaballs change the modeling method, and BoT and B-rep are the
preferred general successors to the legacy polygon and spline forms.
== Reproducing the conversions
The snapshot generator creates the database and runs these principal MGED
operations (names shortened here only where noted):
[source]
----
brep comparison.csg.r brep --no-evaluation
brep comparison.csg.r brep comparison.brep_evaluated.s
facetize -n comparison.csg.r comparison.nmg.s
facetize --methods NMG comparison.csg.r comparison.bot.s
facetize --methods NMG base.s base.bot # repeated for all seven leaves
voxelize -s "3 3 3" -d 4 -t 0.45 comparison.voxel_cells.r comparison.csg.r
pnts gen -t 2 --surface --grid comparison.csg.r comparison.samples
pnts write comparison.samples comparison.xyz
pnts read -f xyzijk --size 0.45 comparison.xyz comparison.point_cloud.s
----
The generator also runs `g-voxel` and expands its sparse occupied-cell report
into the x-fastest byte array used by `vol`. It then renders every shaded
object with `rt -B -M -P1` and the saved view; MGED's `plot -2d`, `plot3-fb`,
and `fb-png` produce the wireframe image. See
`solid_geometry_comparison/generate_comparison.cmake` and
`solid_geometry_comparison/create_pawn.tcl` for the complete reproducible
inputs.
@@ -1,24 +0,0 @@
# Create the shared pawn used by the solid-representation comparison.
title {Solid geometry representation comparison pawn}
units mm
# Deliberate overlaps keep the pawn connected while exercising curved-surface
# intersections during Boolean evaluation.
db put base.s ell V {0 0 4.5} A {17 0 0} B {0 17 0} C {0 0 4.5}
db put base_bead.s ell V {0 0 9.5} A {14 0 0} B {0 14 0} C {0 0 5}
db put body.s ell V {0 0 18} A {12 0 0} B {0 12 0} C {0 0 9}
db put stem.s ell V {0 0 29} A {7 0 0} B {0 7 0} C {0 0 13}
db put collar.s ell V {0 0 39} A {9 0 0} B {0 9 0} C {0 0 3.5}
db put neck.s ell V {0 0 43} A {6.5 0 0} B {0 6.5 0} C {0 0 5}
db put head.s ell V {0 0 50} A {9 0 0} B {0 9 0} C {0 0 9}
db put comparison.csg.r comb region yes id 1000 los 100 GIFTmater 1 rgb {235 190 90} shader {plastic} tree {u {u {u {l base.s} {l base_bead.s}} {u {l body.s} {l stem.s}}} {u {u {l collar.s} {l neck.s}} {l head.s}}}
# The revolve uses a deliberately independent outline. Its single closed
# sketch approximates the same pawn silhouette without copying the CSG tree.
db put comparison.profile sketch V {0 0 0} A {1 0 0} B {0 0 1} VL {{0 0} {17 0} {17 2} {16.3 4} {15 6} {14 8} {15.4 7} {16 9} {15.4 11} {13.5 12.5} {11.2 14} {12 18} {11 21} {9.5 23} {8 26} {7.5 32} {6.5 36} {7.5 37} {9 39} {7.5 41} {6.5 42} {6.5 43} {7.5 44} {8.5 46} {9 50} {8.5 54} {6.7 56.5} {0 59}} SL {{line S 0 E 1} {line S 1 E 2} {line S 2 E 3} {line S 3 E 4} {line S 4 E 5} {line S 5 E 6} {line S 6 E 7} {line S 7 E 8} {line S 8 E 9} {line S 9 E 10} {line S 10 E 11} {line S 11 E 12} {line S 12 E 13} {line S 13 E 14} {line S 14 E 15} {line S 15 E 16} {line S 16 E 17} {line S 17 E 18} {line S 18 E 19} {line S 19 E 20} {line S 20 E 21} {line S 21 E 22} {line S 22 E 23} {line S 23 E 24} {line S 24 E 25} {line S 25 E 26} {line S 26 E 27} {line S 27 E 0}}
db put comparison.revolve.s revolve V {0 0 0} axis {0 0 1} R {1 0 0} ang 6.283185307179586 sk_name comparison.profile
db put comparison.revolve.r comb region yes id 1001 los 100 GIFTmater 1 rgb {235 190 90} shader {plastic} tree {l comparison.revolve.s}
q
@@ -1,372 +0,0 @@
# Regenerate the solid geometry representation comparison snapshots.
#
# The article is hand-written. This script builds its common pawn model,
# derives each representation using BRL-CAD tools, and replaces the committed
# images. All databases and sidecar data remain in WORKDIR.
cmake_minimum_required(VERSION 3.20)
foreach(v MGED RT GVOXEL ASC2PIX FBCLEAR PLOT3FB FBPNG
MODEL_SCRIPT IMGDIR WORKDIR)
if(NOT DEFINED ${v})
message(FATAL_ERROR "generate_comparison: -D${v}=... is required")
endif()
endforeach()
if(NOT DEFINED SIZE)
set(SIZE 512)
endif()
set(RENDER_TIMEOUT 1800)
set(PAWN_DB "${WORKDIR}/solid_representation_pawn.g")
set(VIEW_SCRIPT "${WORKDIR}/pawn.view")
set(MGED_SCRIPT "${WORKDIR}/assemble_variants.tcl")
set(VOXELIZE_SCRIPT "${WORKDIR}/voxelize.tcl")
set(VOXEL_LIST "${WORKDIR}/voxels1.txt")
set(VOLUME_ASCII "${WORKDIR}/comparison_volume.asc")
set(VOLUME_FILE "${WORKDIR}/comparison.vol")
file(REMOVE_RECURSE "${WORKDIR}")
file(MAKE_DIRECTORY "${WORKDIR}")
file(MAKE_DIRECTORY "${IMGDIR}")
function(run_process label)
execute_process(
COMMAND ${ARGN}
WORKING_DIRECTORY "${WORKDIR}"
TIMEOUT ${RENDER_TIMEOUT}
RESULT_VARIABLE process_result
OUTPUT_VARIABLE process_stdout
ERROR_VARIABLE process_stderr
)
if(NOT process_result EQUAL 0)
message(
FATAL_ERROR
"${label} failed (exit ${process_result})\n${process_stdout}${process_stderr}"
)
endif()
message(STATUS "${label}")
endfunction()
function(require_brep_property object property expected_output)
execute_process(
COMMAND "${MGED}" --no-rc -c "${PAWN_DB}" brep "${object}" "${property}"
WORKING_DIRECTORY "${WORKDIR}"
TIMEOUT ${RENDER_TIMEOUT}
RESULT_VARIABLE property_result
OUTPUT_VARIABLE property_stdout
ERROR_VARIABLE property_stderr
)
set(property_output "${property_stdout}${property_stderr}")
if(NOT property_result EQUAL 0 OR NOT property_output MATCHES "${expected_output}")
message(
FATAL_ERROR
"B-rep ${object} is not ${property}\n${property_output}"
)
endif()
message(STATUS "Validated B-rep ${object}: ${property}")
endfunction()
execute_process(
COMMAND "${MGED}" --no-rc -c "${PAWN_DB}"
WORKING_DIRECTORY "${WORKDIR}"
TIMEOUT ${RENDER_TIMEOUT}
INPUT_FILE "${MODEL_SCRIPT}"
RESULT_VARIABLE create_result
OUTPUT_VARIABLE create_stdout
ERROR_VARIABLE create_stderr
)
if(NOT create_result EQUAL 0 OR NOT EXISTS "${PAWN_DB}")
message(
FATAL_ERROR
"Creating the comparison pawn failed (exit ${create_result})\n${create_stdout}${create_stderr}"
)
endif()
# Preserve one Boolean hierarchy as B-rep leaves, and evaluate another into a
# single B-rep. The default suffix is intentional: supplying an explicit
# suffix changes parsing in older MGED versions.
set(PAWN_LEAVES base base_bead body stem collar neck head)
run_process(
"Created Boolean tree of B-rep leaves"
"${MGED}" --no-rc -c "${PAWN_DB}" brep comparison.csg.r brep --no-evaluation
)
foreach(leaf IN LISTS PAWN_LEAVES)
require_brep_property("${leaf}.s.brep" solid "brep is solid")
endforeach()
run_process(
"Created evaluated B-rep"
"${MGED}" --no-rc -c "${PAWN_DB}" brep comparison.csg.r brep comparison.brep_evaluated.s
)
require_brep_property(comparison.brep_evaluated.s valid "brep is valid")
require_brep_property(comparison.brep_evaluated.s solid "brep is solid")
# Generate both the topology-rich NMG form and the triangle-only BoT form.
run_process(
"Created evaluated NMG"
"${MGED}" --no-rc -c "${PAWN_DB}" facetize -n comparison.csg.r comparison.nmg.s
)
run_process(
"Created evaluated BoT"
"${MGED}" --no-rc -c "${PAWN_DB}" facetize --methods NMG comparison.csg.r comparison.bot.s
)
# Tessellating leaves independently preserves the editable Boolean hierarchy.
foreach(leaf IN LISTS PAWN_LEAVES)
run_process(
"Tessellated ${leaf}.s"
"${MGED}" --no-rc -c "${PAWN_DB}" facetize --methods NMG "${leaf}.s" "${leaf}.bot"
)
endforeach()
file(WRITE "${VOXELIZE_SCRIPT}" "voxelize -s {3 3 3} -d 4 -t 0.45 comparison.voxel_cells.r comparison.csg.r\nq\n")
execute_process(
COMMAND "${MGED}" --no-rc -c "${PAWN_DB}"
WORKING_DIRECTORY "${WORKDIR}"
TIMEOUT ${RENDER_TIMEOUT}
INPUT_FILE "${VOXELIZE_SCRIPT}"
RESULT_VARIABLE voxelize_result
OUTPUT_VARIABLE voxelize_stdout
ERROR_VARIABLE voxelize_stderr
)
if(NOT voxelize_result EQUAL 0)
message(
FATAL_ERROR
"Creating explicit voxel cells failed (exit ${voxelize_result})\n${voxelize_stdout}${voxelize_stderr}"
)
endif()
message(STATUS "Created explicit voxel cells")
# PNTS stores point size at import time. The generator first writes all
# sampled fields (xyzijk), then reads them back with a visible point diameter.
run_process(
"Sampled pawn surface"
"${MGED}" --no-rc -c "${PAWN_DB}" pnts gen -t 2 --surface --grid
comparison.csg.r comparison.samples
)
run_process(
"Exported pawn point samples"
"${MGED}" --no-rc -c "${PAWN_DB}" pnts write comparison.samples comparison.xyz
)
run_process(
"Created visible point cloud"
"${MGED}" --no-rc -c "${PAWN_DB}" pnts read -f xyzijk --size 0.45
comparison.xyz comparison.point_cloud.s
)
# g-voxel reports occupied cells. Expand that sparse report into the regular,
# x-fastest byte array required by VOL. The pawn bounds are [-17,17] in X/Y
# and [0,60] in Z; 2 mm cells therefore form a 17 x 17 x 30 grid.
file(REMOVE "${VOXEL_LIST}")
run_process(
"Sampled VOL grid"
"${GVOXEL}" -s "2 2 2" -d 4 -t 0.5 "${PAWN_DB}" comparison.csg.r
)
if(NOT EXISTS "${VOXEL_LIST}")
message(FATAL_ERROR "g-voxel did not create ${VOXEL_LIST}")
endif()
file(STRINGS "${VOXEL_LIST}" voxel_lines)
list(LENGTH voxel_lines occupied_voxels)
if(occupied_voxels EQUAL 0)
message(FATAL_ERROR "g-voxel reported no occupied cells")
endif()
foreach(line IN LISTS voxel_lines)
string(
REGEX MATCH
"^\\((-?[0-9]+)\\.0+, (-?[0-9]+)\\.0+, (-?[0-9]+)\\.0+\\)[ \t]+[^ \t]+[ \t]+[0-9.]+$"
parsed "${line}"
)
if(NOT parsed)
message(FATAL_ERROR "Cannot parse g-voxel output: ${line}")
endif()
set(x_coord "${CMAKE_MATCH_1}")
set(y_coord "${CMAKE_MATCH_2}")
set(z_coord "${CMAKE_MATCH_3}")
math(EXPR x_index "(${x_coord} + 16) / 2")
math(EXPR y_index "(${y_coord} + 16) / 2")
math(EXPR z_index "(${z_coord} - 1) / 2")
if(x_index LESS 0 OR x_index GREATER 16 OR
y_index LESS 0 OR y_index GREATER 16 OR
z_index LESS 0 OR z_index GREATER 29)
message(FATAL_ERROR "g-voxel coordinate outside the expected pawn grid: ${line}")
endif()
set("voxel_${x_index}_${y_index}_${z_index}" 255)
endforeach()
set(volume_text "")
foreach(z_index RANGE 0 29)
foreach(y_index RANGE 0 16)
foreach(x_index RANGE 0 16)
if(DEFINED voxel_${x_index}_${y_index}_${z_index})
set(sample ff)
else()
set(sample 00)
endif()
string(APPEND volume_text "${sample}\n")
endforeach()
endforeach()
endforeach()
file(WRITE "${VOLUME_ASCII}" "${volume_text}")
execute_process(
COMMAND "${ASC2PIX}"
WORKING_DIRECTORY "${WORKDIR}"
TIMEOUT ${RENDER_TIMEOUT}
INPUT_FILE "${VOLUME_ASCII}"
OUTPUT_FILE "${VOLUME_FILE}"
RESULT_VARIABLE asc2pix_result
ERROR_VARIABLE asc2pix_error
)
if(NOT asc2pix_result EQUAL 0)
message(FATAL_ERROR "asc2pix failed (exit ${asc2pix_result})\n${asc2pix_error}")
endif()
file(SIZE "${VOLUME_FILE}" volume_size)
if(NOT volume_size EQUAL 8670)
message(FATAL_ERROR "VOL sidecar is ${volume_size} bytes; expected 8670")
endif()
message(STATUS "Encoded ${occupied_voxels} occupied VOL cells")
# Wrap single primitives in regions so every shaded comparison uses the same
# material. The polygonal tree repeats the original CSG union hierarchy with
# BoT leaves. VOL references a sidecar basename resolved beside the database.
file(WRITE "${MGED_SCRIPT}" [=[
db put comparison.brep_evaluated.r comb region yes id 1010 los 100 GIFTmater 1 rgb {235 190 90} shader {plastic} tree {l comparison.brep_evaluated.s}
db put comparison.nmg.r comb region yes id 1020 los 100 GIFTmater 1 rgb {235 190 90} shader {plastic} tree {l comparison.nmg.s}
db put comparison.bot.r comb region yes id 1030 los 100 GIFTmater 1 rgb {235 190 90} shader {plastic} tree {l comparison.bot.s}
db put comparison.polygonal_boolean.r comb region yes id 1040 los 100 GIFTmater 1 rgb {235 190 90} shader {plastic} tree {u {u {u {l base.bot} {l base_bead.bot}} {u {l body.bot} {l stem.bot}}} {u {u {l collar.bot} {l neck.bot}} {l head.bot}}}
attr set comparison.voxel_cells.r region R region_id 1050 material_id 1 los 100 shader plastic color 235/190/90
db put comparison.point_cloud.r comb region yes id 1060 los 100 GIFTmater 1 rgb {235 190 90} shader {plastic} tree {l comparison.point_cloud.s}
db put comparison.volume.s vol file {comparison.vol} name {comparison.vol} src f w 17 n 17 d 30 lo 1 hi 255 size {2 2 2} mat {1 0 0 -17 0 1 0 -17 0 0 1 0 0 0 0 1}
db put comparison.volume.r comb region yes id 1070 los 100 GIFTmater 1 rgb {235 190 90} shader {plastic} tree {l comparison.volume.s}
q
]=])
execute_process(
COMMAND "${MGED}" --no-rc -c "${PAWN_DB}"
WORKING_DIRECTORY "${WORKDIR}"
TIMEOUT ${RENDER_TIMEOUT}
INPUT_FILE "${MGED_SCRIPT}"
RESULT_VARIABLE assemble_result
OUTPUT_VARIABLE assemble_stdout
ERROR_VARIABLE assemble_stderr
)
if(NOT assemble_result EQUAL 0)
message(
FATAL_ERROR
"Assembling comparison regions failed (exit ${assemble_result})\n${assemble_stdout}${assemble_stderr}"
)
endif()
file(WRITE "${VIEW_SCRIPT}" "viewsize 8.000000000000000e+01;\n")
file(APPEND "${VIEW_SCRIPT}" "orientation 2.480970000000000e-01 4.765910000000000e-01 7.480970000000000e-01 3.894350000000000e-01;\n")
file(APPEND "${VIEW_SCRIPT}" "eye_pt 4.199070000000000e+01 2.940060000000000e+01 5.329140000000000e+01;\n")
file(APPEND "${VIEW_SCRIPT}" "start 0; clean;\n")
file(APPEND "${VIEW_SCRIPT}" "end;\n")
function(copy_snapshot local_image)
if(NOT EXISTS "${local_image}")
message(FATAL_ERROR "Expected image was not created: ${local_image}")
endif()
file(SIZE "${local_image}" image_size)
if(image_size EQUAL 0)
message(FATAL_ERROR "Rendered image is empty: ${local_image}")
endif()
file(COPY "${local_image}" DESTINATION "${IMGDIR}")
get_filename_component(image_name "${local_image}" NAME)
file(
CHMOD "${IMGDIR}/${image_name}"
PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ
)
endfunction()
function(render_snapshot name object)
set(filename "solid_rep_${name}.png")
set(local_image "${WORKDIR}/${filename}")
file(REMOVE "${local_image}")
execute_process(
COMMAND "${RT}" -B -M -W "-s${SIZE}" -P1 -o "${filename}" "${PAWN_DB}" "${object}"
WORKING_DIRECTORY "${WORKDIR}"
TIMEOUT ${RENDER_TIMEOUT}
INPUT_FILE "${VIEW_SCRIPT}"
RESULT_VARIABLE render_result
OUTPUT_VARIABLE render_stdout
ERROR_VARIABLE render_stderr
)
if(NOT render_result EQUAL 0)
message(
FATAL_ERROR
"Rendering ${name} failed (exit ${render_result})\n${render_stdout}${render_stderr}"
)
endif()
copy_snapshot("${local_image}")
message(STATUS "Rendered ${filename}")
endfunction()
render_snapshot(csg comparison.csg.r)
render_snapshot(brep_boolean comparison.csg.r.brep)
render_snapshot(brep_evaluated comparison.brep_evaluated.r)
render_snapshot(polygonal_boolean comparison.polygonal_boolean.r)
render_snapshot(nmg comparison.nmg.r)
render_snapshot(bot comparison.bot.r)
render_snapshot(revolve comparison.revolve.r)
render_snapshot(voxel_cells comparison.voxel_cells.r)
render_snapshot(volume comparison.volume.r)
render_snapshot(point_cloud comparison.point_cloud.r)
# MGED exports its current wireframe display as view-plane plot3. Rasterize
# that plot through a disk framebuffer so regeneration needs no display.
set(WIREFRAME_PLOT "${WORKDIR}/solid_rep_wireframe.plot3")
set(WIREFRAME_PNG "${WORKDIR}/solid_rep_wireframe.png")
set(WIREFRAME_FB_NAME "solid_rep_wireframe.fb")
set(WIREFRAME_SCRIPT "${WORKDIR}/wireframe.tcl")
file(REMOVE "${WIREFRAME_PLOT}" "${WORKDIR}/${WIREFRAME_FB_NAME}" "${WIREFRAME_PNG}")
file(WRITE "${WIREFRAME_SCRIPT}" [=[
draw comparison.csg.r
size 80
orientation 0.248097 0.476591 0.748097 0.389435
eye_pt 41.9907 29.4006 53.2914
plot -2d solid_rep_wireframe.plot3
q
]=])
execute_process(
COMMAND "${MGED}" --no-rc -c "${PAWN_DB}"
WORKING_DIRECTORY "${WORKDIR}"
TIMEOUT ${RENDER_TIMEOUT}
INPUT_FILE "${WIREFRAME_SCRIPT}"
RESULT_VARIABLE wireframe_result
OUTPUT_VARIABLE wireframe_stdout
ERROR_VARIABLE wireframe_stderr
)
if(NOT wireframe_result EQUAL 0 OR NOT EXISTS "${WIREFRAME_PLOT}")
message(
FATAL_ERROR
"MGED wireframe export failed (exit ${wireframe_result})\n${wireframe_stdout}${wireframe_stderr}"
)
endif()
message(STATUS "Exported wireframe plot")
run_process(
"Cleared wireframe framebuffer"
"${FBCLEAR}" -c -F "${WIREFRAME_FB_NAME}" -w "${SIZE}" -n "${SIZE}" 24 24 24
)
execute_process(
COMMAND "${PLOT3FB}" -F "${WIREFRAME_FB_NAME}" -o -w "${SIZE}" -n "${SIZE}"
WORKING_DIRECTORY "${WORKDIR}"
TIMEOUT ${RENDER_TIMEOUT}
INPUT_FILE "${WIREFRAME_PLOT}"
RESULT_VARIABLE plot_result
OUTPUT_VARIABLE plot_stdout
ERROR_VARIABLE plot_stderr
)
if(NOT plot_result EQUAL 0)
message(FATAL_ERROR "plot3-fb failed (exit ${plot_result})\n${plot_stdout}${plot_stderr}")
endif()
run_process(
"Rasterized wireframe snapshot"
"${FBPNG}" -F "${WIREFRAME_FB_NAME}" -w "${SIZE}" -n "${SIZE}"
"solid_rep_wireframe.png"
)
copy_snapshot("${WIREFRAME_PNG}")
message(STATUS "Solid representation comparison: 11 snapshots regenerated")
-1
View File
@@ -22,5 +22,4 @@ Task-focused guides and how-to articles.
* link:articles/procedural_geometry.html[BRL-CAD Procedural Geometry Gallery]
* link:articles/projection_shader.html[Using the Projection Shader]
* link:articles/renderer_showcase.html[BRL-CAD Renderer Showcase]
* link:articles/solid_geometry_comparison.html[Solid Geometry Representation Comparisons]
* link:articles/tire.html[Vehicle Tire and Wheel Creation in BRL-CAD]
+1 -1
View File
@@ -55,7 +55,7 @@ __BEGIN_DECLS
* version 5 UUID suitable for repeatable identifier hashing.
*/
BU_EXPORT int
bu_uuid_create(uint8_t uuid[STATIC_ARRAY(16)], size_t nbytes, const uint8_t *bytes, const uint8_t *namespace_uuid);
bu_uuid_create(uint8_t uuid[STATIC_ARRAY(16)], size_t nbytes, const uint8_t *bytes, const uint8_t namespace_uuid[STATIC_ARRAY(16)]);
/**
* This is a convenience UUID comparison routine compatible with
+15 -20
View File
@@ -1108,9 +1108,9 @@ function(brlcad_install_strclear_replace stamp_dir strclear source install_file
endif()
endfunction()
function(brlcad_install_binary_postprocess stamp_dir strclear source install_file install_type mode rpath_tool install_rpath build_lib_path rel_rpath verbose)
function(brlcad_install_binary_postprocess stamp_dir strclear source install_file install_type mode rpath_tool install_rpath build_lib_path rel_rpath use_selective_rpath verbose)
set(_brlcad_physical_file "$ENV{DESTDIR}${install_file}")
set(_brlcad_signature "binary-postprocess|${install_type}|${mode}|${rpath_tool}|${install_rpath}|${build_lib_path}|${rel_rpath}|${strclear}")
set(_brlcad_signature "binary-postprocess|${install_type}|${mode}|${rpath_tool}|${install_rpath}|${build_lib_path}|${rel_rpath}|${use_selective_rpath}|${strclear}")
_brlcad_postprocess_needed(_brlcad_needed "${stamp_dir}" "${source}" "${_brlcad_physical_file}" "${_brlcad_signature}")
if(NOT _brlcad_needed)
return()
@@ -1121,41 +1121,32 @@ function(brlcad_install_binary_postprocess stamp_dir strclear source install_fil
message(FATAL_ERROR "Post-install copy did not create ${_brlcad_physical_file}")
endif()
set(_brlcad_result 0)
set(_brlcad_rpath_output)
set(_brlcad_rpath_error)
if("${mode}" STREQUAL "RPATH_TOOL")
# Install the exact project-defined search order. A selective update can
# leave an existing relative-only RPATH without the canonical install path.
set(_brlcad_selective_rpath_args)
if(use_selective_rpath)
set(_brlcad_selective_rpath_args --set-rpath-if-needed --set-rpath-if-needed-prepend --stale-rpath-prefix "${build_lib_path}")
endif()
execute_process(
COMMAND "${rpath_tool}" --set-rpath "${install_rpath}" "${_brlcad_physical_file}"
COMMAND "${rpath_tool}" --set-rpath "${install_rpath}" ${_brlcad_selective_rpath_args} "${_brlcad_physical_file}"
RESULT_VARIABLE _brlcad_result
OUTPUT_VARIABLE _brlcad_rpath_output
ERROR_VARIABLE _brlcad_rpath_error
)
elseif("${mode}" STREQUAL "APPLE")
execute_process(
COMMAND install_name_tool -delete_rpath "${build_lib_path}" "${_brlcad_physical_file}"
RESULT_VARIABLE _brlcad_result
OUTPUT_VARIABLE _brlcad_rpath_output
ERROR_VARIABLE _brlcad_rpath_error
OUTPUT_VARIABLE _brlcad_output
ERROR_VARIABLE _brlcad_error
)
if(_brlcad_result EQUAL 0)
execute_process(
COMMAND install_name_tool -add_rpath "${rel_rpath}" "${_brlcad_physical_file}"
RESULT_VARIABLE _brlcad_result
OUTPUT_VARIABLE _brlcad_rpath_output
ERROR_VARIABLE _brlcad_rpath_error
)
endif()
endif()
if(NOT _brlcad_result EQUAL 0)
message(
WARNING
"Post-install RPATH update failed for ${_brlcad_physical_file}\n"
"stdout: ${_brlcad_rpath_output}\n"
"stderr: ${_brlcad_rpath_error}"
)
message(WARNING "Post-install RPATH update failed for ${_brlcad_physical_file}")
return()
endif()
@@ -1849,9 +1840,13 @@ endfunction()
elseif(APPLE)
set(_brlcad_install_postprocess_mode "APPLE")
endif(P_RPATH_EXECUTABLE)
set(_brlcad_install_use_selective_rpath FALSE)
if(P_RPATH_SUPPORTS_SET_IF_NEEDED_PREPEND)
set(_brlcad_install_use_selective_rpath TRUE)
endif(P_RPATH_SUPPORTS_SET_IF_NEEDED_PREPEND)
install(
CODE
"include(\"${BRLCAD_EXT_INSTALL_POSTPROCESS_SCRIPT}\")\nbrlcad_install_binary_postprocess(\"${BRLCAD_EXT_INSTALL_POSTPROCESS_STAMP_DIR}\" \"${STRCLEAR_EXECUTABLE}\" \"${CMAKE_BINARY_DIR}/${tf}\" \"\${CMAKE_INSTALL_PREFIX}/${tf}\" \"PROGRAM\" \"${_brlcad_install_postprocess_mode}\" \"${_brlcad_install_postprocess_tool}\" \"${_brlcad_install_postprocess_rpath}\" \"${CMAKE_BINARY_DIR}/${LIB_DIR}\" \"${REL_RPATH}\" \"${BRLCAD_VERBOSE}\")"
"include(\"${BRLCAD_EXT_INSTALL_POSTPROCESS_SCRIPT}\")\nbrlcad_install_binary_postprocess(\"${BRLCAD_EXT_INSTALL_POSTPROCESS_STAMP_DIR}\" \"${STRCLEAR_EXECUTABLE}\" \"${CMAKE_BINARY_DIR}/${tf}\" \"\${CMAKE_INSTALL_PREFIX}/${tf}\" \"PROGRAM\" \"${_brlcad_install_postprocess_mode}\" \"${_brlcad_install_postprocess_tool}\" \"${_brlcad_install_postprocess_rpath}\" \"${CMAKE_BINARY_DIR}/${LIB_DIR}\" \"${REL_RPATH}\" \"${_brlcad_install_use_selective_rpath}\" \"${BRLCAD_VERBOSE}\")"
)
continue()
endif("${tf}" IN_LIST ALL_BINARY_FILES)
+5 -7
View File
@@ -471,13 +471,11 @@ if(BRLCAD_VERBOSE)
set(CMAKE_VERBOSE_MAKEFILE ON)
endif(BRLCAD_VERBOSE)
# Build with profile-guided optimization support. This requires a two-pass
# compile, once with BRLCAD_PGO=ON and a profile location that did not exist
# beforehand (specified via the PGO_PATH environment variable), and again in a
# fresh build directory to use metrics captured on "typical" operations and
# data. By default, the path is BUILDDIR/profiling. For MSVC, set
# VCPROFILE_PATH to PGO_PATH while running the instrumented programs so their
# per-binary .pgc files are available beside the corresponding .pgd files.
# Build with profile-guided optimization support. this requires a two-pass
# compile, once with BRLCAD_PGO=ON on a location that did not exist beforehand
# (specified via the PGO_PATH environment variable), and again to use profiling
# metrics captured on "typical" operations and data. By default, path is
# BUILDDIR/profiling
option(BRLCAD_PGO "Enable profile-guided optimization (set PGO_PATH environment variable)")
mark_as_advanced(BRLCAD_PGO)
-1
View File
@@ -108,7 +108,6 @@ set(
probe_validation/README.md
probe_validation/CMakeLists.txt
probe_validation/probe_validation.cpp
scripts/pgo_benchmark.cmake
scripts/printtime.cmake
scripts/tcl_mkindex.cmake
scripts/timestamp.cmake
-435
View File
@@ -1,435 +0,0 @@
# P G O _ B E N C H M A R K . C M A K E
# BRL-CAD
#
# Copyright (c) 2026 United States Government as represented by
# the U.S. Army Research Laboratory.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# 3. The name of the author may not be used to endorse or promote
# products derived from this software without specific prior written
# permission.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
cmake_minimum_required(VERSION 3.22)
# TRAIN runs the standard benchmark and additional geometry, then verifies
# that compiler profile counters were produced. COMPARE runs the standard
# benchmark from baseline and profile-use build trees and requires its
# equal-weight mean speedup to exceed PGO_MIN_SPEEDUP. The training model
# list accepts build-relative or absolute paths, so external model sets can be
# supplied without changing this script.
#
# Required inputs:
# TRAIN: PGO_BUILD_DIR, PGO_RESULTS_DIR, PGO_PROFILE_DIR
# COMPARE: PGO_BASELINE_BUILD_DIR, PGO_OPTIMIZED_BUILD_DIR,
# PGO_RESULTS_DIR
set(_pgo_valid_modes TRAIN COMPARE)
if(NOT DEFINED PGO_MODE)
message(FATAL_ERROR "PGO_MODE must be TRAIN or COMPARE")
endif()
string(TOUPPER "${PGO_MODE}" PGO_MODE)
if(NOT PGO_MODE IN_LIST _pgo_valid_modes)
message(FATAL_ERROR "PGO_MODE must be TRAIN or COMPARE, not '${PGO_MODE}'")
endif()
set(_pgo_default_models moss world star bldg391 m35 sphflake)
set(
_pgo_default_training_models
share/db/havoc.g
share/db/faa/Generic_Twin.g
share/db/nist/NIST_MBE_PMI_2.g
)
if(NOT DEFINED PGO_MODELS)
set(PGO_MODELS ${_pgo_default_models})
endif()
if(NOT DEFINED PGO_TRAINING_MODELS)
set(PGO_TRAINING_MODELS ${_pgo_default_training_models})
endif()
if(NOT DEFINED PGO_TIMEFRAME)
set(PGO_TIMEFRAME 8)
endif()
if(NOT DEFINED PGO_MAXTIME)
set(PGO_MAXTIME 60)
endif()
if(NOT DEFINED PGO_AVERAGE)
set(PGO_AVERAGE 3)
endif()
if(NOT DEFINED PGO_DEVIATION)
set(PGO_DEVIATION 3)
endif()
if(NOT DEFINED PGO_TRAINING_SIZE)
set(PGO_TRAINING_SIZE 512)
endif()
if(NOT DEFINED PGO_TRAINING_AZIMUTH)
set(PGO_TRAINING_AZIMUTH 35)
endif()
if(NOT DEFINED PGO_TRAINING_ELEVATION)
set(PGO_TRAINING_ELEVATION 25)
endif()
if(NOT DEFINED PGO_MIN_SPEEDUP)
set(PGO_MIN_SPEEDUP 1.0)
endif()
function(_pgo_require variable_name)
if(NOT DEFINED "${variable_name}" OR "${${variable_name}}" STREQUAL "")
message(FATAL_ERROR "${variable_name} is required for PGO_MODE=${PGO_MODE}")
endif()
endfunction()
function(_pgo_absolute_path input_path output_variable)
get_filename_component(_pgo_path "${input_path}" ABSOLUTE)
file(TO_CMAKE_PATH "${_pgo_path}" _pgo_path)
set("${output_variable}" "${_pgo_path}" PARENT_SCOPE)
endfunction()
function(_pgo_cache_value build_directory variable_name output_variable)
set(_pgo_cache_file "${build_directory}/CMakeCache.txt")
if(NOT EXISTS "${_pgo_cache_file}")
message(FATAL_ERROR "CMake cache does not exist: ${_pgo_cache_file}")
endif()
file(
STRINGS
"${_pgo_cache_file}"
_pgo_cache_entry
LIMIT_COUNT 1
REGEX "^${variable_name}(:[^=]*)?="
)
if(_pgo_cache_entry)
string(REGEX REPLACE "^[^=]*=" "" _pgo_value "${_pgo_cache_entry}")
else()
set(_pgo_value "")
endif()
set("${output_variable}" "${_pgo_value}" PARENT_SCOPE)
endfunction()
function(_pgo_validate_build build_directory expected_pgo expected_msvc_phase)
_pgo_cache_value("${build_directory}" BRLCAD_PGO _pgo_enabled)
if(expected_pgo AND NOT _pgo_enabled)
message(FATAL_ERROR "BRLCAD_PGO is not enabled in ${build_directory}")
elseif(NOT expected_pgo AND _pgo_enabled)
message(FATAL_ERROR "The baseline build unexpectedly enables BRLCAD_PGO: ${build_directory}")
endif()
_pgo_cache_value("${build_directory}" BRLCAD_MSVC_PGO_PHASE _pgo_msvc_phase)
if(_pgo_msvc_phase AND NOT _pgo_msvc_phase STREQUAL expected_msvc_phase)
message(
FATAL_ERROR
"Expected MSVC PGO phase ${expected_msvc_phase} in ${build_directory}, found ${_pgo_msvc_phase}"
)
endif()
endfunction()
function(_pgo_find_build_file build_directory file_name output_variable)
set(_pgo_candidates "${build_directory}/bin/${file_name}")
if(DEFINED PGO_CONFIG AND NOT "${PGO_CONFIG}" STREQUAL "")
list(
APPEND
_pgo_candidates
"${build_directory}/bin/${PGO_CONFIG}/${file_name}"
"${build_directory}/${PGO_CONFIG}/bin/${file_name}"
)
endif()
if(CMAKE_HOST_WIN32)
set(_pgo_executable_candidates "")
foreach(_pgo_candidate IN LISTS _pgo_candidates)
list(APPEND _pgo_executable_candidates "${_pgo_candidate}.exe")
endforeach()
list(APPEND _pgo_candidates ${_pgo_executable_candidates})
endif()
foreach(_pgo_candidate IN LISTS _pgo_candidates)
if(EXISTS "${_pgo_candidate}")
set("${output_variable}" "${_pgo_candidate}" PARENT_SCOPE)
return()
endif()
endforeach()
message(FATAL_ERROR "Could not find ${file_name} under ${build_directory}/bin")
endfunction()
function(_pgo_find_shell build_directory output_variable)
if(DEFINED PGO_SHELL AND NOT "${PGO_SHELL}" STREQUAL "")
set(_pgo_shell "${PGO_SHELL}")
elseif(EXISTS "${build_directory}/CMakeCache.txt")
file(
STRINGS
"${build_directory}/CMakeCache.txt"
_pgo_shell_cache_entry
LIMIT_COUNT 1
REGEX "^SH_EXEC(:[^=]*)?="
)
if(_pgo_shell_cache_entry)
string(REGEX REPLACE "^[^=]*=" "" _pgo_shell "${_pgo_shell_cache_entry}")
endif()
endif()
if(NOT DEFINED _pgo_shell OR "${_pgo_shell}" STREQUAL "" OR NOT EXISTS "${_pgo_shell}")
unset(_pgo_shell)
unset(_pgo_shell CACHE)
find_program(_pgo_shell NAMES sh bash)
endif()
if(NOT _pgo_shell)
message(FATAL_ERROR "The BRL-CAD benchmark requires a POSIX shell; set PGO_SHELL to its path")
endif()
set("${output_variable}" "${_pgo_shell}" PARENT_SCOPE)
endfunction()
function(_pgo_run_benchmark build_directory result_directory)
_pgo_find_build_file("${build_directory}" benchmark _pgo_benchmark)
_pgo_find_build_file("${build_directory}" rt _pgo_rt)
_pgo_find_build_file("${build_directory}" pixcmp _pgo_pixcmp)
_pgo_find_shell("${build_directory}" _pgo_shell)
file(MAKE_DIRECTORY "${result_directory}")
message(STATUS "Running the BRL-CAD benchmark from ${build_directory}")
execute_process(
COMMAND
"${_pgo_shell}" "${_pgo_benchmark}" run
"TIMEFRAME=${PGO_TIMEFRAME}"
"MAXTIME=${PGO_MAXTIME}"
"AVERAGE=${PGO_AVERAGE}"
"DEVIATION=${PGO_DEVIATION}"
"RT=${_pgo_rt}"
"CMP=${_pgo_pixcmp}"
-P1
WORKING_DIRECTORY "${result_directory}"
RESULT_VARIABLE _pgo_benchmark_result
)
if(NOT "${_pgo_benchmark_result}" STREQUAL "0")
message(FATAL_ERROR "The benchmark from ${build_directory} failed with status ${_pgo_benchmark_result}")
endif()
endfunction()
function(_pgo_extract_rate log_file output_text output_integer)
if(NOT EXISTS "${log_file}")
message(FATAL_ERROR "Benchmark log does not exist: ${log_file}")
endif()
file(READ "${log_file}" _pgo_log)
string(REGEX MATCHALL "[0-9]+(\\.[0-9]+)? rays/sec \\(RTFM\\)" _pgo_rate_lines "${_pgo_log}")
if(NOT _pgo_rate_lines)
message(FATAL_ERROR "No RTFM result was found in ${log_file}")
endif()
list(GET _pgo_rate_lines -1 _pgo_rate_line)
string(REGEX REPLACE " rays/sec.*$" "" _pgo_rate "${_pgo_rate_line}")
if(NOT _pgo_rate MATCHES "^([0-9]+)(\\.([0-9]+))?$")
message(FATAL_ERROR "Invalid RTFM result '${_pgo_rate}' in ${log_file}")
endif()
set(_pgo_whole "${CMAKE_MATCH_1}")
set(_pgo_fraction "${CMAKE_MATCH_3}00")
string(SUBSTRING "${_pgo_fraction}" 0 2 _pgo_fraction)
string(REGEX REPLACE "^0+" "" _pgo_whole "${_pgo_whole}")
string(REGEX REPLACE "^0+" "" _pgo_fraction "${_pgo_fraction}")
if("${_pgo_whole}" STREQUAL "")
set(_pgo_whole 0)
endif()
if("${_pgo_fraction}" STREQUAL "")
set(_pgo_fraction 0)
endif()
math(EXPR _pgo_rate_integer "${_pgo_whole} * 100 + ${_pgo_fraction}")
if(_pgo_rate_integer LESS_EQUAL 0)
message(FATAL_ERROR "Non-positive RTFM result '${_pgo_rate}' in ${log_file}")
endif()
set("${output_text}" "${_pgo_rate}" PARENT_SCOPE)
set("${output_integer}" "${_pgo_rate_integer}" PARENT_SCOPE)
endfunction()
function(_pgo_decimal_to_thousandths value output_variable)
if(NOT "${value}" MATCHES "^([0-9]+)(\\.([0-9]+))?$")
message(FATAL_ERROR "Expected a non-negative decimal number, not '${value}'")
endif()
set(_pgo_whole "${CMAKE_MATCH_1}")
set(_pgo_fraction "${CMAKE_MATCH_3}000")
string(SUBSTRING "${_pgo_fraction}" 0 3 _pgo_fraction)
string(REGEX REPLACE "^0+" "" _pgo_whole "${_pgo_whole}")
string(REGEX REPLACE "^0+" "" _pgo_fraction "${_pgo_fraction}")
if("${_pgo_whole}" STREQUAL "")
set(_pgo_whole 0)
endif()
if("${_pgo_fraction}" STREQUAL "")
set(_pgo_fraction 0)
endif()
math(EXPR _pgo_value "${_pgo_whole} * 1000 + ${_pgo_fraction}")
set("${output_variable}" "${_pgo_value}" PARENT_SCOPE)
endfunction()
function(_pgo_format_thousandths value output_variable)
math(EXPR _pgo_whole "${value} / 1000")
math(EXPR _pgo_fraction "${value} % 1000")
set(_pgo_fraction "00${_pgo_fraction}")
string(LENGTH "${_pgo_fraction}" _pgo_fraction_length)
math(EXPR _pgo_fraction_offset "${_pgo_fraction_length} - 3")
string(SUBSTRING "${_pgo_fraction}" ${_pgo_fraction_offset} 3 _pgo_fraction)
set("${output_variable}" "${_pgo_whole}.${_pgo_fraction}" PARENT_SCOPE)
endfunction()
if(PGO_MODE STREQUAL "TRAIN")
_pgo_require(PGO_BUILD_DIR)
_pgo_require(PGO_RESULTS_DIR)
_pgo_require(PGO_PROFILE_DIR)
_pgo_absolute_path("${PGO_BUILD_DIR}" PGO_BUILD_DIR)
_pgo_absolute_path("${PGO_RESULTS_DIR}" PGO_RESULTS_DIR)
_pgo_absolute_path("${PGO_PROFILE_DIR}" PGO_PROFILE_DIR)
if(NOT IS_DIRECTORY "${PGO_BUILD_DIR}")
message(FATAL_ERROR "PGO_BUILD_DIR does not exist: ${PGO_BUILD_DIR}")
endif()
_pgo_validate_build("${PGO_BUILD_DIR}" TRUE GENERATE)
# MSVC's profile runtime uses this location for each image's PGC files.
# GCC ignores it and writes its GCDA files to the compiled-in PGO path.
file(MAKE_DIRECTORY "${PGO_PROFILE_DIR}")
set(ENV{VCPROFILE_PATH} "${PGO_PROFILE_DIR}")
_pgo_run_benchmark("${PGO_BUILD_DIR}" "${PGO_RESULTS_DIR}/benchmark")
_pgo_find_build_file("${PGO_BUILD_DIR}" rt _pgo_rt)
if(CMAKE_HOST_WIN32)
set(_pgo_null_device NUL)
else()
set(_pgo_null_device /dev/null)
endif()
set(_pgo_training_index 0)
foreach(_pgo_model IN LISTS PGO_TRAINING_MODELS)
math(EXPR _pgo_training_index "${_pgo_training_index} + 1")
if(IS_ABSOLUTE "${_pgo_model}")
set(_pgo_model_path "${_pgo_model}")
else()
set(_pgo_model_path "${PGO_BUILD_DIR}/${_pgo_model}")
endif()
if(NOT EXISTS "${_pgo_model_path}")
message(FATAL_ERROR "Training model does not exist: ${_pgo_model_path}")
endif()
get_filename_component(_pgo_log_name "${_pgo_model_path}" NAME_WE)
string(REGEX REPLACE "[^A-Za-z0-9_.-]" "_" _pgo_log_name "${_pgo_log_name}")
set(_pgo_log_file "${PGO_RESULTS_DIR}/${_pgo_training_index}-${_pgo_log_name}.log")
message(STATUS "Training with ${_pgo_model_path}")
execute_process(
COMMAND
"${_pgo_rt}" -B -P1 "-s${PGO_TRAINING_SIZE}"
"-a${PGO_TRAINING_AZIMUTH}" "-e${PGO_TRAINING_ELEVATION}"
-o "${_pgo_null_device}" "${_pgo_model_path}"
RESULT_VARIABLE _pgo_rt_result
OUTPUT_VARIABLE _pgo_rt_output
ERROR_VARIABLE _pgo_rt_error
)
file(WRITE "${_pgo_log_file}" "${_pgo_rt_output}${_pgo_rt_error}")
if(NOT "${_pgo_rt_result}" STREQUAL "0")
message(FATAL_ERROR "Training ${_pgo_model} failed with status ${_pgo_rt_result}; see ${_pgo_log_file}")
endif()
string(REGEX MATCH "[^\r\n]*rays/sec \\(RTFM\\)" _pgo_rtfm_line "${_pgo_rt_output}${_pgo_rt_error}")
if(NOT _pgo_rtfm_line)
message(FATAL_ERROR "Training ${_pgo_model} did not complete a raytrace; see ${_pgo_log_file}")
endif()
message(STATUS "${_pgo_model}: ${_pgo_rtfm_line}")
endforeach()
file(GLOB_RECURSE _pgo_gcda_files LIST_DIRECTORIES FALSE "${PGO_PROFILE_DIR}/*.gcda")
file(GLOB_RECURSE _pgo_pgc_files LIST_DIRECTORIES FALSE "${PGO_PROFILE_DIR}/*.pgc")
list(LENGTH _pgo_gcda_files _pgo_gcda_count)
list(LENGTH _pgo_pgc_files _pgo_pgc_count)
math(EXPR _pgo_profile_count "${_pgo_gcda_count} + ${_pgo_pgc_count}")
if(_pgo_profile_count EQUAL 0)
message(FATAL_ERROR "Training did not generate GCC GCDA or MSVC PGC data under ${PGO_PROFILE_DIR}")
endif()
message(STATUS "Training generated ${_pgo_profile_count} profile counter files under ${PGO_PROFILE_DIR}")
else()
_pgo_require(PGO_BASELINE_BUILD_DIR)
_pgo_require(PGO_OPTIMIZED_BUILD_DIR)
_pgo_require(PGO_RESULTS_DIR)
_pgo_absolute_path("${PGO_BASELINE_BUILD_DIR}" PGO_BASELINE_BUILD_DIR)
_pgo_absolute_path("${PGO_OPTIMIZED_BUILD_DIR}" PGO_OPTIMIZED_BUILD_DIR)
_pgo_absolute_path("${PGO_RESULTS_DIR}" PGO_RESULTS_DIR)
_pgo_validate_build("${PGO_BASELINE_BUILD_DIR}" FALSE "")
_pgo_validate_build("${PGO_OPTIMIZED_BUILD_DIR}" TRUE USE)
_pgo_run_benchmark("${PGO_BASELINE_BUILD_DIR}" "${PGO_RESULTS_DIR}/baseline")
_pgo_run_benchmark("${PGO_OPTIMIZED_BUILD_DIR}" "${PGO_RESULTS_DIR}/optimized")
set(_pgo_report "### Profile-guided optimization results\n\n")
string(APPEND _pgo_report "| Model | Baseline rays/sec | PGO rays/sec | Speedup |\n")
string(APPEND _pgo_report "| --- | ---: | ---: | ---: |\n")
set(_pgo_speedup_sum 0)
set(_pgo_model_count 0)
set(_pgo_tsv "model\tbaseline_rays_per_second\tpgo_rays_per_second\tspeedup\n")
foreach(_pgo_model IN LISTS PGO_MODELS)
_pgo_extract_rate("${PGO_RESULTS_DIR}/baseline/${_pgo_model}.log" _pgo_baseline_rate _pgo_baseline_integer)
_pgo_extract_rate("${PGO_RESULTS_DIR}/optimized/${_pgo_model}.log" _pgo_optimized_rate _pgo_optimized_integer)
math(
EXPR
_pgo_speedup
"(${_pgo_optimized_integer} * 1000 + ${_pgo_baseline_integer} / 2) / ${_pgo_baseline_integer}"
)
_pgo_format_thousandths("${_pgo_speedup}" _pgo_speedup_text)
math(EXPR _pgo_speedup_sum "${_pgo_speedup_sum} + ${_pgo_speedup}")
math(EXPR _pgo_model_count "${_pgo_model_count} + 1")
string(
APPEND
_pgo_report
"| `${_pgo_model}` | ${_pgo_baseline_rate} | ${_pgo_optimized_rate} | ${_pgo_speedup_text}x |\n"
)
string(
APPEND
_pgo_tsv
"${_pgo_model}\t${_pgo_baseline_rate}\t${_pgo_optimized_rate}\t${_pgo_speedup_text}\n"
)
endforeach()
if(_pgo_model_count EQUAL 0)
message(FATAL_ERROR "PGO_MODELS must name at least one benchmark model")
endif()
math(EXPR _pgo_mean_speedup "(${_pgo_speedup_sum} + ${_pgo_model_count} / 2) / ${_pgo_model_count}")
_pgo_format_thousandths("${_pgo_mean_speedup}" _pgo_mean_speedup_text)
string(APPEND _pgo_report "\nArithmetic mean speedup: ${_pgo_mean_speedup_text}x\n")
file(MAKE_DIRECTORY "${PGO_RESULTS_DIR}")
file(WRITE "${PGO_RESULTS_DIR}/results.tsv" "${_pgo_tsv}")
if(DEFINED PGO_SUMMARY_FILE AND NOT "${PGO_SUMMARY_FILE}" STREQUAL "")
_pgo_absolute_path("${PGO_SUMMARY_FILE}" _pgo_summary_file)
elseif(NOT "$ENV{GITHUB_STEP_SUMMARY}" STREQUAL "")
set(_pgo_summary_file "$ENV{GITHUB_STEP_SUMMARY}")
endif()
if(DEFINED _pgo_summary_file)
file(APPEND "${_pgo_summary_file}" "${_pgo_report}")
endif()
message("${_pgo_report}")
_pgo_decimal_to_thousandths("${PGO_MIN_SPEEDUP}" _pgo_min_speedup)
if(NOT _pgo_mean_speedup GREATER _pgo_min_speedup)
message(
FATAL_ERROR
"PGO raytracing speedup ${_pgo_mean_speedup_text}x did not exceed ${PGO_MIN_SPEEDUP}x"
)
endif()
endif()
# Local Variables:
# tab-width: 8
# mode: cmake
# indent-tabs-mode: t
# End:
# ex: shiftwidth=2 tabstop=8
+19 -35
View File
@@ -7,25 +7,14 @@
set -e
set -o pipefail
# CLANG_VERSION should be set by User or CI environments to avoid hard-coding
# a particular version into the script
if [ -z "$CLANG_VERSION" ]; then
echo "Error: CLANG_VERSION environment variable is not set." >&2
exit 1
fi
# Derive tool paths from the version
SCAN_BUILD_DIR="/usr/share/clang/scan-build-${CLANG_VERSION}"
SCAN_BUILD_BIN="${SCAN_BUILD_DIR}/bin"
SCAN_BUILD_LIBEXEC="${SCAN_BUILD_DIR}/libexec"
CLANG_ANALYZER_BIN="/usr/bin/clang-${CLANG_VERSION}"
# Add scan-build to the PATH
export PATH="${SCAN_BUILD_BIN}:${SCAN_BUILD_LIBEXEC}:${PATH}"
# Set compilers for the analyzer scripts
export CCC_CC="clang-${CLANG_VERSION}"
export CCC_CXX="clang++-${CLANG_VERSION}"
# Note: we set these variables to tell the ccc-analyzer script which compilers
# to use, but it is not always enough - when some of the sub-builds are
# triggered, they do not seem to inherit these settings and revert to the
# default compiler. The only way so far to avoid this issue reliably seems to
# be to edit the ccc-analyzer script to use the compiler we want as the default
# compiler.
export CCC_CC=clang
export CCC_CXX=clang++
# This appears to be a workable way to enable the new Z3 static analyzer
# support, but at least as of 2017-12 it greatly slows the testing (by orders
@@ -56,24 +45,19 @@ fi
# Encapsulate the logic to do a scan build
function runtest {
echo "$1"
scan-build --use-analyzer="${CLANG_ANALYZER_BIN}" -o "./scan-reports-$1" make -j12 "$1"
if [ -d "./scan-reports-$1" ] && [ -n "$(ls -A "./scan-reports-$1")" ]; then
report_cnt=$(find "./scan-reports-$1" -name 'report-*.html' | wc -l)
failure=$((failure + report_cnt))
else
rm -rf "./scan-reports-$1"
fi
echo "$1"
scan-build --use-analyzer=/usr/bin/$CCC_CC -o ./scan-reports-$1 make -j12 $1
if [ "$(ls -A ./scan-reports-$1)" ]; then
report_cnt=$(ls -l ./scan-reports-$1/*/report* | wc -l)
failure=$(($failure + $report_cnt))
else
rm -rf ./scan-reports-$1
fi
}
# Configure using the correct compiler and values.
scan-build --use-analyzer="${CLANG_ANALYZER_BIN}" -o ./scan-reports-config cmake .. \
-DBRLCAD_EXTRADOCS=OFF \
-DBRLCAD_ENABLE_QT=ON \
-DBRLCAD_LTO_MODE=OFF \
-DBRLCAD_EXT_DIR="$bext_dir" \
-DCMAKE_C_COMPILER=ccc-analyzer \
-DCMAKE_CXX_COMPILER=c++-analyzer
# configure using the correct compiler and values. We don't
# need this report, so clear it after configure is done
scan-build --use-analyzer=/usr/bin/$CCC_CC -o ./scan-reports-config cmake .. -DBRLCAD_EXTRADOCS=OFF -DBRLCAD_ENABLE_QT=ON -DBRLCAD_LTO_MODE=OFF -DBRLCAD_EXT_DIR="$bext_dir" -DCMAKE_C_COMPILER=ccc-analyzer -DCMAKE_CXX_COMPILER=c++-analyzer
# clear out any old reports
rm -rfv ./scan-reports-*
-13
View File
@@ -144,18 +144,6 @@ if(BRLCAD_X11_PROVIDER_RESOLVED STREQUAL "XMIN" AND
)
brlcad_regression_test(regress-archer-embedded-xmin-gui
"archer;bwish" STAND_ALONE TEST_DEFINED)
brlcad_add_gui_test(
NAME regress-archer-geometry-xmin-gui
TIMEOUT 120
ENVIRONMENT ${_gui_smoke_environment}
"GUI_TEST_LIBRARY=${_gui_test_library}"
COMMAND "${SH_EXEC}" "${_gui_tcl_runner}" archer-geometry
$<TARGET_FILE:bwish>
"${CMAKE_CURRENT_SOURCE_DIR}/archer_geometry_xmin_gui.tcl"
)
brlcad_regression_test(regress-archer-geometry-xmin-gui
"archer;bwish" STAND_ALONE TEST_DEFINED)
endif()
endif()
@@ -213,7 +201,6 @@ cmakefiles(
archer_action.sh
archer_smoke.sh
archer_embedded_xmin_gui.tcl
archer_geometry_xmin_gui.tcl
archer_menu_manifest.txt
archer_xmin_gui.tcl
qged_action.sh
-134
View File
@@ -1,134 +0,0 @@
# A R C H E R _ G E O M E T R Y _ X M I N _ G U I . T C L
# BRL-CAD
#
# Copyright (c) 2026 United States Government as represented by
# the U.S. Army Research Laboratory.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public License
# version 2.1 as published by the Free Software Foundation.
#
# This library is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this file; see the file named COPYING for more
# information.
#
###
if {![info exists ::env(GUI_TEST_LIBRARY)]} {
puts stderr "GUI_TEST_LIBRARY is required"
exit 2
}
source $::env(GUI_TEST_LIBRARY)
set ::env(ARCHER_PREFS_FILE) [file join $::env(GUI_TEST_DIR) .archerrc]
proc archer_geometry_preferences {{geometry ""}} {
set channel [open $::env(ARCHER_PREFS_FILE) w]
if {$geometry ne ""} {
puts $channel [list set mWindowGeometry $geometry]
}
close $channel
}
proc archer_geometry_saved {} {
set channel [open $::env(ARCHER_PREFS_FILE) r]
set contents [read $channel]
close $channel
if {[regexp -line {^set mWindowGeometry (.+)$} $contents -> geometry]} {
return $geometry
}
return ""
}
proc archer_geometry_settle {} {
# Allow MapNotify and the deferred geometry restore to reach the event loop.
set settle_delay_ms 100
after $settle_delay_ms [list set ::archer_geometry_settled 1]
vwait ::archer_geometry_settled
update
::gui::test::require_no_background_errors
}
if {[catch {
package require Archer 1.0
::gui::test::capture_background_errors
wm withdraw .
set saved_geometry 900x650+120+90
set startup_geometry 1000x700+20+30
set updated_geometry 950x680+60+70
set default_geometry 920x660+40+50
archer_geometry_preferences $saved_geometry
Archer .unmapped
::gui::test::require {[wm state .unmapped] eq "withdrawn"} \
"startup fixture unexpectedly showed its window"
::itcl::delete object .unmapped
archer_geometry_settle
::gui::test::require {[archer_geometry_saved] eq $saved_geometry} \
"closing an unmapped Archer replaced its saved geometry"
archer_geometry_preferences
Archer .unmapped_new
::itcl::delete object .unmapped_new
archer_geometry_settle
::gui::test::require {[archer_geometry_saved] eq ""} \
"closing an unmapped Archer saved an unfinished layout size"
archer_geometry_preferences $saved_geometry
Archer .restore
.restore configure -geometry $startup_geometry
wm geometry .restore $startup_geometry
event generate [.restore component hpane] <Map>
archer_geometry_settle
::gui::test::require {[wm geometry .restore] eq $startup_geometry} \
"a child Map event restored the main window's geometry prematurely"
wm deiconify .restore
archer_geometry_settle
::gui::test::require {[wm geometry .restore] eq $saved_geometry} \
"mapping the main window did not restore its saved geometry"
wm geometry .restore $updated_geometry
event generate [.restore component hpane] <Map>
archer_geometry_settle
::gui::test::require {[wm geometry .restore] eq $updated_geometry} \
"a later child Map event reset the resized main window"
wm withdraw .restore
::itcl::delete object .restore
archer_geometry_settle
::gui::test::require {[archer_geometry_saved] eq $updated_geometry} \
"closing a previously mapped window did not save its latest geometry"
archer_geometry_preferences
Archer .default
wm geometry .default $default_geometry
wm deiconify .default
archer_geometry_settle
::gui::test::require {[wm geometry .default] eq $default_geometry} \
"an empty geometry option reset the window to its layout size"
wm withdraw .default
::itcl::delete object .default
archer_geometry_settle
} message options]} {
puts stderr $message
if {[dict exists $options -errorinfo]} {
puts stderr [dict get $options -errorinfo]
}
puts "FAIL: Archer window geometry regression"
exit 1
}
puts "PASS: Archer window geometry restoration and startup cancellation"
exit 0
# Local Variables:
# tab-width: 8
# mode: Tcl
# tcl-indent-level: 4
# indent-tabs-mode: t
# End:
# ex: shiftwidth=4 tabstop=8
+9 -7
View File
@@ -72,15 +72,17 @@ set(archer_wizard_FILES
)
if(BRLCAD_ENABLE_TCL)
# Archer scans only the plugin category directories for registration scripts.
# Keep class definitions in their subdirectories so they are not sourced twice.
foreach(plugin_file IN LISTS archer_utility_FILES archer_wizard_FILES)
get_filename_component(plugin_dir "${plugin_file}" DIRECTORY)
file(RELATIVE_PATH plugin_dir "${CMAKE_CURRENT_SOURCE_DIR}/plugins" "${CMAKE_CURRENT_SOURCE_DIR}/${plugin_dir}")
brlcad_adddata("${plugin_file}" "plugins/archer/${plugin_dir}")
endforeach()
brlcad_adddata(archer_utility_FILES plugins/archer/Utility)
brlcad_adddata(archer_wizard_FILES plugins/archer/Wizards)
brlcad_adddata(plugins/Commands/README plugins/archer/Command)
brlcad_adddata(plugins/Core/README plugins/archer/Core)
brlcad_adddata(plugins/Utility/attrGroupsDisplayUtilityP/AttrGroupsDisplayUtilityP.tcl plugins/archer/Utility/attrGroupsDisplayUtilityP)
brlcad_adddata(plugins/Utility/botUtilityP/BotUtilityP.tcl plugins/archer/Utility/botUtilityP)
brlcad_adddata(plugins/Utility/lodUtilityP/LODUtilityP.tcl plugins/archer/Utility/lodUtilityP)
brlcad_adddata(plugins/Wizards/humanwizard/HumanWizard.tcl plugins/archer/Wizards/humanwizard)
brlcad_adddata(plugins/Wizards/tankwizard/TankWizard.tcl plugins/archer/Wizards/tankwizard)
brlcad_adddata(plugins/Wizards/tankwizard/images/tank.png plugins/archer/Wizards/tankwizardIA/images)
brlcad_adddata(plugins/Wizards/tirewizard/TireWizard.tcl plugins/archer/Wizards/tirewizard)
endif(BRLCAD_ENABLE_TCL)
set(
-10
View File
@@ -109,16 +109,6 @@ brlcad_addexec(g-var g-var.c "librt;libbu;${M_LIBRARY}" FOLDER Conv)
brlcad_addexec(g-vrml g-vrml.c "librt;libnmg;libbu;${M_LIBRARY}" FOLDER Conv)
brlcad_addexec(g-x3d g-x3d.c "librt;libnmg;libbu;${M_LIBRARY}" FOLDER Conv)
# GCC cannot model BU_SETJUMP's longjmp path during LTO and reports an
# anonymous value as potentially uninitialized.
check_linker_flag(
"C"
"-Wno-error=maybe-uninitialized"
G_X3D_LINKER_WNO_MAYBE_UNINITIALIZED
)
if(G_X3D_LINKER_WNO_MAYBE_UNINITIALIZED)
target_link_options(g-x3d PRIVATE -Wno-maybe-uninitialized)
endif()
brlcad_addexec(nastran-g nastran-g.c "libwdb;librt;libnmg;libbu;${M_LIBRARY}" FOLDER Conv)
+6 -6
View File
@@ -326,7 +326,7 @@ SHPOpenLL( const char * pszLayer, const char * pszAccess, SAHooks *psHooks ) {
/* -------------------------------------------------------------------- */
/* Initialize the info structure. */
/* -------------------------------------------------------------------- */
SHPHandle psSHP = STATIC_CAST(SHPHandle, calloc(1,sizeof(SHPInfo)));
SHPHandle psSHP = STATIC_CAST(SHPHandle, calloc(sizeof(SHPInfo),1));
psSHP->bUpdated = FALSE;
memcpy( &(psSHP->sHooks), psHooks, sizeof(SAHooks) );
@@ -1176,7 +1176,7 @@ SHPCreateObject( int nSHPType, int nShapeId, int nParts,
psObject->nParts = MAX(1,nParts);
psObject->panPartStart = STATIC_CAST(int *,
calloc(psObject->nParts, sizeof(int)));
calloc(sizeof(int), psObject->nParts));
psObject->panPartType = STATIC_CAST(int *,
malloc(sizeof(int) * psObject->nParts));
@@ -1205,13 +1205,13 @@ SHPCreateObject( int nSHPType, int nShapeId, int nParts,
{
const size_t nSize = sizeof(double) * nVertices;
psObject->padfX = STATIC_CAST(double *, padfX ? malloc(nSize) :
calloc(nVertices,sizeof(double)));
calloc(sizeof(double),nVertices));
psObject->padfY = STATIC_CAST(double *, padfY ? malloc(nSize) :
calloc(nVertices,sizeof(double)));
calloc(sizeof(double),nVertices));
psObject->padfZ = STATIC_CAST(double *, padfZ && bHasZ ? malloc(nSize) :
calloc(nVertices,sizeof(double)));
calloc(sizeof(double),nVertices));
psObject->padfM = STATIC_CAST(double *, padfM && bHasM ? malloc(nSize) :
calloc(nVertices,sizeof(double)));
calloc(sizeof(double),nVertices));
if( padfX != SHPLIB_NULLPTR )
memcpy(psObject->padfX, padfX, nSize);
if( padfY != SHPLIB_NULLPTR )
+2 -2
View File
@@ -5545,8 +5545,8 @@ repair_ambiguous_singular_periodic_loop_branches(ON_Brep *brep,
std::vector<int> affected_positions;
affected_positions.reserve(arc_positions.size() + 2);
affected_positions.push_back(first_position);
for (const int position : arc_positions)
affected_positions.push_back(position);
affected_positions.insert(affected_positions.end(),
arc_positions.begin(), arc_positions.end());
affected_positions.push_back(second_position);
for (int shift_sign = -1; shift_sign <= 1 && !repaired;
+16 -20
View File
@@ -50,16 +50,16 @@
/* Hash a single 512-bit block. This is the core of the algorithm. */
void SHA1Transform(uint32_t state[5], const unsigned char buffer[SHA1_BLOCK_SIZE])
void SHA1Transform(uint32_t state[5], const unsigned char buffer[64])
{
uint32_t a, b, c, d, e;
typedef union {
unsigned char c[SHA1_BLOCK_SIZE];
unsigned char c[64];
uint32_t l[16];
} CHAR64LONG16;
#ifdef SHA1HANDSOFF
CHAR64LONG16 block[1]; /* use array to appear as a pointer */
memcpy(block, buffer, sizeof(block));
memcpy(block, buffer, 64);
#else
/* The following had better never be used because it causes the
* pointer-to-const buffer to be cast into a pointer to non-const.
@@ -131,11 +131,11 @@ void SHA1Update(SHA1_CTX* context, const unsigned char* data, uint32_t len)
if ((context->count[0] += len << 3) < j)
context->count[1]++;
context->count[1] += (len>>29);
j = (j >> 3) & (SHA1_BLOCK_SIZE - 1);
if ((j + len) >= SHA1_BLOCK_SIZE) {
memcpy(&context->buffer[j], data, (i = SHA1_BLOCK_SIZE-j));
j = (j >> 3) & 63;
if ((j + len) > 63) {
memcpy(&context->buffer[j], data, (i = 64-j));
SHA1Transform(context->state, context->buffer);
for ( ; i + SHA1_BLOCK_SIZE - 1 < len; i += SHA1_BLOCK_SIZE) {
for ( ; i + 63 < len; i += 64) {
SHA1Transform(context->state, &data[i]);
}
j = 0;
@@ -149,26 +149,22 @@ void SHA1Update(SHA1_CTX* context, const unsigned char* data, uint32_t len)
void SHA1Final(unsigned char digest[20], SHA1_CTX* context)
{
static const unsigned char padding[SHA1_BLOCK_SIZE] = {0x80};
unsigned char finalcount[8];
const uint32_t block_size = (uint32_t)sizeof(context->buffer);
const uint32_t length_offset = block_size - (uint32_t)sizeof(finalcount);
uint32_t buffer_used;
uint32_t padding_length;
unsigned i;
unsigned char finalcount[8];
unsigned char c;
for (i = 0; i < 8; i++) {
finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
>> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
}
buffer_used = (context->count[0] >> 3) & (block_size - 1);
if (buffer_used < length_offset)
padding_length = length_offset - buffer_used;
else
padding_length = block_size + length_offset - buffer_used;
SHA1Update(context, padding, padding_length);
SHA1Update(context, finalcount, (uint32_t)sizeof(finalcount));
c = 0200;
SHA1Update(context, &c, 1);
while ((context->count[0] & 504) != 448) {
c = 0000;
SHA1Update(context, &c, 1);
}
SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */
for (i = 0; i < 20; i++) {
digest[i] = (unsigned char)
((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
+2 -4
View File
@@ -7,17 +7,15 @@
#include "common.h"
#define SHA1_BLOCK_SIZE 64
typedef struct {
uint32_t state[5];
uint32_t count[2];
unsigned char buffer[SHA1_BLOCK_SIZE];
unsigned char buffer[64];
} SHA1_CTX;
__BEGIN_DECLS
void SHA1Transform(uint32_t state[5], const unsigned char buffer[SHA1_BLOCK_SIZE]);
void SHA1Transform(uint32_t state[5], const unsigned char buffer[64]);
void SHA1Init(SHA1_CTX* context);
void SHA1Update(SHA1_CTX* context, const unsigned char* data, uint32_t len);
void SHA1Final(unsigned char digest[20], SHA1_CTX* context);
+1 -1
View File
@@ -46,7 +46,7 @@ extern double drand48(void);
int
bu_uuid_create(uint8_t uuid[STATIC_ARRAY(16)], size_t nbytes, const uint8_t *bytes, const uint8_t *namespace_uuid)
bu_uuid_create(uint8_t uuid[STATIC_ARRAY(16)], size_t nbytes, const uint8_t *bytes, const uint8_t namespace_uuid[STATIC_ARRAY(16)])
{
int type = 4; /* random */
+4 -4
View File
@@ -934,7 +934,7 @@ x24_setup(struct fb *ifp, int width, int height)
case FLG_VP8:
case FLG_VS8:
case FLG_VG8:
if ((xi->xi_pix = (unsigned char *) calloc(width*height, sizeof(uint8_t))) == NULL) {
if ((xi->xi_pix = (unsigned char *) calloc(sizeof(uint8_t), width*height)) == NULL) {
fb_log("X24_open: pix8 malloc failed\n");
return -1;
}
@@ -950,7 +950,7 @@ x24_setup(struct fb *ifp, int width, int height)
xi->xi_visual, xi->xi_depth, XYBitmap, 0,
NULL, width, height, 32, 0);
if ((xi->xi_pix = (unsigned char *) calloc(xi->xi_image->bytes_per_line * height, sizeof(uint8_t))) == NULL) {
if ((xi->xi_pix = (unsigned char *) calloc(sizeof(uint8_t), xi->xi_image->bytes_per_line * height)) == NULL) {
fb_log("X24_open: pix1 malloc failed\n");
return -1;
}
@@ -2653,7 +2653,7 @@ X24_configureWindow(struct fb *ifp, int width, int height)
XDestroyImage(xi->xi_image);
/* Make new buffers and new image */
if ((xi->xi_pix = (unsigned char *)calloc(xi->xi_xwidth * xi->xi_xheight, sizeof(uint8_t))) == NULL) {
if ((xi->xi_pix = (unsigned char *)calloc(sizeof(uint8_t), xi->xi_xwidth * xi->xi_xheight)) == NULL) {
fb_log("X24: pix8 malloc failed in resize!\n");
return 1;
}
@@ -2671,7 +2671,7 @@ X24_configureWindow(struct fb *ifp, int width, int height)
xi->xi_visual, xi->xi_depth, XYBitmap, 0,
NULL, xi->xi_xwidth, xi->xi_xheight, 32, 0);
if ((xi->xi_pix = (unsigned char *)calloc(xi->xi_image->bytes_per_line * xi->xi_xheight, sizeof(uint8_t))) == NULL) {
if ((xi->xi_pix = (unsigned char *)calloc(sizeof(uint8_t), xi->xi_image->bytes_per_line * xi->xi_xheight)) == NULL) {
fb_log("X24: pix1 malloc failed in resize!\n");
return 1;
}
+2 -2
View File
@@ -422,12 +422,12 @@ fb_open(const char *file, int width, int height)
if (width < 0 || height < 0)
return FB_NULL;
ifp = (struct fb *)calloc(1, sizeof(struct fb));
ifp = (struct fb *)calloc(sizeof(struct fb), 1);
if (ifp == FB_NULL) {
Malloc_Bomb(sizeof(struct fb));
return FB_NULL;
}
ifp->i = (struct fb_impl *)calloc(1, sizeof(struct fb_impl));
ifp->i = (struct fb_impl *)calloc(sizeof(struct fb_impl), 1);
if (file == NULL || *file == '\0') {
/* No name given, check environment variable first. */
file = (const char *)getenv("FB_FILE");
+2 -2
View File
@@ -114,8 +114,8 @@ struct fb *
fb_open_existing(const char *file, int width, int height, struct fb_platform_specific *fb_p)
{
struct fb *ifp;
ifp = (struct fb *)calloc(1, sizeof(struct fb));
ifp->i = (struct fb_impl *) calloc(1, sizeof(struct fb_impl));
ifp = (struct fb *)calloc(sizeof(struct fb), 1);
ifp->i = (struct fb_impl *) calloc(sizeof(struct fb_impl), 1);
fb_set_interface(ifp, file);
fb_set_magic(ifp, FB_MAGIC);
fb_setup_existing(ifp, width, height, fb_p);
+3 -9
View File
@@ -254,15 +254,9 @@ qtgl_open(void *ctx, void *UNUSED(interp), int argc, const char **argv)
if (bu_vls_strlen(&dmp->i->dm_pathName) == 0)
bu_vls_printf(&dmp->i->dm_pathName, ".dm_qtgl%d", count);
++count;
if (bu_vls_strlen(&dmp->i->dm_dName) == 0) {
char *dp;
dp = getenv("DISPLAY");
if (dp)
bu_vls_strcpy(&dmp->i->dm_dName, dp);
else
bu_vls_strcpy(&dmp->i->dm_dName, ":0.0");
}
/* The supplied QOpenGLWidget determines the Qt display. Keep dm_dName
* empty unless the caller supplied -d; DISPLAY is an X11 setting and
* cannot identify a Qt context on every supported platform. */
/* initialize dm specific variables */
pubvars->devmotionnotify = 0;
+3 -9
View File
@@ -246,15 +246,9 @@ swrast_open(void *ctx, void *UNUSED(interp), int argc, const char **argv)
if (bu_vls_strlen(&dmp->i->dm_pathName) == 0)
bu_vls_printf(&dmp->i->dm_pathName, ".dm_swrast%d", count);
++count;
if (bu_vls_strlen(&dmp->i->dm_dName) == 0) {
char *dp;
dp = getenv("DISPLAY");
if (dp)
bu_vls_strcpy(&dmp->i->dm_dName, dp);
else
bu_vls_strcpy(&dmp->i->dm_dName, ":0.0");
}
/* OSMesa is offscreen and has no display to discover. Leave dm_dName
* empty unless the caller supplied -d; a window-system wrapper can then
* select its own initialized display without inheriting X11 state. */
/* initialize dm specific variables */
pubvars->devmotionnotify = 0;
+10
View File
@@ -464,6 +464,16 @@ tkswrast_open(void *ctx, void *vinterp, int argc, const char **argv)
tv->orig_configureWin = dmp->i->dm_configureWin;
tv->orig_close = dmp->i->dm_close;
/* The wrapped offscreen backend deliberately has no default display.
* For this Tk presentation layer, use the display Tk actually opened.
* This remains correct for X11, Win32, and Aqua even when the process
* inherited an unrelated DISPLAY value. An explicit -d remains intact
* and is validated below by Tk_CreateWindowFromPath. */
if (bu_vls_strlen(&dmp->i->dm_dName) == 0) {
bu_vls_printf(&dmp->i->dm_dName, "%s.%d", Tk_DisplayName(tkwin),
Tk_ScreenNumber(tkwin));
}
char *cp = strrchr(bu_vls_addr(&dmp->i->dm_pathName), '.');
if (dmp->i->dm_top) {
tv->xtkwin = Tk_CreateWindowFromPath(interp, tkwin,
+5 -7
View File
@@ -1040,13 +1040,11 @@ wgl_open(void *UNUSED(ctx), void *vinterp, int argc, const char *argv[])
++count;
if (bu_vls_strlen(&dmp->i->dm_dName) == 0) {
char *dp;
dp = getenv("DISPLAY");
if (dp)
bu_vls_strcpy(&dmp->i->dm_dName, dp);
else
bu_vls_strcpy(&dmp->i->dm_dName, ":0.0");
/* DISPLAY names an X server and is not meaningful to WGL. Unix-like
* shells on Windows may nevertheless export it, so use the screen of
* the Tk window that supplies the native HWND. */
bu_vls_printf(&dmp->i->dm_dName, "%s.%d", Tk_DisplayName(tkwin),
Tk_ScreenNumber(tkwin));
}
/* initialize dm specific variables */
+70 -90
View File
@@ -247,41 +247,19 @@ rt_in_rpp(struct xray *rp,
}
/* A name alone cannot distinguish transformed instances of a solid. */
static struct soltab *
rt_find_solid_with_mat(const struct rt_i *rtip,
const struct directory *dp, const mat_t mat)
{
struct soltab *stp;
RT_VISIT_ALL_SOLTABS_START(stp, (struct rt_i *)rtip) {
if (stp->st_dp != dp)
continue;
const fastf_t *st_mat = stp->st_matp ?
stp->st_matp : bn_mat_identity;
if (bn_mat_is_equal(mat, st_mat, &rtip->rti_tol))
return stp;
} RT_VISIT_ALL_SOLTABS_END;
return NULL;
}
/**
* Traverse the original database tree while tracking member transforms.
* Traverse the passed tree using rt_db_internals to show the way
* This function supports rt_bound_internal and is internal to librt
*
* Returns 0 on success, -1 if no bounds can be computed.
* Returns -
* 0 success
* -1 failure (tree_min and tree_max may have been altered)
*/
static int
rt_traverse_tree_mat(struct rt_i *rtip, const union tree *tp,
fastf_t *tree_min, fastf_t *tree_max,
const mat_t mat)
int
rt_traverse_tree(struct rt_i *rtip, const union tree *tp, fastf_t *tree_min, fastf_t *tree_max)
{
vect_t r_min, r_max; /* rpp for right side of tree */
if (!tp)
return -1;
RT_CK_TREE(tp);
switch (tp->tr_op) {
@@ -291,8 +269,6 @@ rt_traverse_tree_mat(struct rt_i *rtip, const union tree *tp,
const struct soltab *stp;
stp = tp->tr_a.tu_stp;
if (!stp)
return -1;
RT_CK_SOLTAB(stp);
if (stp->st_aradius <= 0) {
bu_log("rt_traverse_tree: encountered dead solid '%s'\n",
@@ -317,20 +293,16 @@ rt_traverse_tree_mat(struct rt_i *rtip, const union tree *tp,
case OP_XOR:
case OP_UNION:
/* BINARY type -- expand to contain both */
if (rt_traverse_tree_mat(rtip, tp->tr_b.tb_left,
tree_min, tree_max, mat) < 0 ||
rt_traverse_tree_mat(rtip, tp->tr_b.tb_right,
r_min, r_max, mat) < 0)
if (rt_traverse_tree(rtip, tp->tr_b.tb_left, tree_min, tree_max) < 0 ||
rt_traverse_tree(rtip, tp->tr_b.tb_right, r_min, r_max) < 0)
return -1;
VMIN(tree_min, r_min);
VMAX(tree_max, r_max);
break;
case OP_INTERSECT:
/* BINARY type -- find common area only */
if (rt_traverse_tree_mat(rtip, tp->tr_b.tb_left,
tree_min, tree_max, mat) < 0 ||
rt_traverse_tree_mat(rtip, tp->tr_b.tb_right,
r_min, r_max, mat) < 0)
if (rt_traverse_tree(rtip, tp->tr_b.tb_left, tree_min, tree_max) < 0 ||
rt_traverse_tree(rtip, tp->tr_b.tb_right, r_min, r_max) < 0)
return -1;
/* min = largest min, max = smallest max */
VMAX(tree_min, r_min);
@@ -341,8 +313,7 @@ rt_traverse_tree_mat(struct rt_i *rtip, const union tree *tp,
* rt_gettree's subtractor shaker may have already discarded a
* disjoint B (and its soltab) from the prepared tree, while this
* routine may be walking the original database tree. */
if (rt_traverse_tree_mat(rtip, tp->tr_b.tb_left,
tree_min, tree_max, mat) < 0)
if (rt_traverse_tree(rtip, tp->tr_b.tb_left, tree_min, tree_max) < 0)
return -1;
break;
@@ -353,8 +324,6 @@ rt_traverse_tree_mat(struct rt_i *rtip, const union tree *tp,
case OP_DB_LEAF:
{
const struct soltab *stp;
struct directory *dp;
mat_t leaf_mat;
if (rtip == NULL) {
bu_log("rt_traverse_tree: A valid rtip was not passed for calculating bounds of '%s'\n",
@@ -362,44 +331,60 @@ rt_traverse_tree_mat(struct rt_i *rtip, const union tree *tp,
return -1;
}
MAT_COPY(leaf_mat, mat);
if (tp->tr_l.tl_mat)
bn_mat_mul(leaf_mat, mat, tp->tr_l.tl_mat);
/* Good to go */
dp = db_lookup(rtip->rti_dbip, tp->tr_l.tl_name,
LOOKUP_QUIET);
if (dp == RT_DIR_NULL)
return -1;
stp = rt_find_solid_with_mat(rtip, dp, leaf_mat);
/* Attempt to get a solid pointer, will fail for combs */
stp = rt_find_solid(rtip, tp->tr_l.tl_name);
if (stp == NULL) {
/* Recurse through combinations using their original
* trees. A primitive without a matching prepared
* instance has no valid bounds. */
/* It was a comb! get an internal format and
* repeat the whole thing that got us here in the
* 1st place
*/
struct rt_db_internal intern;
struct directory *dp;
struct rt_comb_internal *combp;
/* Get the directory pointer */
if ((dp=db_lookup(rtip->rti_dbip, tp->tr_l.tl_name, LOOKUP_QUIET)) == RT_DIR_NULL) {
bu_log("rt_traverse_tree: db_lookup(%s) failed", tp->tr_l.tl_name);
return -1;
}
/* Why does recursion work with the internal
* format ? The internal format does have the
* boolean op for a comb in the tr_a.tu_op field
* in the root node, even though it has no prims
* at the leaves. So recursive calls to load the
* prim further down the tree, will return the
* correct bb as we are going through the proper
* switch case in each step down the tree
*/
if (!rt_db_lookup_internal(rtip->rti_dbip, tp->tr_l.tl_name, &dp, &intern, LOOKUP_NOISY)) {
bu_log("rt_traverse_tree: rt_db_lookup_internal(%s) failed to get the internal form",
tp->tr_l.tl_name);
return -1;
}
if (intern.idb_minor_type != ID_COMBINATION) {
bu_log("rt_traverse_tree: no prepared instance"
" for '%s'\n", tp->tr_l.tl_name);
rt_db_free_internal(&intern);
/* The passed rt_db_internal should be a comb,
* prepare a rt_comb_internal
*/
if (intern.idb_minor_type == ID_COMBINATION) {
combp = (struct rt_comb_internal *)intern.idb_ptr;
} else {
/* if it's not a comb, then something else is
* cooking.
*/
bu_log("rt_traverse_tree: WARNING : rt_db_lookup_internal(%s) got the internal form of a primitive when it should not, the bounds may not be correct", tp->tr_l.tl_name);
return -1;
}
combp = (struct rt_comb_internal *)intern.idb_ptr;
RT_CK_COMB(combp);
int ret = rt_traverse_tree_mat(rtip, combp->tree,
tree_min, tree_max, leaf_mat);
rt_db_free_internal(&intern);
if (ret)
/* further down the rabbit hole */
if (rt_traverse_tree(rtip, combp->tree, tree_min, tree_max)) {
bu_log("rt_traverse_tree: rt_bound_tree() failed\n");
return -1;
}
} else {
/* Got a solid pointer, get bounds and return */
RT_CK_SOLTAB(stp);
@@ -423,24 +408,13 @@ rt_traverse_tree_mat(struct rt_i *rtip, const union tree *tp,
}
case OP_NOP:
/* An empty tree has no bounds to return. */
return -1;
/* Implies that this tree has nothing in it */
break;
}
return 0;
}
int
rt_traverse_tree(struct rt_i *rtip, const union tree *tp,
fastf_t *tree_min, fastf_t *tree_max)
{
mat_t mat;
MAT_IDN(mat);
return rt_traverse_tree_mat(rtip, tp, tree_min, tree_max, mat);
}
int
rt_bound_instance(point_t *bmin, point_t *bmax,
struct directory *dp,
@@ -498,8 +472,7 @@ rt_bound_internal(struct db_i *dbip, struct directory *dp,
struct rt_db_internal intern;
struct rt_comb_internal *combp;
vect_t tree_min, tree_max;
const union tree *tp;
union tree primitive_tree;
union tree *tp;
/* Initialize RPP bounds */
VSETALL(rpp_min, MAX_FASTF);
@@ -521,8 +494,7 @@ rt_bound_internal(struct db_i *dbip, struct directory *dp,
if (!rt_db_lookup_internal(dbip, dp->d_namep, &dp, &intern, LOOKUP_NOISY)) {
bu_log("rt_bound_internal: lookup failed for '%s'\n",
dp->d_namep);
bu_exit(1, "rt_bound_internal: rt_db_lookup_internal(%s) failed to get the internal form", dp->d_namep);
rt_i_destroy(rtip);
return -1;
}
@@ -532,18 +504,26 @@ rt_bound_internal(struct db_i *dbip, struct directory *dp,
*/
if (intern.idb_minor_type == ID_COMBINATION) {
combp = (struct rt_comb_internal *)intern.idb_ptr;
RT_CK_COMB(combp);
tp = combp->tree;
} else {
/* A primitive uses its prepared solid directly. */
RT_TREE_INIT(&primitive_tree);
primitive_tree.tr_l.tl_op = OP_SOLID;
primitive_tree.tr_a.tu_stp = rt_find_solid(rtip, dp->d_namep);
tp = &primitive_tree;
/* A primitive was passed, construct a struct rt_comb_internal
* with a single leaf node.
*/
BU_ALLOC(combp, struct rt_comb_internal);
RT_COMB_INTERNAL_INIT(combp);
combp->region_flag = 0;
BU_GET(tp, union tree);
RT_TREE_INIT(tp);
tp->tr_l.tl_op = OP_SOLID;
tp->tr_l.tl_name = bu_strdup("dummy");
tp->tr_l.tl_mat = (matp_t)NULL;
tp->tr_a.tu_stp = rt_find_solid(rtip, dp->d_namep);
combp->tree = tp;
}
if (rt_traverse_tree(rtip, tp, tree_min, tree_max)) {
bu_log("rt_bound_internal: tree traversal failed\n");
RT_CK_COMB(combp);
if (rt_traverse_tree(rtip, combp->tree, tree_min, tree_max)) {
bu_log("rt_bound_internal: rt_bound_tree() failed\n");
rt_db_free_internal(&intern);
rt_i_destroy(rtip);
return -1;
+2 -2
View File
@@ -111,7 +111,7 @@ hlbvh_init_pool(size_t n_primatives) {
}
/* utility functions */
static uint32_t left_shift3(uint32_t x)
static inline uint32_t left_shift3(uint32_t x)
{
BU_ASSERT(x <= (1 << 10));
if (x == (1 << 10)) --x;
@@ -299,7 +299,7 @@ maximum_extent(const fastf_t b[6])
return 2;
}
static int
static inline int
pred(const struct bvh_build_node *node, fastf_t *centroid_bounds,
uint8_t dim, long min_cost_split_bucket)
{
+1 -1
View File
@@ -730,7 +730,7 @@ bot_makesegs_specific(hit_da *hits,
/* r_min can describe a spatial partition cell that begins inside this
* solid. Start BVH traversal just before the ray enters the BoT's own
* root box so entrance triangles behind the ray origin remain visible. */
static void
static inline void
bot_backed_origin(point_t b_pt, const struct xray *rp, const struct bvh_flat_node *root,
const vect_t inv_dir, const struct soltab *stp)
{
+1 -1
View File
@@ -517,7 +517,7 @@ rt_metaball_vshot(struct soltab *stp[], struct xray *rp[], struct seg *segp, int
}
static void
inline void
rt_metaball_norm_internal(vect_t *n, point_t *p, struct rt_metaball_internal *mb)
{
struct wdb_metaball_pnt *mbpt;
+1
View File
@@ -27,6 +27,7 @@ __BEGIN_DECLS
int rt_metaball_bbox(struct rt_db_internal *ip, point_t *min, point_t *max, const struct bn_tol *tol);
fastf_t rt_metaball_get_bounding_sphere(point_t *center, fastf_t threshold, struct rt_metaball_internal *mb);
int rt_metaball_find_intersection(point_t *intersect, const struct rt_metaball_internal *mb, const point_t *a, const point_t *b, fastf_t step, const fastf_t finalstep);
void rt_metaball_norm_internal(vect_t *n, point_t *p, struct rt_metaball_internal *mb);
__END_DECLS
#endif /* LIBRT_PRIMITIVES_METABALL_METABALL_H */
+1 -1
View File
@@ -33,7 +33,7 @@
#define PART_SPHERE_HEIGHT_RATIO 0.001
#define PART_CYLINDER_RADIUS_RATIO 0.001
static int
static inline int
part_update_type(struct rt_part_internal *part)
{
if (!part || !isfinite(part->part_vrad) ||
+14 -20
View File
@@ -72,15 +72,10 @@ brlcad_add_test(NAME rt_tree_prune COMMAND rt_tree_prune)
brlcad_addexec(rt_reprep_prune reprep_prune.c "librt;libwdb;libbu;${M_LIBRARY}" TEST)
# Note - this feature is not available in a BRLCAD_ENABLE_RUNTIME_DEBUG=OFF
# build, since it has an unavoidable performance overhead in the hot loop to
# check if the setting is enabled.
if (BRLCAD_ENABLE_RUNTIME_DEBUG)
brlcad_addexec(rt_rtcmp_capture rtcmp_capture.c "librt;libwdb;libbu;${M_LIBRARY}" TEST)
brlcad_add_test(NAME rt_rtcmp_capture COMMAND rt_rtcmp_capture)
brlcad_add_test(NAME rt_rtcmp_capture_primitives COMMAND rt_rtcmp_capture primitives)
brlcad_add_test(NAME rt_reprep_prune COMMAND rt_reprep_prune)
endif()
brlcad_addexec(rt_rtcmp_capture rtcmp_capture.c "librt;libwdb;libbu;${M_LIBRARY}" TEST)
brlcad_add_test(NAME rt_rtcmp_capture COMMAND rt_rtcmp_capture)
brlcad_add_test(NAME rt_rtcmp_capture_primitives COMMAND rt_rtcmp_capture primitives)
brlcad_add_test(NAME rt_reprep_prune COMMAND rt_reprep_prune)
brlcad_addexec(rt_submodel_xform submodel_xform.c "librt;libwdb;libbu;${M_LIBRARY}" TEST)
brlcad_add_test(NAME rt_submodel_xform COMMAND rt_submodel_xform)
@@ -217,37 +212,36 @@ brlcad_add_test(NAME rt_metaball_adjust COMMAND rt_metaball_adjust)
set(
distcheck_files
CMakeLists.txt
arb_intersect.g
ars_inside.c
arb_intersect.g
binary_attribute.c
binunif.c
bound_internal.c
brep_boolean_tests.g
brep_io.cpp
bound_internal.c
crofton.c
cyclic_tests.g
datum_annot_semantics.c
db_name.c
default_object.c
datum_annot_semantics.c
dsp_raytrace_check.c
dsp_sa_vol_check.c
primitive_brep.cpp
reprep_prune.c
brep_boolean_tests.g
cyclic_tests.g
extreme_ssi_test.g
invalid_inmem.c
lcomb_large.c
matrix_tests.g
metaball_adjust.c
nurbs_surfaces.g
pnts_bounds.c
prim_tess.c
primitive_brep.cpp
reprep_prune.c
rt_datum.c
rt_perturb.c
rtcmp_capture.c
search_stress.c
sketch.g
static_init.cpp
sketch.g
submodel_xform.c
prim_tess.c
pnts_bounds.c
tess_timing.c
tree_prune.c
vds_tree.c
-63
View File
@@ -37,7 +37,6 @@ main(int UNUSED(argc), const char **argv)
point_t bmin, bmax;
point_t expected_min = {-1.0, -1.0, -1.0};
point_t expected_max = { 1.0, 1.0, 1.0};
mat_t translated;
int ret = 1;
bu_setprogname(argv[0]);
@@ -76,68 +75,6 @@ main(int UNUSED(argc), const char **argv)
if (!VNEAR_EQUAL(bmax, expected_max, BN_TOL_DIST))
goto done;
dp = db_lookup(dbip, "left.s", LOOKUP_QUIET);
if (dp == RT_DIR_NULL || rt_bound_internal(dbip, dp, bmin, bmax))
goto done;
if (!VNEAR_EQUAL(bmin, expected_min, BN_TOL_DIST) ||
!VNEAR_EQUAL(bmax, expected_max, BN_TOL_DIST))
goto done;
BU_LIST_INIT(&wm.l);
if (mk_comb(wdbp, "empty.c", &wm.l, 0, NULL, NULL, NULL,
0, 0, 0, 0, 0, 0, 0))
goto done;
dp = db_lookup(dbip, "empty.c", LOOKUP_QUIET);
if (dp == RT_DIR_NULL ||
rt_bound_internal(dbip, dp, bmin, bmax) == 0)
goto done;
BU_LIST_INIT(&wm.l);
if (!mk_addmember("empty.c", &wm.l, NULL, WMOP_UNION))
goto done;
if (mk_lcomb(wdbp, "nested.c", &wm, 0, NULL, NULL, NULL, 0))
goto done;
dp = db_lookup(dbip, "nested.c", LOOKUP_QUIET);
if (dp == RT_DIR_NULL ||
rt_bound_internal(dbip, dp, bmin, bmax) == 0)
goto done;
MAT_IDN(translated);
MAT_DELTAS(translated, 20.0, 0.0, 0.0);
BU_LIST_INIT(&wm.l);
if (!mk_addmember("left.s", &wm.l, NULL, WMOP_UNION) ||
!mk_addmember("left.s", &wm.l, translated, WMOP_UNION))
goto done;
if (mk_lcomb(wdbp, "instanced.r", &wm, 1, NULL, NULL, NULL, 0))
goto done;
dp = db_lookup(dbip, "instanced.r", LOOKUP_QUIET);
if (dp == RT_DIR_NULL || rt_bound_internal(dbip, dp, bmin, bmax))
goto done;
VSET(expected_max, 21.0, 1.0, 1.0);
if (!VNEAR_EQUAL(bmin, expected_min, BN_TOL_DIST) ||
!VNEAR_EQUAL(bmax, expected_max, BN_TOL_DIST))
goto done;
BU_LIST_INIT(&wm.l);
if (!mk_addmember("left.s", &wm.l, translated, WMOP_UNION))
goto done;
if (mk_lcomb(wdbp, "child.c", &wm, 0, NULL, NULL, NULL, 0))
goto done;
MAT_DELTAS(translated, 10.0, 0.0, 0.0);
BU_LIST_INIT(&wm.l);
if (!mk_addmember("child.c", &wm.l, translated, WMOP_UNION))
goto done;
if (mk_lcomb(wdbp, "parent.r", &wm, 1, NULL, NULL, NULL, 0))
goto done;
dp = db_lookup(dbip, "parent.r", LOOKUP_QUIET);
if (dp == RT_DIR_NULL || rt_bound_internal(dbip, dp, bmin, bmax))
goto done;
VSET(expected_min, 29.0, -1.0, -1.0);
VSET(expected_max, 31.0, 1.0, 1.0);
if (!VNEAR_EQUAL(bmin, expected_min, BN_TOL_DIST) ||
!VNEAR_EQUAL(bmax, expected_max, BN_TOL_DIST))
goto done;
ret = 0;
done:
-64
View File
@@ -85,69 +85,6 @@ proc exercise_object_lifecycle {class object args} {
}
}
proc exercise_panedwindow_bindings {} {
set pane_size 200
set drag_distance 20
set native_motion_binding [bind Panedwindow <Motion>]
toplevel .panes
foreach orientation {horizontal vertical} {
set pane .panes.$orientation
iwidgets::panedwindow $pane -orient $orientation \
-width $pane_size -height $pane_size -showhandle 0
$pane add first -minimum 0 -margin 0
$pane add second -minimum 0 -margin 0
pack $pane -side left -fill both -expand yes
}
panedwindow .panes.native -width $pane_size -height $pane_size
foreach name {first second} {
frame .panes.native.$name
.panes.native add .panes.native.$name
}
pack .panes.native -side left -fill both -expand yes
update
# Hull events must not invoke native Tk handlers on Iwidgets objects.
foreach pane {.panes.horizontal .panes.vertical .panes.native} {
foreach event {
<Motion> <Leave>
<ButtonPress-1> <B1-Motion> <ButtonRelease-1>
<ButtonPress-2> <B2-Motion> <ButtonRelease-2>
} {
event generate $pane $event -x 1 -y 1
}
update
assert_equal "$pane pointer events" $::background_errors {}
}
assert_equal "native panedwindow motion binding" \
[bind Panedwindow <Motion>] $native_motion_binding
# Removing the hull's class tag must retain Iwidgets' sash dragging.
foreach orientation {horizontal vertical} {
set pane .panes.$orientation
set before [$pane fraction]
set sash [$pane component sash1]
set x 0
set y 0
if {$orientation eq "horizontal"} {
set y $drag_distance
} else {
set x $drag_distance
}
event generate $sash <ButtonPress-1> -x 0 -y 0
event generate $sash <B1-Motion> -x $x -y $y
event generate $sash <B1-ButtonRelease-1> -x $x -y $y
update
if {[lindex [$pane fraction] 0] <= [lindex $before 0]} {
fail "$orientation panedwindow sash did not move"
}
assert_equal "$orientation sash events" $::background_errors {}
}
destroy .panes
update
}
proc require_at_least {package minimum} {
set version [package require $package $minimum]
if {[package vcompare $version $minimum] < 0} {
@@ -165,7 +102,6 @@ set tk_version [require_at_least Tk 8.6]
set itcl_version [require_at_least Itcl 4.3.0]
set itk_version [require_at_least Itk 4.2.3]
set iwidgets_version [require_at_least Iwidgets 4.1.1]
exercise_panedwindow_bindings
interp alias {} Hierarchy {} ::iwidgets::Hierarchy
interp alias {} scrolledlistbox {} ::iwidgets::scrolledlistbox
+91 -7
View File
@@ -340,6 +340,26 @@ f_attach(ClientData clientData, Tcl_Interp *interpreter, int argc, const char *a
}
#ifdef HAVE_TK
static int
mged_restore_display_env(Tcl_Interp *interp, Tcl_Obj *saved_display)
{
int status;
if (saved_display != NULL) {
status = (Tcl_SetVar2Ex(interp, "env", "DISPLAY", saved_display,
TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG) != NULL) ? TCL_OK : TCL_ERROR;
Tcl_DecrRefCount(saved_display);
return status;
}
status = Tcl_UnsetVar2(interp, "env", "DISPLAY",
TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG);
return status;
}
#endif
int
gui_setup(struct mged_state *s, const char *dstr)
{
@@ -348,6 +368,7 @@ gui_setup(struct mged_state *s, const char *dstr)
#ifdef HAVE_TK
Tk_GenericProc *handler = doEvent;
Tcl_Obj *saved_display = NULL;
#endif
/* initialize only once */
if (tkwin != NULL)
@@ -355,24 +376,83 @@ gui_setup(struct mged_state *s, const char *dstr)
Tcl_ResetResult(s->interp);
/* set DISPLAY to dstr */
if (dstr != (char *)NULL) {
Tcl_SetVar(s->interp, "env(DISPLAY)", dstr, TCL_GLOBAL_ONLY);
#ifdef HAVE_TK
/* Tk has no display-name argument in its C initialization API. For an
* explicit MGED -d/loadtk argument, env(DISPLAY) is therefore the only
* portable way to select an X11 display before Tk_Init. Do not do this
* for ambient process state: X11 Tk already reads DISPLAY itself, and
* native Win32/Aqua Tk deliberately ignores that X11-only variable. */
if (dstr != NULL) {
saved_display = Tcl_GetVar2Ex(s->interp, "env", "DISPLAY",
TCL_GLOBAL_ONLY);
if (saved_display != NULL)
Tcl_IncrRefCount(saved_display);
if (Tcl_SetVar2(s->interp, "env", "DISPLAY", dstr,
TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG) == NULL) {
if (saved_display != NULL)
Tcl_DecrRefCount(saved_display);
return TCL_ERROR;
}
}
#ifdef HAVE_TK
/* This runs the tk.tcl script */
if (Tk_Init(s->interp) == TCL_ERROR) {
const char *result = Tcl_GetStringResult(s->interp);
/* hack to avoid a stupid Tk error */
if (bu_strncmp(result, "this isn't a Tk applicationcouldn't", 35) == 0) {
result = (result + 27);
Tcl_ResetResult(s->interp);
Tcl_AppendResult(s->interp, result, (char *)NULL);
Tcl_SetObjResult(s->interp, Tcl_NewStringObj(result + 27, -1));
}
if (dstr != NULL) {
Tcl_SavedResult init_result;
/* Environment restoration is cleanup on this path; retain Tk's
* diagnostic even if an unusual Tcl environment trace rejects it. */
Tcl_SaveResult(s->interp, &init_result);
(void)mged_restore_display_env(s->interp, saved_display);
Tcl_RestoreResult(s->interp, &init_result);
}
return TCL_ERROR;
}
if (dstr != NULL) {
int is_x11;
if (Tcl_Eval(s->interp, "tk windowingsystem") != TCL_OK) {
Tcl_SavedResult windowing_result;
Tcl_SaveResult(s->interp, &windowing_result);
(void)mged_restore_display_env(s->interp, saved_display);
Tcl_RestoreResult(s->interp, &windowing_result);
return TCL_ERROR;
}
is_x11 = BU_STR_EQUAL(Tcl_GetStringResult(s->interp), "x11");
Tcl_ResetResult(s->interp);
if (is_x11) {
/* X11 may use the explicit display for subsequently created
* toplevels and display managers, so keep it in the environment. */
if (saved_display != NULL)
Tcl_DecrRefCount(saved_display);
} else {
Tk_Window display_probe;
/* Win32 and Aqua cannot be redirected by DISPLAY. Restore the
* caller's environment, then let Tk validate whether the explicit
* name denotes the already initialized native screen. This accepts
* native aliases such as :0/:0.0 but reports unsupported alternate
* displays instead of silently opening a different screen. */
if (mged_restore_display_env(s->interp, saved_display) != TCL_OK)
return TCL_ERROR;
display_probe = Tk_CreateWindowFromPath(s->interp,
Tk_MainWindow(s->interp), ".__mged_display_probe", dstr);
if (display_probe == NULL)
return TCL_ERROR;
Tk_DestroyWindow(display_probe);
Tcl_ResetResult(s->interp);
}
}
/* Initialize [incr Tk] */
if (Tcl_Eval(s->interp, "package require Itk") != TCL_OK) {
return TCL_ERROR;
@@ -385,6 +465,10 @@ gui_setup(struct mged_state *s, const char *dstr)
}
#endif
#ifndef HAVE_TK
(void)dstr;
#endif
/* Initialize the Iwidgets package */
if (Tcl_Eval(s->interp, "package require Iwidgets") != TCL_OK) {
return TCL_ERROR;
+30 -16
View File
@@ -2446,6 +2446,29 @@ apply_cli_overrides(struct mged_state *s, struct mged_cli_overrides *cl)
if (cli_dbl_is_set(cl->eye_sep_dist)) CLI_SETVAR_DBL("eye_sep_dist", cl->eye_sep_dist);
/* --- Tcl mged_default array entries ---------------------------------- */
if (cl->dpy_string) {
const char *display = cl->dpy_string;
#ifdef HAVE_TK
struct bu_vls tk_screen = BU_VLS_INIT_ZERO;
Tk_Window main_window = Tk_MainWindow(s->interp);
/* Apply -d after .mgedrc just like the other command-line overrides.
* Once Tk is initialized, store its canonical screen name rather than
* the spelling used to select it (for example, :0 and :0.0 may denote
* the same native screen). Classic/headless mode retains the original
* value for a later display-manager attach. */
if (main_window != NULL) {
bu_vls_printf(&tk_screen, "%s.%d", Tk_DisplayName(main_window),
Tk_ScreenNumber(main_window));
display = bu_vls_cstr(&tk_screen);
}
#endif
Tcl_SetVar2(s->interp, "mged_default", "display", display,
TCL_GLOBAL_ONLY);
#ifdef HAVE_TK
bu_vls_free(&tk_screen);
#endif
}
if (cl->dm_type)
Tcl_SetVar2(s->interp, "mged_default", "dm_type", cl->dm_type, TCL_GLOBAL_ONLY);
if (cl->geom)
@@ -2694,7 +2717,7 @@ main(int argc, char *argv[])
struct bu_opt_desc opt_defs[54];
/* ---- Existing short options, now with long aliases ---- */
BU_OPT(opt_defs[0], "a", "attach", "type", bu_opt_str, &cl.attach, "display manager attach target");
BU_OPT(opt_defs[1], "d", "display", "string", bu_opt_str, &cl.dpy_string, "X display string");
BU_OPT(opt_defs[1], "d", "display", "screen", bu_opt_str, &cl.dpy_string, "Tk display and screen name");
BU_OPT(opt_defs[2], "r", "read-only", "", NULL, &cl.read_only, "open database read-only");
BU_OPT(opt_defs[3], "p", "pipe", "", NULL, &cl.pipe_mode, "pipe mode (emit CMD_DONE sentinels)");
BU_OPT(opt_defs[4], "c", "classic", "", NULL, &cl.classic_mode, "classic text-only mode");
@@ -3044,9 +3067,6 @@ main(int argc, char *argv[])
(void)Tcl_Eval(s->interp, bu_vls_addr(&s->input_str));
bu_vls_trunc(&s->input_str, 0);
if (!s->dpy_string)
s->dpy_string = getenv("DISPLAY");
/* show ourselves */
if (s->interactive) {
if (s->classic_mged) {
@@ -3068,23 +3088,17 @@ main(int argc, char *argv[])
/* start up the gui */
int status;
struct bu_vls vls = BU_VLS_INIT_ZERO;
struct bu_vls error = BU_VLS_INIT_ZERO;
(void)Tcl_Eval(s->interp, "set mged_console_mode gui");
bu_vls_strcpy(&vls, "loadtk");
if (s->dpy_string)
bu_vls_printf(&vls, " %s", s->dpy_string);
status = Tcl_Eval(s->interp, bu_vls_addr(&vls));
/* An unset -d is deliberately passed as NULL. Tk already knows how
* to select its platform display: X11 consults DISPLAY, while the
* Win32 and Aqua backends select their native display. Treating an
* inherited DISPLAY value as an explicit request breaks native Tk
* when Unix-like shells export an X11 placeholder. */
status = gui_setup(s, s->dpy_string);
bu_vls_strcpy(&error, Tcl_GetStringResult(s->interp));
bu_vls_free(&vls);
if (status != TCL_OK && !s->dpy_string) {
/* failed to load tk, try localhost X11 if DISPLAY was not set */
status = Tcl_Eval(s->interp, "loadtk :0");
}
if (status != TCL_OK) {
if (!run_in_foreground && use_pipe) {
+1 -1
View File
@@ -337,7 +337,7 @@ main(int ac, char *av[])
unsigned char ground_rgb[3];
unsigned char light_rgb[3];
double pitch_r[MAX_GEARS] = {0.0};
double pitch_r[MAX_GEARS];
double center_x[MAX_GEARS];
double total_span;
double max_outer;
+10 -29
View File
@@ -226,7 +226,7 @@ package provide Archer 1.0
method buildViewAxesPreferences {}
method doAboutArcher {}
method doarcherHelp {}
method handleMap {_window}
method handleMap {}
method handleBindingModeChange {_name1 _name2 _op}
method overrideBindingMode {_mode}
method updateOverrideBindingMode {_keysym}
@@ -427,7 +427,6 @@ package provide Archer 1.0
private {
variable mInstanceInit 1
variable mWindowMapped 0
}
}
@@ -529,7 +528,7 @@ package provide Archer 1.0
}
# resize and position window after it's drawn
bind [namespace tail $this] <Map> [::itcl::code $this handleMap %W]
bind [namespace tail $this] <Map> [::itcl::code $this handleMap]
}
@@ -4264,26 +4263,18 @@ proc title_node_handler {node} {
}
::itcl::body Archer::handleMap {_window} {
# Child windows also dispatch Map events through the toplevel's tag.
if {$_window ne [namespace tail $this]} {
return
}
set mWindowMapped 1
set geometry $mWindowGeometry
if {$geometry eq ""} {
set geometry $itk_option(-geometry)
}
if {$geometry ne ""} {
after idle [list wm geometry $_window $geometry]
::itcl::body Archer::handleMap {} {
if {$mWindowGeometry != ""} {
after idle "wm geometry [namespace tail $this] $mWindowGeometry"
} else {
after idle "wm geometry [namespace tail $this] $itk_option(-geometry)"
}
if {$mSeparateCommandWindow && $mCmdWindowGeometry != ""} {
after idle [list wm geometry $itk_component(sepcmdT) $mCmdWindowGeometry]
after idle [::itcl::code wm geometry $itk_component(sepcmdT) $mCmdWindowGeometry]
}
bind $_window <Map> {}
bind [namespace tail $this] <Map> {}
}
::itcl::body Archer::handleDisplayEscape {_dm} {
@@ -9360,17 +9351,7 @@ proc title_node_handler {node} {
puts $_pfile "set mVPaneToggle3 $mVPaneToggle3"
puts $_pfile "set mVPaneToggle5 $mVPaneToggle5"
# Before the first map, the hull's size only reflects unfinished layout.
if {$mWindowMapped} {
if {$ArcherCore::inheritFromToplevel} {
set mWindowGeometry [wm geometry [namespace tail $this]]
} else {
set mWindowGeometry [winfo geometry [namespace tail $this]]
}
}
if {$mWindowGeometry ne ""} {
puts $_pfile [list set mWindowGeometry $mWindowGeometry]
}
puts $_pfile "set mWindowGeometry [winfo geometry [namespace tail $this]]"
if {$mSeparateCommandWindow} {
puts $_pfile "set mCmdWindowGeometry [winfo geometry $itk_component(sepcmdT)]"
+3 -3
View File
@@ -1090,9 +1090,9 @@ namespace delete ::ArcherCoreBootstrap
wm withdraw [namespace tail $this]
}
if {![info exists env(DISPLAY)]} {
set env(DISPLAY) ":0"
}
# Tk has already selected its X11, Win32, or Aqua display. DISPLAY is an
# X11 input to that initialization, not portable application state; in
# particular, synthesizing :0 here can misdirect native Tk child windows.
set mImgDir [file join [bu_dir data] tclscripts archer images]
+2 -1
View File
@@ -165,7 +165,8 @@ proc secErrorDialog {root title text default args} {
update idletasks
# First frame consists of error icon and message
frame $base.frame\#1
frame $base.frame\#1 \
-class Panedwindow
pack $base.frame\#1 -fill x -anchor w
canvas $base.frame\#1.bitmap \
+1 -5
View File
@@ -25,11 +25,7 @@
#
if ![info exists mged_default(display)] {
if [info exists env(DISPLAY)] {
set mged_default(display) $env(DISPLAY)
} else {
set mged_default(display) :0
}
set mged_default(display) [winfo screen .]
}
if ![info exists mged_gui(mged,screen)] {
+1 -5
View File
@@ -24,11 +24,7 @@
#
if ![info exists mged_default(display)] {
if [info exists env(DISPLAY)] {
set mged_default(display) $env(DISPLAY)
} else {
set mged_default(display) :0
}
set mged_default(display) [winfo screen .]
}
if ![info exists mged_gui(mged,screen)] {
+1 -6
View File
@@ -27,10 +27,6 @@ if ![info exists mged_players] {
set mged_players {}
}
if ![info exists env(DISPLAY)] {
set env(DISPLAY) ":0"
}
#==============================================================================
# Ensure that tk.tcl has been loaded already via mged command 'loadtk'.
#==============================================================================
@@ -47,11 +43,10 @@ if { [info exists tk_strictMotif] == 0 } {
# MGED html manual directory search order precedence should be:
# MGED_HTML_DIR
# [bu_dir data]/html/manuals/mged
# [bu_dir doc]/html/manuals/mged
if ![info exists mged_default(html_dir)] {
set mged_default(html_dir) [file normalize [file join [bu_dir data] html manuals mged]]
set mged_default(html_dir) [file normalize [file join [bu_dir doc] html manuals mged]]
if {![file exists $mged_default(html_dir)]} {
set mged_default(html_dir) [file normalize [file join [bu_dir doc] html manuals mged]]
}
+1 -2
View File
@@ -154,8 +154,7 @@ proc dump_mged_state {fd} {
puts $fd "# Determines the border width in the geometry window"
puts $fd "set mged_default(bd) $mged_default(bd)"
puts $fd ""
puts $fd "# X display string used to determine the screen"
puts $fd "# on which to display the GUI's windows"
puts $fd "# Tk screen name used for the GUI's windows"
puts $fd "set mged_default(display) $mged_default(display)"
puts $fd ""
puts $fd "# Configures the GUI. Note - this is only"
+6 -7
View File
@@ -108,13 +108,12 @@ if {![info exists mged_default(config)]} {
set mged_default(config) b
}
if {[info exists env(DISPLAY)]} {
set mged_default(display) $env(DISPLAY)
} else {
if {![info exists mged_default(display)]} {
set mged_default(display) :0
}
set env(DISPLAY) $mged_default(display)
# DISPLAY is an X11 connection setting, not a portable Tk screen name. Tk is
# initialized before this script runs, so its canonical screen is authoritative
# on X11, Win32, and Aqua alike. Preserve a value supplied explicitly through
# .mgedrc or the gui command for multi-display X11 use.
if {![info exists mged_default(display)]} {
set mged_default(display) [winfo screen .]
}
if {![info exists mged_default(gdisplay)]} {