Compare commits

..

No commits in common. "de43670ec21c61738f63f3b5d84fe0af72e3abb2" and "21cb6859a2f00590586b96ad08d2c6c225f1a170" have entirely different histories.

440 changed files with 7915 additions and 23097 deletions

View file

@ -1 +0,0 @@
CMakePresets.json

View file

@ -1,19 +0,0 @@
Checks:
- '-*'
- 'bugprone-*'
- 'clang-analyzer-*'
- 'cppcoreguidelines-*'
- 'misc-*'
- 'modernize-*'
- 'performance-*'
- '-bugprone-easily-swappable-parameters'
- '-cppcoreguidelines-avoid-do-while'
- '-cppcoreguidelines-avoid-non-const-global-variables'
- '-cppcoreguidelines-pro-type-reinterpret-cast'
- '-cppcoreguidelines-pro-type-union-access'
- '-misc-include-cleaner'
- '-misc-non-private-member-variables-in-classes'
- '-misc-use-anonymous-namespace'
- '-modernize-return-braced-init-list'
- '-modernize-use-trailing-return-type'
FormatStyle: 'file'

View file

@ -11,7 +11,7 @@ on:
concurrency: concurrency:
# Cancel in-progress jobs for the same pull request # Cancel in-progress jobs for the same pull request
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} group: ${{ github.head_ref || github.run_id }}
cancel-in-progress: true cancel-in-progress: true
jobs: jobs:
@ -20,130 +20,61 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
include: include:
- name: windows_msvc2022_x64 - name: win64_msvc2022
os: windows-2022 os: windows-2022
build_type: Release build_type: Release
env_cc: '' env_cc: ''
env_cxx: '' env_cxx: ''
compiler: msvc compiler: msvc
cppflags: ''
ldflags: ''
msvc_arch: x64 msvc_arch: x64
msvc_version: 2022 msvc_version: 2022
qt_version: 6.9.2 qt_version: 6.7.2
qt_arch_aqt: win64_msvc2022_64 qt_arch_aqt: win64_msvc2019_64
qt_arch_dir: msvc2022_64 qt_arch_dir: msvc2019_64
qt_modules: qtimageformats qtmultimedia qtpositioning qtserialport qt_modules: qtimageformats qtmultimedia qtpositioning qtserialport
qt_tools: '' qt_tools: ''
conan_arch: x86_64
conan_compiler: Visual Studio
conan_compiler_version: 17
conan_compiler_runtime: --settings compiler.runtime=MD
conan_package_manager: '' conan_package_manager: ''
conan_profile: scwx-windows_msvc2022_x64
appimage_arch: ''
artifact_suffix: windows-x64 artifact_suffix: windows-x64
- name: linux_gcc_x64 - name: linux64_gcc
os: ubuntu-22.04 os: ubuntu-22.04
build_type: Release build_type: Release
env_cc: gcc-11 env_cc: gcc-11
env_cxx: g++-11 env_cxx: g++-11
compiler: gcc compiler: gcc
cppflags: '' qt_version: 6.7.2
ldflags: ''
qt_version: 6.9.2
qt_arch_aqt: linux_gcc_64 qt_arch_aqt: linux_gcc_64
qt_arch_dir: gcc_64 qt_arch_dir: gcc_64
qt_modules: qtimageformats qtmultimedia qtpositioning qtserialport qt_modules: qtimageformats qtmultimedia qtpositioning qtserialport
qt_tools: '' qt_tools: ''
conan_arch: x86_64
conan_compiler: gcc
conan_compiler_version: 11
conan_compiler_runtime: ''
conan_package_manager: --conf tools.system.package_manager:mode=install --conf tools.system.package_manager:sudo=True conan_package_manager: --conf tools.system.package_manager:mode=install --conf tools.system.package_manager:sudo=True
conan_profile: scwx-linux_gcc-11
appimage_arch: x86_64
artifact_suffix: linux-x64 artifact_suffix: linux-x64
compiler_packages: ''
- name: linux_clang_x64
os: ubuntu-24.04
build_type: Release
env_cc: clang-17
env_cxx: clang++-17
compiler: clang
cppflags: ''
ldflags: ''
qt_version: 6.9.2
qt_arch_aqt: linux_gcc_64
qt_arch_dir: gcc_64
qt_modules: qtimageformats qtmultimedia qtpositioning qtserialport
qt_tools: ''
conan_package_manager: --conf tools.system.package_manager:mode=install --conf tools.system.package_manager:sudo=True
conan_profile: scwx-linux_clang-17
appimage_arch: x86_64
artifact_suffix: linux-clang-x64
compiler_packages: clang-17
- name: linux_gcc_arm64
os: ubuntu-24.04-arm
build_type: Release
env_cc: gcc-11
env_cxx: g++-11
compiler: gcc
cppflags: ''
ldflags: ''
qt_version: 6.9.2
qt_arch_aqt: linux_gcc_arm64
qt_arch_dir: gcc_arm64
qt_modules: qtimageformats qtmultimedia qtpositioning qtserialport
qt_tools: ''
conan_package_manager: --conf tools.system.package_manager:mode=install --conf tools.system.package_manager:sudo=True
conan_profile: scwx-linux_gcc-11_armv8
appimage_arch: aarch64
artifact_suffix: linux-arm64
compiler_packages: g++-11
- name: macos_clang18_x64
os: macos-13
build_type: Release
env_cc: clang
env_cxx: clang++
compiler: clang
qt_version: 6.9.2
qt_arch_aqt: clang_64
qt_arch_dir: macos
qt_modules: qtimageformats qtmultimedia qtpositioning qtserialport
qt_tools: ''
conan_package_manager: ''
conan_profile: scwx-macos_clang-18
appimage_arch: ''
artifact_suffix: macos-x64
- name: macos_clang18_arm64
os: macos-14
build_type: Release
env_cc: clang
env_cxx: clang++
compiler: clang
qt_version: 6.9.2
qt_arch_aqt: clang_64
qt_arch_dir: macos
qt_modules: qtimageformats qtmultimedia qtpositioning qtserialport
qt_tools: ''
conan_package_manager: ''
conan_profile: scwx-macos_clang-18_armv8
appimage_arch: ''
artifact_suffix: macos-arm64
name: ${{ matrix.name }} name: ${{ matrix.name }}
env: env:
CC: ${{ matrix.env_cc }} CC: ${{ matrix.env_cc }}
CXX: ${{ matrix.env_cxx }} CXX: ${{ matrix.env_cxx }}
SCWX_VERSION: v0.5.1 SCWX_VERSION: v0.4.5
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Setup - name: Setup
run: git config --global core.longpaths true run: git config --global core.longpaths true
- name: Checkout - name: Checkout
uses: actions/checkout@v5 uses: actions/checkout@v4
with: with:
path: source path: source
submodules: recursive submodules: recursive
- name: Install Qt - name: Install Qt
uses: jdpurcell/install-qt-action@v5 uses: jurplel/install-qt-action@v3
env:
AQT_CONFIG: ${{ github.workspace }}/source/tools/aqt-settings.ini
with: with:
version: ${{ matrix.qt_version }} version: ${{ matrix.qt_version }}
arch: ${{ matrix.qt_arch_aqt }} arch: ${{ matrix.qt_arch_aqt }}
@ -158,79 +89,50 @@ jobs:
vsversion: ${{ matrix.msvc_version }} vsversion: ${{ matrix.msvc_version }}
- name: Setup Ubuntu Environment - name: Setup Ubuntu Environment
if: ${{ startsWith(matrix.os, 'ubuntu') }} if: matrix.os == 'ubuntu-22.04'
shell: bash shell: bash
run: | run: |
sudo apt-get install doxygen \ sudo apt-get install doxygen \
libfuse2 \ libfuse2 \
ninja-build \ ninja-build
wayland-protocols \
libwayland-dev \
libwayland-egl-backend-dev \
flatpak \
flatpak-builder \
${{ matrix.compiler_packages }}
- name: Setup macOS Environment
if: ${{ startsWith(matrix.os, 'macos') }}
shell: bash
run: |
brew install llvm@18
LLVM_PATH=$(brew --prefix llvm@18)
echo "CC=${LLVM_PATH}/bin/clang" >> $GITHUB_ENV
echo "CXX=${LLVM_PATH}/bin/clang++" >> $GITHUB_ENV
echo "CPPFLAGS=-I${LLVM_PATH}/include" >> $GITHUB_ENV
echo "LDFLAGS=-L${LLVM_PATH}/lib -L${LLVM_PATH}/lib/c++" >> $GITHUB_ENV
- name: Setup Python Environment - name: Setup Python Environment
shell: pwsh shell: pwsh
run: | run: |
pip install geopandas ` pip install geopandas `
GitPython ` GitPython
conan
- name: Cache Conan Packages
uses: actions/cache@v4
with:
path: ~/.conan2
key: build-${{ matrix.conan_profile }}-${{ hashFiles('./source/conanfile.py', './source/tools/conan/profiles/*') }}
- name: Install Conan Packages - name: Install Conan Packages
shell: pwsh shell: pwsh
run: | run: |
conan config install ` pip install "conan<2.0"
./source/tools/conan/profiles/${{ matrix.conan_profile }} ` conan profile new default --detect
-tf profiles conan install ./source/ `
mkdir build
cd build
mkdir conan
conan install ../source/ `
--remote conancenter ` --remote conancenter `
--build missing ` --build missing `
--profile:all ${{ matrix.conan_profile }} ` --settings arch=${{ matrix.conan_arch }} `
--settings:all build_type=${{ matrix.build_type }} ` --settings build_type=${{ matrix.build_type }} `
--output-folder ./conan/ ` --settings compiler="${{ matrix.conan_compiler }}" `
--settings compiler.version=${{ matrix.conan_compiler_version }} `
${{ matrix.conan_compiler_runtime }} `
${{ matrix.conan_package_manager }} ${{ matrix.conan_package_manager }}
- name: Build Supercell Wx - name: Build Supercell Wx
shell: pwsh shell: pwsh
run: | run: |
mkdir build
cd build cd build
cmake ../source/ ` cmake ../source/ `
-G Ninja ` -G Ninja `
-DCMAKE_BUILD_TYPE="${{ matrix.build_type }}" ` -DCMAKE_BUILD_TYPE="${{ matrix.build_type }}" `
-DCMAKE_PROJECT_TOP_LEVEL_INCLUDES="${{ github.workspace }}/source/external/cmake-conan/conan_provider.cmake" ` -DCMAKE_INSTALL_PREFIX="${{ github.workspace }}/supercell-wx"
-DCMAKE_INSTALL_PREFIX="${{ github.workspace }}/supercell-wx" `
-DCONAN_HOST_PROFILE="${{ matrix.conan_profile }}" `
-DCONAN_BUILD_PROFILE="${{ matrix.conan_profile }}"
ninja supercell-wx wxtest ninja supercell-wx wxtest
- name: Separate Debug Symbols (Linux) - name: Separate Debug Symbols (Linux)
if: ${{ startsWith(matrix.os, 'ubuntu') }} if: matrix.os == 'ubuntu-22.04'
shell: bash shell: bash
run: | run: |
cd build/ cd build/
cd Release/
cd bin/ cd bin/
objcopy --only-keep-debug supercell-wx supercell-wx.debug objcopy --only-keep-debug supercell-wx supercell-wx.debug
objcopy --strip-debug --strip-unneeded supercell-wx objcopy --strip-debug --strip-unneeded supercell-wx
@ -246,7 +148,7 @@ jobs:
cmake --install . --component supercell-wx cmake --install . --component supercell-wx
- name: Collect Artifacts - name: Collect Artifacts
if: ${{ startsWith(matrix.os, 'ubuntu') }} if: matrix.os == 'ubuntu-22.04'
shell: bash shell: bash
run: | run: |
pushd supercell-wx/ pushd supercell-wx/
@ -259,8 +161,6 @@ jobs:
cd plugins/ cd plugins/
mkdir -p sqldrivers/ mkdir -p sqldrivers/
cp "${RUNNER_WORKSPACE}/Qt/${{ matrix.qt_version }}/${{ matrix.qt_arch_dir }}/plugins/sqldrivers/libqsqlite.so" sqldrivers/ cp "${RUNNER_WORKSPACE}/Qt/${{ matrix.qt_version }}/${{ matrix.qt_arch_dir }}/plugins/sqldrivers/libqsqlite.so" sqldrivers/
mkdir -p platforms/
cp ${RUNNER_WORKSPACE}/Qt/${{ matrix.qt_version }}/${{ matrix.qt_arch_dir }}/plugins/platforms/libqwayland* platforms/
cd .. cd ..
popd popd
tar -czf supercell-wx-${{ matrix.artifact_suffix }}.tar.gz supercell-wx/ tar -czf supercell-wx-${{ matrix.artifact_suffix }}.tar.gz supercell-wx/
@ -277,23 +177,23 @@ jobs:
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: supercell-wx-debug-${{ matrix.artifact_suffix }} name: supercell-wx-debug-${{ matrix.artifact_suffix }}
path: ${{ github.workspace }}/build/Release/bin/*.pdb path: ${{ github.workspace }}/build/bin/*.pdb
- name: Upload Artifacts (Linux) - name: Upload Artifacts (Linux)
if: ${{ startsWith(matrix.os, 'ubuntu') }} if: matrix.os == 'ubuntu-22.04'
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: supercell-wx-${{ matrix.artifact_suffix }} name: supercell-wx-${{ matrix.artifact_suffix }}
path: ${{ github.workspace }}/supercell-wx-${{ matrix.artifact_suffix }}.tar.gz path: ${{ github.workspace }}/supercell-wx-${{ matrix.artifact_suffix }}.tar.gz
- name: Upload Debug Artifacts (Linux) - name: Upload Debug Artifacts (Linux)
if: ${{ startsWith(matrix.os, 'ubuntu') }} if: matrix.os == 'ubuntu-22.04'
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: supercell-wx-debug-${{ matrix.artifact_suffix }} name: supercell-wx-debug-${{ matrix.artifact_suffix }}
path: | path: |
${{ github.workspace }}/build/Release/bin/*.debug ${{ github.workspace }}/build/bin/*.debug
${{ github.workspace }}/build/Release/lib/*.debug ${{ github.workspace }}/build/lib/*.debug
- name: Build Installer (Windows) - name: Build Installer (Windows)
if: matrix.os == 'windows-2022' if: matrix.os == 'windows-2022'
@ -310,90 +210,42 @@ jobs:
path: ${{ github.workspace }}/build/supercell-wx-*.msi* path: ${{ github.workspace }}/build/supercell-wx-*.msi*
- name: Build AppImage (Linux) - name: Build AppImage (Linux)
if: ${{ startsWith(matrix.os, 'ubuntu') }} if: matrix.os == 'ubuntu-22.04'
env: env:
INSTALL_DIR: ${{ github.workspace }}/supercell-wx/ APPIMAGE_DIR: ${{ github.workspace }}/supercell-wx/
APPIMAGE_DIR: ${{ github.workspace }}/supercell-wx-appimage/ LDAI_UPDATE_INFORMATION: gh-releases-zsync|dpaulat|supercell-wx|latest|*x86_64.AppImage.zsync
LDAI_UPDATE_INFORMATION: gh-releases-zsync|dpaulat|supercell-wx|latest|*${{ matrix.appimage_arch }}.AppImage.zsync LDAI_OUTPUT: supercell-wx-${{ env.SCWX_VERSION }}-x86_64.AppImage
LDAI_OUTPUT: supercell-wx-${{ env.SCWX_VERSION }}-${{ matrix.appimage_arch }}.AppImage
LINUXDEPLOY_OUTPUT_APP_NAME: supercell-wx LINUXDEPLOY_OUTPUT_APP_NAME: supercell-wx
LINUXDEPLOY_OUTPUT_VERSION: ${{ env.SCWX_VERSION }} LINUXDEPLOY_OUTPUT_VERSION: ${{ env.SCWX_VERSION }}
shell: bash shell: bash
run: | run: |
wget https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-${{ matrix.appimage_arch }}.AppImage wget https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage
chmod +x linuxdeploy-${{ matrix.appimage_arch }}.AppImage chmod +x linuxdeploy-x86_64.AppImage
cp "${{ github.workspace }}/source/scwx-qt/res/icons/scwx-256.png" supercell-wx.png cp "${{ github.workspace }}/source/scwx-qt/res/icons/scwx-256.png" supercell-wx.png
cp "${{ github.workspace }}/source/scwx-qt/res/linux/supercell-wx.desktop" . cp "${{ github.workspace }}/source/scwx-qt/res/linux/supercell-wx.desktop" .
cp -r "${{ env.INSTALL_DIR }}" "${{ env.APPIMAGE_DIR }}"
pushd "${{ env.APPIMAGE_DIR }}" pushd "${{ env.APPIMAGE_DIR }}"
mkdir -p usr/ mkdir -p usr/
mv bin/ usr/ mv bin/ usr/
mv lib/ usr/ mv lib/ usr/
mv plugins/ usr/ mv plugins/ usr/
popd popd
./linuxdeploy-${{ matrix.appimage_arch }}.AppImage --appdir ${{ env.APPIMAGE_DIR }} -i supercell-wx.png -d supercell-wx.desktop ./linuxdeploy-x86_64.AppImage --appdir ${{ env.APPIMAGE_DIR }} -i supercell-wx.png -d supercell-wx.desktop
./linuxdeploy-${{ matrix.appimage_arch }}.AppImage --appdir ${{ env.APPIMAGE_DIR }} --output appimage ./linuxdeploy-x86_64.AppImage --appdir ${{ env.APPIMAGE_DIR }} --output appimage
rm -f linuxdeploy-${{ matrix.appimage_arch }}.AppImage rm -f linuxdeploy-x86_64.AppImage
- name: Upload AppImage (Linux) - name: Upload AppImage (Linux)
if: ${{ startsWith(matrix.os, 'ubuntu') }} if: matrix.os == 'ubuntu-22.04'
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: supercell-wx-appimage-${{ matrix.artifact_suffix }} name: supercell-wx-appimage-x64
path: ${{ github.workspace }}/*-${{ matrix.appimage_arch }}.AppImage* path: ${{ github.workspace }}/*-x86_64.AppImage*
- name: Build FlatPak (Linux)
if: ${{ startsWith(matrix.os, 'ubuntu') }}
env:
INSTALL_DIR: ${{ github.workspace }}/supercell-wx/
FLATPAK_DIR: ${{ github.workspace }}/supercell-wx-flatpak/
shell: bash
run: |
cp -r ${{ env.INSTALL_DIR }} ${{ env.FLATPAK_DIR }}
# Copy krb5 libraries to flatpak
cp /usr/lib/*/libkrb5.so* \
/usr/lib/*/libkrb5support.so* \
/usr/lib/*/libgssapi_krb5.so* \
/usr/lib/*/libk5crypto.so* \
/usr/lib/*/libkeyutils.so* \
${{ env.FLATPAK_DIR }}/lib
flatpak remote-add --if-not-exists --user flathub https://dl.flathub.org/repo/flathub.flatpakrepo
flatpak-builder --force-clean \
--user \
--install-deps-from=flathub \
--repo=flatpak-repo \
--install flatpak-build \
${{ github.workspace }}/source/tools/net.supercellwx.app.yml
flatpak build-bundle flatpak-repo supercell-wx.flatpak net.supercellwx.app
- name: Upload FlatPak (Linux)
if: ${{ startsWith(matrix.os, 'ubuntu') }}
uses: actions/upload-artifact@v4
with:
name: supercell-wx-flatpak-${{ matrix.artifact_suffix }}
path: ${{ github.workspace }}/supercell-wx.flatpak
- name: Build Disk Image (macOS)
if: ${{ startsWith(matrix.os, 'macos') }}
shell: pwsh
run: |
cd build
cpack
- name: Upload Disk Image (macOS)
if: ${{ startsWith(matrix.os, 'macos') }}
uses: actions/upload-artifact@v4
with:
name: supercell-wx-${{ matrix.artifact_suffix }}
path: ${{ github.workspace }}/build/supercell-wx-*.dmg*
- name: Test Supercell Wx - name: Test Supercell Wx
working-directory: ${{ github.workspace }}/build working-directory: ${{ github.workspace }}/build
env: env:
MAPBOX_API_KEY: ${{ secrets.MAPBOX_API_KEY }} MAPBOX_API_KEY: ${{ secrets.MAPBOX_API_KEY }}
MAPTILER_API_KEY: ${{ secrets.MAPTILER_API_KEY }} MAPTILER_API_KEY: ${{ secrets.MAPTILER_API_KEY }}
run: ctest -C ${{ matrix.build_type }} --exclude-regex "test_mln.*|NtpClient.*|UpdateManager.*" run: ctest -C ${{ matrix.build_type }} --exclude-regex test_mln.*
- name: Upload Test Logs - name: Upload Test Logs
if: ${{ !cancelled() }} if: ${{ !cancelled() }}

View file

@ -1,42 +0,0 @@
name: clang-format-check
on:
workflow_dispatch:
pull_request:
branches:
- 'develop'
concurrency:
# Cancel in-progress jobs for the same pull request
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
format:
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@v5
with:
fetch-depth: 0
submodules: false
- name: Update References
shell: bash
run: |
git fetch origin develop
- name: Setup Ubuntu Environment
shell: bash
run: |
sudo apt-get install clang-format-19
sudo rm -f /usr/bin/clang-format
sudo ln -s /usr/bin/clang-format-19 /usr/bin/clang-format
- name: Check Formatting
shell: bash
run: |
MERGE_BASE=$(git merge-base origin/develop ${{ github.event.pull_request.head.sha || github.ref }})
echo "Comparing against ${MERGE_BASE}"
git clang-format-19 --diff --style=file -v ${MERGE_BASE}

View file

@ -1,21 +0,0 @@
name: Post clang-tidy Review Comments
on:
workflow_run:
workflows: ["clang-tidy-review"]
types:
- completed
jobs:
build:
runs-on: ubuntu-latest
if: ${{ github.event.workflow_run.conclusion != 'cancelled' }}
steps:
- name: Post Comments
uses: ZedThree/clang-tidy-review/post@v0.21.0
with:
lgtm_comment_body: ''
annotations: false
max_comments: 25
num_comments_as_exitcode: false

View file

@ -1,152 +0,0 @@
name: clang-tidy-review
on:
pull_request:
branches:
- 'develop'
concurrency:
# Cancel in-progress jobs for the same pull request
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
build:
strategy:
matrix:
include:
- name: linux_clang-tidy_x64
os: ubuntu-24.04
build_type: Release
env_cc: clang-18
env_cxx: clang++-18
qt_version: 6.9.2
qt_arch_aqt: linux_gcc_64
qt_modules: qtimageformats qtmultimedia qtpositioning qtserialport
qt_tools: ''
conan_package_manager: --conf tools.system.package_manager:mode=install --conf tools.system.package_manager:sudo=True
conan_profile: scwx-linux_clang-18
compiler_packages: clang-18 clang-tidy-18
clang_tidy_binary: clang-tidy-18
name: ${{ matrix.name }}
runs-on: ${{ matrix.os }}
env:
CC: ${{ matrix.env_cc }}
CXX: ${{ matrix.env_cxx }}
steps:
- name: Checkout
uses: actions/checkout@v5
with:
path: source
submodules: recursive
- name: Checkout clang-tidy-review Repository
uses: actions/checkout@v5
with:
repository: ZedThree/clang-tidy-review
ref: v0.20.1
path: clang-tidy-review
- name: Install Qt
uses: jdpurcell/install-qt-action@v5
env:
AQT_CONFIG: ${{ github.workspace }}/source/tools/aqt-settings.ini
with:
version: ${{ matrix.qt_version }}
arch: ${{ matrix.qt_arch_aqt }}
modules: ${{ matrix.qt_modules }}
tools: ${{ matrix.qt_tools }}
- name: Setup Ubuntu Environment
if: ${{ startsWith(matrix.os, 'ubuntu') }}
shell: bash
run: |
sudo apt-get install doxygen \
libfuse2 \
ninja-build \
wayland-protocols \
libwayland-dev \
libwayland-egl-backend-dev \
${{ matrix.compiler_packages }}
- name: Setup Python Environment
shell: pwsh
run: |
pip install geopandas `
GitPython `
conan
pip install --break-system-packages clang-tidy-review/post/clang_tidy_review
- name: Cache Conan Packages
uses: actions/cache@v4
with:
path: ~/.conan2
key: build-${{ matrix.conan_profile }}-${{ hashFiles('./source/conanfile.py', './source/tools/conan/profiles/*') }}
- name: Install Conan Packages
shell: pwsh
run: |
conan config install `
./source/tools/conan/profiles/${{ matrix.conan_profile }} `
-tf profiles
mkdir build
cd build
mkdir conan
conan install ../source/ `
--remote conancenter `
--build missing `
--profile:all ${{ matrix.conan_profile }} `
--settings:all build_type=${{ matrix.build_type }} `
--output-folder ./conan/ `
${{ matrix.conan_package_manager }}
- name: Autogenerate
shell: pwsh
run: |
cd build
cmake ../source/ `
-G Ninja `
-DCMAKE_BUILD_TYPE="${{ matrix.build_type }}" `
-DCMAKE_PROJECT_TOP_LEVEL_INCLUDES="${{ github.workspace }}/source/external/cmake-conan/conan_provider.cmake" `
-DCMAKE_INSTALL_PREFIX="${{ github.workspace }}/supercell-wx" `
-DCONAN_HOST_PROFILE="${{ matrix.conan_profile }}" `
-DCONAN_BUILD_PROFILE="${{ matrix.conan_profile }}" `
-DCMAKE_EXPORT_COMPILE_COMMANDS=on
ninja glad_gl_core_33 `
scwx-qt_generate_counties_db `
scwx-qt_generate_versions `
scwx-qt_autogen
- name: Code Review
id: review
shell: bash
run: |
cd source
review --clang_tidy_binary=${{ matrix.clang_tidy_binary }} \
--token=${{ github.token }} \
--repo='${{ github.repository }}' \
--pr='${{ github.event.pull_request.number }}' \
--build_dir='../build' \
--base_dir='${{ github.workspace }}/source' \
--clang_tidy_checks='' \
--config_file='' \
--include='*.[ch],*.[ch]xx,*.[chi]pp,*.[ch]++,*.cc,*.hh' \
--exclude='' \
--apt-packages='' \
--cmake-command='' \
--max-comments=25 \
--lgtm-comment-body='' \
--split_workflow=true \
--annotations=false \
--parallel=0
rsync -avzh --ignore-missing-args clang-tidy-review-output.json ../
rsync -avzh --ignore-missing-args clang-tidy-review-metadata.json ../
rsync -avzh --ignore-missing-args clang_fixes.json ../
- name: Upload Review
uses: ZedThree/clang-tidy-review/upload@v0.21.0
- name: Status Check
if: steps.review.outputs.total_comments > 0
run: exit 1

11
.gitignore vendored
View file

@ -5,20 +5,9 @@ CMakeLists.txt.user
CMakeCache.txt CMakeCache.txt
CMakeFiles CMakeFiles
CMakeScripts CMakeScripts
CMakeUserPresets.json
Testing Testing
cmake_install.cmake cmake_install.cmake
install_manifest.txt install_manifest.txt
compile_commands.json compile_commands.json
CTestTestfile.cmake CTestTestfile.cmake
_deps _deps
# Editor directories
.idea/
.vs/
# Python Virtual Environment
.venv/
# Specific excludes for Supercell Wx
tools/lib/user-setup.sh

54
.gitmodules vendored
View file

@ -1,45 +1,39 @@
[submodule "data"]
path = data
url = https://github.com/dpaulat/supercell-wx-data
[submodule "external/aws-sdk-cpp"]
path = external/aws-sdk-cpp
url = https://github.com/aws/aws-sdk-cpp.git
[submodule "external/cmake-conan"] [submodule "external/cmake-conan"]
path = external/cmake-conan path = external/cmake-conan
url = https://github.com/conan-io/cmake-conan.git url = https://github.com/conan-io/cmake-conan.git
[submodule "external/date"] [submodule "test/data"]
path = external/date path = test/data
url = https://github.com/HowardHinnant/date.git url = https://github.com/dpaulat/supercell-wx-test-data
[submodule "external/glad"]
path = external/glad
url = https://github.com/Dav1dde/glad.git
[submodule "external/hsluv-c"] [submodule "external/hsluv-c"]
path = external/hsluv-c path = external/hsluv-c
url = https://github.com/hsluv/hsluv-c.git url = https://github.com/hsluv/hsluv-c.git
[submodule "external/stb"]
path = external/stb
url = https://github.com/nothings/stb.git
[submodule "data"]
path = data
url = https://github.com/dpaulat/supercell-wx-data
[submodule "external/imgui"] [submodule "external/imgui"]
path = external/imgui path = external/imgui
url = https://github.com/ocornut/imgui.git url = https://github.com/ocornut/imgui.git
[submodule "external/imgui-backend-qt"] [submodule "external/imgui-backend-qt"]
path = external/imgui-backend-qt path = external/imgui-backend-qt
url = https://github.com/dpaulat/imgui-backend-qt url = https://github.com/dpaulat/imgui-backend-qt
[submodule "external/maplibre-native"] [submodule "external/aws-sdk-cpp"]
path = external/maplibre-native path = external/aws-sdk-cpp
url = https://github.com/dpaulat/maplibre-gl-native.git url = https://github.com/aws/aws-sdk-cpp.git
[submodule "external/maplibre-native-qt"] [submodule "external/date"]
path = external/maplibre-native-qt path = external/date
url = https://github.com/dpaulat/maplibre-native-qt.git url = https://github.com/HowardHinnant/date.git
[submodule "external/qt6ct"]
path = external/qt6ct
url = https://github.com/AdenKoperczak/qt6ct.git
[submodule "external/stb"]
path = external/stb
url = https://github.com/nothings/stb.git
[submodule "external/textflowcpp"]
path = external/textflowcpp
url = https://github.com/catchorg/textflowcpp.git
[submodule "external/units"] [submodule "external/units"]
path = external/units path = external/units
url = https://github.com/nholthaus/units.git url = https://github.com/nholthaus/units.git
[submodule "test/data"] [submodule "external/textflowcpp"]
path = test/data path = external/textflowcpp
url = https://github.com/dpaulat/supercell-wx-test-data url = https://github.com/catchorg/textflowcpp.git
[submodule "external/maplibre-native-qt"]
path = external/maplibre-native-qt
url = https://github.com/dpaulat/maplibre-native-qt.git
[submodule "external/maplibre-native"]
path = external/maplibre-native
url = https://github.com/dpaulat/maplibre-gl-native.git

View file

@ -23,7 +23,7 @@ Supercell Wx uses code from the following dependencies:
| [FreeType GL](https://github.com/rougier/freetype-gl) | [BSD 2-Clause with views sentence](https://spdx.org/licenses/BSD-2-Clause-Views.html) | | [FreeType GL](https://github.com/rougier/freetype-gl) | [BSD 2-Clause with views sentence](https://spdx.org/licenses/BSD-2-Clause-Views.html) |
| [GeographicLib](https://geographiclib.sourceforge.io/) | [MIT License](https://spdx.org/licenses/MIT.html) | | [GeographicLib](https://geographiclib.sourceforge.io/) | [MIT License](https://spdx.org/licenses/MIT.html) |
| [geos](https://libgeos.org/) | [GNU Lesser General Public License v2.1 or later](https://spdx.org/licenses/LGPL-2.1-or-later.html) | | [geos](https://libgeos.org/) | [GNU Lesser General Public License v2.1 or later](https://spdx.org/licenses/LGPL-2.1-or-later.html) |
| [GLAD](https://github.com/Dav1dde/glad) | [MIT License](https://spdx.org/licenses/MIT.html) | | [GLEW](https://www.opengl.org/sdk/libs/GLEW/) | [MIT License](https://spdx.org/licenses/MIT.html) |
| [GLM](https://github.com/g-truc/glm) | [MIT License](https://spdx.org/licenses/MIT.html) | | [GLM](https://github.com/g-truc/glm) | [MIT License](https://spdx.org/licenses/MIT.html) |
| [GoogleTest](https://google.github.io/googletest/) | [BSD 3-Clause "New" or "Revised" License](https://spdx.org/licenses/BSD-3-Clause.html) | | [GoogleTest](https://google.github.io/googletest/) | [BSD 3-Clause "New" or "Revised" License](https://spdx.org/licenses/BSD-3-Clause.html) |
| [HSLuv](https://www.hsluv.org/) | [MIT License](https://spdx.org/licenses/MIT.html) | | [HSLuv](https://www.hsluv.org/) | [MIT License](https://spdx.org/licenses/MIT.html) |
@ -32,12 +32,9 @@ Supercell Wx uses code from the following dependencies:
| [libpng](http://libpng.org/pub/png/libpng.html) | [PNG Reference Library version 2](https://spdx.org/licenses/libpng-2.0.html) | | [libpng](http://libpng.org/pub/png/libpng.html) | [PNG Reference Library version 2](https://spdx.org/licenses/libpng-2.0.html) |
| [libxml2](http://xmlsoft.org/) | [MIT License](https://spdx.org/licenses/MIT.html) | | [libxml2](http://xmlsoft.org/) | [MIT License](https://spdx.org/licenses/MIT.html) |
| [MapLibre Native](https://maplibre.org/projects/maplibre-native/) | [BSD 2-Clause "Simplified" License](https://spdx.org/licenses/BSD-2-Clause.html) | | [MapLibre Native](https://maplibre.org/projects/maplibre-native/) | [BSD 2-Clause "Simplified" License](https://spdx.org/licenses/BSD-2-Clause.html) |
| [Mesa 3D](https://mesa3d.org/) | [MIT License](https://spdx.org/licenses/MIT.html) |
| [nunicode](https://bitbucket.org/alekseyt/nunicode/src/master/) | [MIT License](https://spdx.org/licenses/MIT.html) | Modified for MapLibre Native | | [nunicode](https://bitbucket.org/alekseyt/nunicode/src/master/) | [MIT License](https://spdx.org/licenses/MIT.html) | Modified for MapLibre Native |
| [OpenSSL](https://www.openssl.org/) | [OpenSSL License](https://spdx.org/licenses/OpenSSL.html) | | [OpenSSL](https://www.openssl.org/) | [OpenSSL License](https://spdx.org/licenses/OpenSSL.html) |
| [Qt](https://www.qt.io/) | [GNU Lesser General Public License v3.0 only](https://spdx.org/licenses/LGPL-3.0-only.html) | Qt Core, Qt GUI, Qt Multimedia, Qt Network, Qt OpenGL, Qt Positioning, Qt Serial Port, Qt SQL, Qt SVG, Qt Widgets<br/>Additional Licenses: https://doc.qt.io/qt-6/licenses-used-in-qt.html | | [Qt](https://www.qt.io/) | [GNU Lesser General Public License v3.0 only](https://spdx.org/licenses/LGPL-3.0-only.html) | Qt Core, Qt GUI, Qt Multimedia, Qt Network, Qt OpenGL, Qt Positioning, Qt Serial Port, Qt SQL, Qt SVG, Qt Widgets<br/>Additional Licenses: https://doc.qt.io/qt-6/licenses-used-in-qt.html |
| [qt6ct](https://github.com/trialuser02/qt6ct) | [BSD 2-Clause "Simplified" License](https://spdx.org/licenses/BSD-2-Clause.html) |
| [range-v3](https://github.com/ericniebler/range-v3) | [Boost Software License 1.0](https://spdx.org/licenses/BSL-1.0.html)<br/>[MIT License](https://spdx.org/licenses/MIT.html)<br/>[Stepanov and McJones, "Elements of Programming" license](https://github.com/ericniebler/range-v3/tree/0.12.0?tab=License-1-ov-file)<br/>[SGI C++ Standard Template Library license](https://github.com/ericniebler/range-v3/tree/0.12.0?tab=License-1-ov-file) |
| [re2](https://github.com/google/re2) | [BSD 3-Clause "New" or "Revised" License](https://spdx.org/licenses/BSD-3-Clause.html) | | [re2](https://github.com/google/re2) | [BSD 3-Clause "New" or "Revised" License](https://spdx.org/licenses/BSD-3-Clause.html) |
| [spdlog](https://github.com/gabime/spdlog) | [MIT License](https://spdx.org/licenses/MIT.html) | | [spdlog](https://github.com/gabime/spdlog) | [MIT License](https://spdx.org/licenses/MIT.html) |
| [SQLite](https://www.sqlite.org/) | Public Domain | | [SQLite](https://www.sqlite.org/) | Public Domain |
@ -70,7 +67,6 @@ Supercell Wx uses assets from the following sources:
| [Font Awesome Free](https://fontawesome.com/) | CC BY 4.0 License | | [Font Awesome Free](https://fontawesome.com/) | CC BY 4.0 License |
| [Inconsolata](https://fonts.google.com/specimen/Inconsolata) | SIL Open Font License | | [Inconsolata](https://fonts.google.com/specimen/Inconsolata) | SIL Open Font License |
| [NOAA's Weather and Climate Toolkit](https://www.ncdc.noaa.gov/wct/) | Public Domain | Default Color Tables | | [NOAA's Weather and Climate Toolkit](https://www.ncdc.noaa.gov/wct/) | Public Domain | Default Color Tables |
| [qt6ct](https://github.com/trialuser02/qt6ct) | [BSD 2-Clause "Simplified" License](https://spdx.org/licenses/BSD-2-Clause.html) |
| [Roboto Flex](https://fonts.google.com/specimen/Roboto+Flex) | SIL Open Font License | | [Roboto Flex](https://fonts.google.com/specimen/Roboto+Flex) | SIL Open Font License |
| [Supercell thunderstorm with dramatic clouds](https://www.shutterstock.com/image-photo/supercell-thunderstorm-dramatic-clouds-1354353521) | Shutterstock Standard License | Photo by John Sirlin | [Supercell thunderstorm with dramatic clouds](https://www.shutterstock.com/image-photo/supercell-thunderstorm-dramatic-clouds-1354353521) | Shutterstock Standard License | Photo by John Sirlin

View file

@ -1,14 +1,7 @@
cmake_minimum_required(VERSION 3.24) cmake_minimum_required(VERSION 3.21)
set(PROJECT_NAME supercell-wx) set(PROJECT_NAME supercell-wx)
include(tools/scwx_config.cmake)
set(CMAKE_OSX_DEPLOYMENT_TARGET 12.0)
scwx_python_setup()
project(${PROJECT_NAME} project(${PROJECT_NAME}
VERSION 0.5.1 VERSION 0.4.5
DESCRIPTION "Supercell Wx is a free, open source advanced weather radar viewer." DESCRIPTION "Supercell Wx is a free, open source advanced weather radar viewer."
HOMEPAGE_URL "https://github.com/dpaulat/supercell-wx" HOMEPAGE_URL "https://github.com/dpaulat/supercell-wx"
LANGUAGES C CXX) LANGUAGES C CXX)
@ -18,21 +11,40 @@ set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
set(CMAKE_POLICY_DEFAULT_CMP0079 NEW) set(CMAKE_POLICY_DEFAULT_CMP0079 NEW)
set(CMAKE_POLICY_DEFAULT_CMP0148 OLD) # aws-sdk-cpp uses FindPythonInterp set(CMAKE_POLICY_DEFAULT_CMP0148 OLD) # aws-sdk-cpp uses FindPythonInterp
scwx_output_dirs_setup()
enable_testing() enable_testing()
set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
include(${PROJECT_SOURCE_DIR}/external/cmake-conan/conan.cmake)
set_property(DIRECTORY set_property(DIRECTORY
APPEND APPEND
PROPERTY CMAKE_CONFIGURE_DEPENDS PROPERTY CMAKE_CONFIGURE_DEPENDS
conanfile.py) conanfile.py)
# Don't use RelWithDebInfo Conan packages
if (${CMAKE_BUILD_TYPE} STREQUAL "RelWithDebInfo")
set(conan_build_type "Release")
else()
set(conan_build_type ${CMAKE_BUILD_TYPE})
endif()
conan_cmake_autodetect(settings
BUILD_TYPE ${conan_build_type})
conan_cmake_install(PATH_OR_REFERENCE ${PROJECT_SOURCE_DIR}
BUILD missing
REMOTE conancenter
SETTINGS ${settings})
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
include(${CMAKE_BINARY_DIR}/conan_paths.cmake)
conan_basic_setup(TARGETS)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DBOOST_ALL_NO_LIB") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DBOOST_ALL_NO_LIB")
set(SCWX_DIR ${PROJECT_SOURCE_DIR}) set(SCWX_DIR ${PROJECT_SOURCE_DIR})
set(SCWX_VERSION "0.5.1") set(SCWX_VERSION "0.4.5")
option(SCWX_ADDRESS_SANITIZER "Build with Address Sanitizer" OFF) option(SCWX_ADDRESS_SANITIZER "Build with Address Sanitizer" OFF)

View file

@ -1,383 +0,0 @@
{
"version": 5,
"cmakeMinimumRequired": {
"major": 3,
"minor": 24,
"patch": 0
},
"configurePresets": [
{
"name": "base",
"hidden": true,
"generator": "Ninja",
"binaryDir": "${sourceDir}/build/${presetName}",
"cacheVariables": {
"CMAKE_PROJECT_TOP_LEVEL_INCLUDES": "${sourceDir}/external/cmake-conan/conan_provider.cmake",
"SCWX_VIRTUAL_ENV": "${sourceDir}/.venv"
}
},
{
"name": "windows-base",
"inherits": "base",
"hidden": true,
"generator": "Visual Studio 17 2022",
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
},
"vendor": {
"microsoft.com/VisualStudioSettings/CMake/1.0": {
"hostOS": [
"Windows"
]
}
}
},
{
"name": "windows-x64-base",
"inherits": "windows-base",
"hidden": true
},
{
"name": "linux-base",
"inherits": "base",
"hidden": true,
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Linux"
}
},
{
"name": "windows-msvc2022-x64-base",
"inherits": "windows-x64-base",
"hidden": true,
"cacheVariables": {
"CMAKE_PREFIX_PATH": "C:/Qt/6.9.2/msvc2022_64"
}
},
{
"name": "windows-msvc2022-x64-ninja-base",
"inherits": "windows-msvc2022-x64-base",
"hidden": true,
"generator": "Ninja",
"cacheVariables": {
"CMAKE_PREFIX_PATH": "C:/Qt/6.9.2/msvc2022_64"
}
},
{
"name": "linux-gcc-base",
"inherits": "linux-base",
"hidden": true,
"cacheVariables": {
"CMAKE_PREFIX_PATH": "/opt/Qt/6.9.2/gcc_64"
},
"environment": {
"CC": "gcc-11",
"CXX": "g++-11"
}
},
{
"name": "windows-msvc2022-x64-debug",
"inherits": "windows-msvc2022-x64-base",
"displayName": "Windows MSVC 2022 x64 Debug",
"architecture": {
"value": "x64",
"strategy": "external"
},
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"CONAN_HOST_PROFILE": "scwx-windows_msvc2022_x64-debug",
"CONAN_BUILD_PROFILE": "scwx-windows_msvc2022_x64-debug"
}
},
{
"name": "windows-msvc2022-x64-release",
"inherits": "windows-msvc2022-x64-base",
"displayName": "Windows MSVC 2022 x64 Release",
"architecture": {
"value": "x64",
"strategy": "external"
},
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"CONAN_HOST_PROFILE": "scwx-windows_msvc2022_x64",
"CONAN_BUILD_PROFILE": "scwx-windows_msvc2022_x64"
}
},
{
"name": "windows-msvc2022-x64-ninja-debug",
"inherits": "windows-msvc2022-x64-ninja-base",
"displayName": "Windows MSVC 2022 x64 Ninja Debug",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"CONAN_HOST_PROFILE": "scwx-windows_msvc2022_x64-debug",
"CONAN_BUILD_PROFILE": "scwx-windows_msvc2022_x64-debug"
}
},
{
"name": "windows-msvc2022-x64-ninja-release",
"inherits": "windows-msvc2022-x64-ninja-base",
"displayName": "Windows MSVC 2022 x64 Ninja Release",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"CONAN_HOST_PROFILE": "scwx-windows_msvc2022_x64",
"CONAN_BUILD_PROFILE": "scwx-windows_msvc2022_x64"
}
},
{
"name": "linux-gcc-debug",
"inherits": "linux-gcc-base",
"displayName": "Linux GCC Debug",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"CMAKE_INSTALL_PREFIX": "${sourceDir}/build/${presetName}/Debug/supercell-wx",
"CONAN_HOST_PROFILE": "scwx-linux_gcc-11-debug",
"CONAN_BUILD_PROFILE": "scwx-linux_gcc-11-debug"
}
},
{
"name": "linux-gcc-release",
"inherits": "linux-gcc-base",
"displayName": "Linux GCC Release",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"CMAKE_INSTALL_PREFIX": "${sourceDir}/build/${presetName}/Release/supercell-wx",
"CONAN_HOST_PROFILE": "scwx-linux_gcc-11",
"CONAN_BUILD_PROFILE": "scwx-linux_gcc-11"
}
},
{
"name": "linux-gcc-debug-asan",
"inherits": "linux-gcc-base",
"displayName": "Linux GCC Debug Address Sanitizer",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"CMAKE_INSTALL_PREFIX": "${sourceDir}/build/${presetName}/Debug/supercell-wx",
"CONAN_HOST_PROFILE": "scwx-linux_gcc-11-debug",
"CONAN_BUILD_PROFILE": "scwx-linux_gcc-11-debug",
"SCWX_ADDRESS_SANITIZER": {
"type": "BOOL",
"value": "ON"
}
}
},
{
"name": "linux-gcc-release-asan",
"inherits": "linux-gcc-base",
"displayName": "Linux GCC Release Address Sanitizer",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"CMAKE_INSTALL_PREFIX": "${sourceDir}/build/${presetName}/Release/supercell-wx",
"CONAN_HOST_PROFILE": "scwx-linux_gcc-11",
"CONAN_BUILD_PROFILE": "scwx-linux_gcc-11",
"SCWX_ADDRESS_SANITIZER": {
"type": "BOOL",
"value": "ON"
}
}
},
{
"name": "ci-linux-gcc14",
"inherits": "linux-gcc-base",
"displayName": "CI Linux GCC 14",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"CONAN_HOST_PROFILE": "scwx-linux_gcc-14",
"CONAN_BUILD_PROFILE": "scwx-linux_gcc-14"
},
"environment": {
"CC": "gcc-14",
"CXX": "g++-14"
}
},
{
"name": "ci-linux-clang17",
"inherits": "linux-gcc-base",
"displayName": "CI Linux Clang 17",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"CONAN_HOST_PROFILE": "scwx-linux_clang-17",
"CONAN_BUILD_PROFILE": "scwx-linux_clang-17"
},
"environment": {
"CC": "clang-17",
"CXX": "clang++-17"
}
},
{
"name": "ci-linux-gcc-arm64",
"inherits": "linux-gcc-base",
"displayName": "CI Linux GCC ARM64",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"CMAKE_PREFIX_PATH": "/opt/Qt/6.9.2/gcc_arm64",
"CONAN_HOST_PROFILE": "scwx-linux_gcc-11_armv8",
"CONAN_BUILD_PROFILE": "scwx-linux_gcc-11_armv8"
},
"environment": {
"CC": "gcc-11",
"CXX": "g++-11"
}
},
{
"name": "macos-base",
"inherits": "base",
"hidden": true,
"cacheVariables": {
"CMAKE_PREFIX_PATH": "$env{HOME}/Qt/6.9.2/macos"
},
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Darwin"
}
},
{
"name": "macos-clang18-base",
"inherits": "macos-base",
"hidden": true
},
{
"name": "macos-clang18-x64-base",
"inherits": "macos-clang18-base",
"hidden": true,
"environment": {
"CC": "/usr/local/opt/llvm@18/bin/clang",
"CXX": "/usr/local/opt/llvm@18/bin/clang++",
"PATH": "/usr/local/opt/llvm@18/bin:$penv{PATH}",
"CPPFLAGS": "-I/usr/local/opt/llvm@18/include",
"LDFLAGS": "-L/usr/local/opt/llvm@18/lib -L/usr/local/opt/llvm@18/lib/c++"
}
},
{
"name": "macos-clang18-arm64-base",
"inherits": "macos-clang18-base",
"hidden": true,
"environment": {
"CC": "/opt/homebrew/opt/llvm@18/bin/clang",
"CXX": "/opt/homebrew/opt/llvm@18/bin/clang++",
"PATH": "/opt/homebrew/opt/llvm@18/bin:$penv{PATH}",
"CPPFLAGS": "-I/opt/homebrew/opt/llvm@18/include",
"LDFLAGS": "-L/opt/homebrew/opt/llvm@18/lib -L/opt/homebrew/opt/llvm@18/lib/c++"
}
},
{
"name": "macos-clang18-x64-debug",
"inherits": "macos-clang18-x64-base",
"displayName": "macOS Clang 18 x64 Debug",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"CONAN_HOST_PROFILE": "scwx-macos_clang-18-debug",
"CONAN_BUILD_PROFILE": "scwx-macos_clang-18-debug"
}
},
{
"name": "macos-clang18-x64-release",
"inherits": "macos-clang18-x64-base",
"displayName": "macOS Clang 18 x64 Release",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"CONAN_HOST_PROFILE": "scwx-macos_clang-18",
"CONAN_BUILD_PROFILE": "scwx-macos_clang-18"
}
},
{
"name": "macos-clang18-arm64-debug",
"inherits": "macos-clang18-arm64-base",
"displayName": "macOS Clang 18 Arm64 Debug",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"CONAN_HOST_PROFILE": "scwx-macos_clang-18_armv8-debug",
"CONAN_BUILD_PROFILE": "scwx-macos_clang-18_armv8-debug"
}
},
{
"name": "macos-clang18-arm64-release",
"inherits": "macos-clang18-arm64-base",
"displayName": "macOS Clang 18 Arm64 Release",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"CONAN_HOST_PROFILE": "scwx-macos_clang-18_armv8",
"CONAN_BUILD_PROFILE": "scwx-macos_clang-18_armv8"
}
}
],
"buildPresets": [
{
"name": "windows-msvc2022-x64-debug",
"configurePreset": "windows-msvc2022-x64-debug",
"displayName": "Windows MSVC 2022 x64 Debug",
"configuration": "Debug"
},
{
"name": "windows-msvc2022-x64-release",
"configurePreset": "windows-msvc2022-x64-release",
"displayName": "Windows MSVC 2022 x64 Release",
"configuration": "Release"
},
{
"name": "linux-gcc-debug",
"configurePreset": "linux-gcc-debug",
"displayName": "Linux GCC Debug",
"configuration": "Debug"
},
{
"name": "linux-gcc-release",
"configurePreset": "linux-gcc-release",
"displayName": "Linux GCC Release",
"configuration": "Release"
},
{
"name": "macos-clang18-x64-debug",
"configurePreset": "macos-clang18-x64-debug",
"displayName": "macOS Clang 18 x64 Debug",
"configuration": "Debug"
},
{
"name": "macos-clang18-x64-release",
"configurePreset": "macos-clang18-x64-release",
"displayName": "macOS Clang 18 x64 Release",
"configuration": "Release"
},
{
"name": "macos-clang18-arm64-debug",
"configurePreset": "macos-clang18-arm64-debug",
"displayName": "macOS Clang 18 Arm64 Debug",
"configuration": "Debug"
},
{
"name": "macos-clang18-arm64-release",
"configurePreset": "macos-clang18-arm64-release",
"displayName": "macOS Clang 18 Arm64 Release",
"configuration": "Release"
}
],
"testPresets": [
{
"name": "windows-msvc2022-x64-debug",
"configurePreset": "windows-msvc2022-x64-debug",
"displayName": "Windows MSVC 2022 x64 Debug",
"configuration": "Debug"
},
{
"name": "windows-msvc2022-x64-release",
"configurePreset": "windows-msvc2022-x64-release",
"displayName": "Windows MSVC 2022 x64 Release",
"configuration": "Release"
},
{
"name": "linux-gcc-debug",
"configurePreset": "linux-gcc-debug",
"displayName": "Linux GCC Debug",
"configuration": "Debug"
},
{
"name": "linux-gcc-release",
"configurePreset": "linux-gcc-release",
"displayName": "Linux GCC Release",
"configuration": "Release"
}
]
}

View file

@ -1,6 +1,6 @@
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2021-2025 Dan Paulat Copyright (c) 2021-2024 Dan Paulat
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View file

@ -26,36 +26,32 @@ Supercell Wx supports the following 64-bit operating systems:
- Fedora Linux 34+ - Fedora Linux 34+
- openSUSE Tumbleweed - openSUSE Tumbleweed
- Ubuntu 22.04+ - Ubuntu 22.04+
- NixOS 25.05+
- Most distributions supporting the GCC Standard C++ Library 11+ - Most distributions supporting the GCC Standard C++ Library 11+
- macOS
- 13.6+ for Intel-based Macs
- 14.0+ for Apple silicon-based Macs
## Linux Dependencies ## Linux Dependencies
Supercell Wx requires the following Linux dependencies: Supercell Wx requires the following Linux dependencies:
- Linux/X11 (Wayland works too) with support for GCC 11, OpenGL 3.3 and OpenGL ES 3.0 - Linux/X11 (Wayland works too) with support for GCC 11 and OpenGL 3.3
- X11/XCB libraries including xcb-cursor - X11/XCB libraries including xcb-cursor
## FAQ ## FAQ
Frequently asked questions: Frequently asked questions:
- Q: Why is the map black when loading for the first time? - Q: Why is the map black when loading for the first time?
- A. You must obtain a free API key from either (or both) [MapTiler](https://cloud.maptiler.com/auth/widget?next=https://cloud.maptiler.com/maps/) which currently does not require a credit/debit card, or [Mapbox](https://account.mapbox.com/) which ***does*** require a credit/debit card, but as of writing, you will receive 200K free requests per month, which should be sufficient for an individual user. - A. You must obtain a free API key from either (or both) [MapTiler](https://cloud.maptiler.com/auth/widget?next=https://cloud.maptiler.com/maps/) which currently does not require a credit/debit card, or [Mapbox](https://account.mapbox.com/) which ***does*** require a credit/debit card, but as of writing, you will receive 200K free requests per month, which should be sufficient for an individual user.
- Q: Why is it that when I change my color table, API key, grid width/height settings, nothing happens after hitting apply? - Q: Why is it that when I change my color table, API key, grid width/height settings, nothing happens after hitting apply?
- A. As of right now, you must restart Supercell Wx in order to apply these changes. In future iterations, this will no longer be an issue. - A. As of right now, you must restart Supercell Wx in order to apply these changes. In future iterations, this will no longer be an issue.
- Q. Is it possible to get dark mode? - Q. Is it possible to get dark mode?
- A. In Windows, make sure to set the flag `-style fusion` at the end of the target path of the .exe - A. In Windows, make sure to set the flag `-style fusion` at the end of the target path of the .exe
- Example: `C:\Users\Administrator\Desktop\Supercell-Wx\bin\supercell-wx.exe -style fusion` - Example: `C:\Users\Administrator\Desktop\Supercell-Wx\bin\supercell-wx.exe -style fusion`
- A. In Linux, if you're using KDE, Supercell Wx should automatically follow your theme settings. - A. In Linux, if you're using KDE, Supercell Wx should automatically follow your theme settings.
- Q: How can I contribute? - Q: How can I contribute?
- A. Head to [Developer Setup](https://supercell-wx.readthedocs.io/en/stable/development/developer-setup.html) and [Contributing](CONTRIBUTING.md) to configure the Supercell Wx development environment for your IDE. Currently Visual Studio and Visual Studio Code are recommended, with other IDEs remaining untested at this time. - A. Head to [Developer Setup](https://supercell-wx.readthedocs.io/en/stable/development/developer-setup.html) and [Contributing](CONTRIBUTING.md) to configure the Supercell Wx development environment for your IDE. Currently Visual Studio and Visual Studio Code are recommended, with other IDEs remaining untested at this time.

View file

@ -1,66 +1,37 @@
from conan import ConanFile from conans import ConanFile
from conan.tools.cmake import CMake
from conan.tools.files import copy
import os
class SupercellWxConan(ConanFile): class SupercellWxConan(ConanFile):
settings = ("os", "compiler", "build_type", "arch") settings = ("os", "compiler", "build_type", "arch")
requires = ("boost/1.88.0", requires = ("boost/1.85.0",
"cpr/1.12.0", "cpr/1.10.5",
"fontconfig/2.15.0", "fontconfig/2.15.0",
"freetype/2.13.2", "freetype/2.13.2",
"geographiclib/2.4", "geographiclib/2.3",
"geos/3.13.0", "geos/3.12.2",
"glm/1.0.1", "glew/2.2.0",
"gtest/1.17.0", "glm/cci.20230113",
"libcurl/8.12.1", "gtest/1.15.0",
"libpng/1.6.50", "libcurl/8.9.1",
"libxml2/2.14.5", "libxml2/2.12.7",
"openssl/3.5.0", "openssl/3.3.1",
"range-v3/0.12.0", "re2/20240702",
"re2/20250722", "spdlog/1.14.1",
"spdlog/1.15.1", "sqlite3/3.46.0",
"sqlite3/3.49.1", "vulkan-loader/1.3.243.0",
"vulkan-loader/1.3.290.0",
"zlib/1.3.1") "zlib/1.3.1")
generators = ("CMakeDeps") generators = ("cmake",
default_options = {"geos/*:shared" : True, "cmake_find_package",
"libiconv/*:shared" : True} "cmake_paths")
default_options = {"geos:shared" : True,
def configure(self): "libiconv:shared" : True,
if self.settings.os == "Windows": "openssl:no_module": True,
self.options["libcurl"].with_ssl = "schannel" "openssl:shared" : True}
elif self.settings.os == "Linux":
self.options["openssl"].shared = True
self.options["libcurl"].ca_bundle = "none"
self.options["libcurl"].ca_path = "none"
elif self.settings.os == "Macos":
self.options["openssl"].shared = True
self.options["libcurl"].ca_bundle = "none"
self.options["libcurl"].ca_path = "none"
def requirements(self): def requirements(self):
if self.settings.os == "Linux": if self.settings.os == "Linux":
self.requires("mesa-glu/9.0.3") self.requires("onetbb/2021.12.0")
self.requires("onetbb/2022.2.0")
def generate(self): def imports(self):
build_folder = os.path.join(self.build_folder, self.copy("*.dll", dst="bin", src="bin")
"..", self.copy("*.dylib", dst="bin", src="lib")
str(self.settings.build_type), self.copy("license*", dst="licenses", src=".", folder=True, ignore_case=True)
self.cpp_info.bindirs[0])
for dep in self.dependencies.values():
if dep.cpp_info.bindirs:
copy(self, "*.dll", dep.cpp_info.bindirs[0], build_folder)
if dep.cpp_info.libdirs:
copy(self, "*.dylib", dep.cpp_info.libdirs[0], build_folder)
def build(self):
cmake = CMake(self)
cmake.configure()
cmake.build()
def package(self):
cmake = CMake(self)
cmake.install()

2
data

@ -1 +1 @@
Subproject commit fd72b32cc12419b4a9c9a72487e58ffa04fb2a70 Subproject commit 8eb89b19fdd1c78e896cc6cb47e07425bb473699

View file

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.24) cmake_minimum_required(VERSION 3.20)
set(PROJECT_NAME scwx-external) set(PROJECT_NAME scwx-external)
set_property(DIRECTORY set_property(DIRECTORY
@ -6,22 +6,18 @@ set_property(DIRECTORY
PROPERTY CMAKE_CONFIGURE_DEPENDS PROPERTY CMAKE_CONFIGURE_DEPENDS
aws-sdk-cpp.cmake aws-sdk-cpp.cmake
date.cmake date.cmake
glad.cmake
hsluv-c.cmake hsluv-c.cmake
imgui.cmake imgui.cmake
maplibre-native-qt.cmake maplibre-native-qt.cmake
stb.cmake stb.cmake
textflowcpp.cmake textflowcpp.cmake
units.cmake units.cmake)
qt6ct.cmake)
include(aws-sdk-cpp.cmake) include(aws-sdk-cpp.cmake)
include(date.cmake) include(date.cmake)
include(glad.cmake)
include(hsluv-c.cmake) include(hsluv-c.cmake)
include(imgui.cmake) include(imgui.cmake)
include(maplibre-native-qt.cmake) include(maplibre-native-qt.cmake)
include(stb.cmake) include(stb.cmake)
include(textflowcpp.cmake) include(textflowcpp.cmake)
include(units.cmake) include(units.cmake)
include(qt6ct.cmake)

@ -1 +1 @@
Subproject commit 8d31e042f950fe70924391a205cceaf342ecec00 Subproject commit d5eb42fe7c632868d4535b454ee2e5ba0e349b7f

View file

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.24) cmake_minimum_required(VERSION 3.20)
set(PROJECT_NAME scwx-aws-sdk-cpp) set(PROJECT_NAME scwx-aws-sdk-cpp)
set(AWS_SDK_WARNINGS_ARE_ERRORS OFF) set(AWS_SDK_WARNINGS_ARE_ERRORS OFF)
@ -21,10 +21,6 @@ set(MINIMIZE_SIZE OFF CACHE BOOL "If enabled, the SDK will be built via
# Save off ${CMAKE_CXX_FLAGS} before modifying compiler settings # Save off ${CMAKE_CXX_FLAGS} before modifying compiler settings
set(CMAKE_CXX_FLAGS_PREV "${CMAKE_CXX_FLAGS}") set(CMAKE_CXX_FLAGS_PREV "${CMAKE_CXX_FLAGS}")
# Configure OpenSSL crypto library
find_package(OpenSSL)
add_library(crypto ALIAS OpenSSL::Crypto)
# Fix CMake errors for internal variables not set # Fix CMake errors for internal variables not set
include(aws-sdk-cpp/cmake/compiler_settings.cmake) include(aws-sdk-cpp/cmake/compiler_settings.cmake)
set_msvc_warnings() set_msvc_warnings()

@ -1 +1 @@
Subproject commit b0e4d1ec08edb35ef31033938567d621f6643c17 Subproject commit b240c809b5ea097077fc8222cad71d2329288e48

2
external/date vendored

@ -1 +1 @@
Subproject commit a5db3aecec580bc78b6c01c118f2628676769b69 Subproject commit cc4685a21e4a4fdae707ad1233c61bbaff241f93

2
external/date.cmake vendored
View file

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.24) cmake_minimum_required(VERSION 3.20)
set(PROJECT_NAME scwx-date) set(PROJECT_NAME scwx-date)
set(USE_SYSTEM_TZ_DB ON) set(USE_SYSTEM_TZ_DB ON)

1
external/glad vendored

@ -1 +0,0 @@
Subproject commit 73db193f853e2ee079bf3ca8a64aa2eaf6459043

11
external/glad.cmake vendored
View file

@ -1,11 +0,0 @@
cmake_minimum_required(VERSION 3.24)
set(PROJECT_NAME scwx-glad)
# Path to glad directory
set(GLAD_SOURCES_DIR "${CMAKE_CURRENT_SOURCE_DIR}/glad/")
# Path to glad CMake files
add_subdirectory("${GLAD_SOURCES_DIR}/cmake" glad_cmake)
# Specify glad settings
glad_add_library(glad_gl_core_33 LOADER REPRODUCIBLE API gl:core=3.3)

2
external/hsluv-c vendored

@ -1 +1 @@
Subproject commit 982217c65a9ff574302335177d2dc078d9bfa6f5 Subproject commit 59539e04a6fa648935cbe57c2104041f23136c4a

View file

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.24) cmake_minimum_required(VERSION 3.20)
set(PROJECT_NAME scwx-hsluv-c) set(PROJECT_NAME scwx-hsluv-c)
set(HSLUV_C_TESTS OFF) set(HSLUV_C_TESTS OFF)

2
external/imgui vendored

@ -1 +1 @@
Subproject commit 45acd5e0e82f4c954432533ae9985ff0e1aad6d5 Subproject commit 6ccc561a2ab497ad4ae6ee1dbd3b992ffada35cb

@ -1 +1 @@
Subproject commit 023345ca8abf731fc50568c0197ceebe76bb4324 Subproject commit 0fe974ebd037844c9f23d6325dbcc128e9973749

View file

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.24) cmake_minimum_required(VERSION 3.20)
set(PROJECT_NAME scwx-imgui) set(PROJECT_NAME scwx-imgui)
find_package(QT NAMES Qt6 find_package(QT NAMES Qt6
@ -12,7 +12,7 @@ find_package(Qt${QT_VERSION_MAJOR}
find_package(Freetype) find_package(Freetype)
set(IMGUI_SOURCES include/scwx/external/imgui/imconfig.h set(IMGUI_SOURCES imgui/imconfig.h
imgui/imgui.cpp imgui/imgui.cpp
imgui/imgui.h imgui/imgui.h
imgui/imgui_demo.cpp imgui/imgui_demo.cpp
@ -33,9 +33,8 @@ set(IMGUI_SOURCES include/scwx/external/imgui/imconfig.h
add_library(imgui STATIC ${IMGUI_SOURCES}) add_library(imgui STATIC ${IMGUI_SOURCES})
target_include_directories(imgui PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/imgui) target_include_directories(imgui PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/imgui)
target_include_directories(imgui PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_compile_definitions(imgui PUBLIC IMGUI_USER_CONFIG=<scwx/external/imgui/imconfig.h>) target_compile_definitions(imgui PRIVATE IMGUI_ENABLE_FREETYPE)
target_link_libraries(imgui PRIVATE Qt${QT_VERSION_MAJOR}::Widgets target_link_libraries(imgui PRIVATE Qt${QT_VERSION_MAJOR}::Widgets
Freetype::Freetype) Freetype::Freetype)

View file

@ -1,147 +0,0 @@
// clang-format off
//-----------------------------------------------------------------------------
// DEAR IMGUI COMPILE-TIME OPTIONS
// Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure.
// You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions.
//-----------------------------------------------------------------------------
// A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/rebased branch with your modifications to it)
// B) or '#define IMGUI_USER_CONFIG "my_imgui_config.h"' in your project and then add directives in your own file without touching this template.
//-----------------------------------------------------------------------------
// You need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include the imgui*.cpp
// files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures.
// Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts.
// Call IMGUI_CHECKVERSION() from your .cpp file to verify that the data structures your files are using are matching the ones imgui.cpp is using.
//-----------------------------------------------------------------------------
#pragma once
//---- Define assertion handler. Defaults to calling assert().
// If your macro uses multiple statements, make sure is enclosed in a 'do { .. } while (0)' block so it can be used as a single statement.
//#define IM_ASSERT(_EXPR) MyAssert(_EXPR)
//#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts
//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows
// Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility.
// - Windows DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions()
// for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details.
//#define IMGUI_API __declspec(dllexport) // MSVC Windows: DLL export
//#define IMGUI_API __declspec(dllimport) // MSVC Windows: DLL import
//#define IMGUI_API __attribute__((visibility("default"))) // GCC/Clang: override visibility when set is hidden
//---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to clean your code of obsolete function/names.
#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
//---- Disable all of Dear ImGui or don't implement standard windows/tools.
// It is very strongly recommended to NOT disable the demo windows and debug tool during development. They are extremely useful in day to day work. Please read comments in imgui_demo.cpp.
//#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty.
//#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty.
//#define IMGUI_DISABLE_DEBUG_TOOLS // Disable metrics/debugger and other debug tools: ShowMetricsWindow(), ShowDebugLogWindow() and ShowIDStackToolWindow() will be empty.
//---- Don't implement some functions to reduce linkage requirements.
//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. (user32.lib/.a, kernel32.lib/.a)
//#define IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with Visual Studio] Implement default IME handler (require imm32.lib/.a, auto-link for Visual Studio, -limm32 on command-line for MinGW)
//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with non-Visual Studio compilers] Don't implement default IME handler (won't require imm32.lib/.a)
//#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, IME).
//#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default).
//#define IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS // Don't implement default platform_io.Platform_OpenInShellFn() handler (Win32: ShellExecute(), require shell32.lib/.a, Mac/Linux: use system("")).
//#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf)
//#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself.
//#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies)
//#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function.
//#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions().
//#define IMGUI_DISABLE_DEFAULT_FONT // Disable default embedded font (ProggyClean.ttf), remove ~9.5 KB from output binary. AddFontDefault() will assert.
//#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available
//---- Enable Test Engine / Automation features.
//#define IMGUI_ENABLE_TEST_ENGINE // Enable imgui_test_engine hooks. Generally set automatically by include "imgui_te_config.h", see Test Engine for details.
//---- Include imgui_user.h at the end of imgui.h as a convenience
// May be convenient for some users to only explicitly include vanilla imgui.h and have extra stuff included.
//#define IMGUI_INCLUDE_IMGUI_USER_H
//#define IMGUI_USER_H_FILENAME "my_folder/my_imgui_user.h"
//---- Pack vertex colors as BGRA8 instead of RGBA8 (to avoid converting from one to another). Need dedicated backend support.
//#define IMGUI_USE_BGRA_PACKED_COLOR
//---- Use legacy CRC32-adler tables (used before 1.91.6), in order to preserve old .ini data that you cannot afford to invalidate.
//#define IMGUI_USE_LEGACY_CRC32_ADLER
//---- Use 32-bit for ImWchar (default is 16-bit) to support Unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...)
//#define IMGUI_USE_WCHAR32
//---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version
// By default the embedded implementations are declared static and not available outside of Dear ImGui sources files.
//#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h"
//#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h"
//#define IMGUI_STB_SPRINTF_FILENAME "my_folder/stb_sprintf.h" // only used if IMGUI_USE_STB_SPRINTF is defined.
//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
//#define IMGUI_DISABLE_STB_SPRINTF_IMPLEMENTATION // only disabled if IMGUI_USE_STB_SPRINTF is defined.
//---- Use stb_sprintf.h for a faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined)
// Compatibility checks of arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by stb_sprintf.h.
//#define IMGUI_USE_STB_SPRINTF
//---- Use FreeType to build and rasterize the font atlas (instead of stb_truetype which is embedded by default in Dear ImGui)
// Requires FreeType headers to be available in the include path. Requires program to be compiled with 'misc/freetype/imgui_freetype.cpp' (in this repository) + the FreeType library (not provided).
// On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'.
#define IMGUI_ENABLE_FREETYPE
//---- Use FreeType + plutosvg or lunasvg to render OpenType SVG fonts (SVGinOT)
// Only works in combination with IMGUI_ENABLE_FREETYPE.
// - plutosvg is currently easier to install, as e.g. it is part of vcpkg. It will support more fonts and may load them faster. See misc/freetype/README for instructions.
// - Both require headers to be available in the include path + program to be linked with the library code (not provided).
// - (note: lunasvg implementation is based on Freetype's rsvg-port.c which is licensed under CeCILL-C Free Software License Agreement)
//#define IMGUI_ENABLE_FREETYPE_PLUTOSVG
//#define IMGUI_ENABLE_FREETYPE_LUNASVG
//---- Use stb_truetype to build and rasterize the font atlas (default)
// The only purpose of this define is if you want force compilation of the stb_truetype backend ALONG with the FreeType backend.
//#define IMGUI_ENABLE_STB_TRUETYPE
//---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4.
// This will be inlined as part of ImVec2 and ImVec4 class declarations.
/*
#define IM_VEC2_CLASS_EXTRA \
constexpr ImVec2(const MyVec2& f) : x(f.x), y(f.y) {} \
operator MyVec2() const { return MyVec2(x,y); }
#define IM_VEC4_CLASS_EXTRA \
constexpr ImVec4(const MyVec4& f) : x(f.x), y(f.y), z(f.z), w(f.w) {} \
operator MyVec4() const { return MyVec4(x,y,z,w); }
*/
//---- ...Or use Dear ImGui's own very basic math operators.
//#define IMGUI_DEFINE_MATH_OPERATORS
//---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices.
// Your renderer backend will need to support it (most example renderer backends support both 16/32-bit indices).
// Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer.
// Read about ImGuiBackendFlags_RendererHasVtxOffset for details.
//#define ImDrawIdx unsigned int
//---- Override ImDrawCallback signature (will need to modify renderer backends accordingly)
//struct ImDrawList;
//struct ImDrawCmd;
//typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data);
//#define ImDrawCallback MyImDrawCallback
//---- Debug Tools: Macro to break in Debugger (we provide a default implementation of this in the codebase)
// (use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging.)
//#define IM_DEBUG_BREAK IM_ASSERT(0)
//#define IM_DEBUG_BREAK __debugbreak()
//---- Debug Tools: Enable highlight ID conflicts _before_ hovering items. When io.ConfigDebugHighlightIdConflicts is set.
// (THIS WILL SLOW DOWN DEAR IMGUI. Only use occasionally and disable after use)
//#define IMGUI_DEBUG_HIGHLIGHT_ALL_ID_CONFLICTS
//---- Debug Tools: Enable slower asserts
//#define IMGUI_DEBUG_PARANOID
//---- Tip: You can add extra functions within the ImGui:: namespace from anywhere (e.g. your own sources/header files)
/*
namespace ImGui
{
void MyFunction(const char* name, MyMatrix44* mtx);
}
*/
// clang-format on

@ -1 +1 @@
Subproject commit 3654f5fa9f06534d7fd2d95b810049a82e5953ef Subproject commit 3d4ca3fdf07c50db3002b11bff93c81ec380e493

@ -1 +1 @@
Subproject commit 8b40697895c19da4479cd037a76608f4c36935e8 Subproject commit 805ccf6204a546e43fed599631ad5d698f68ae86

View file

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.24) cmake_minimum_required(VERSION 3.20)
set(PROJECT_NAME scwx-mln) set(PROJECT_NAME scwx-mln)
set(gtest_disable_pthreads ON) set(gtest_disable_pthreads ON)
@ -19,28 +19,11 @@ if (MSVC)
target_link_options(MLNQtCore PRIVATE "$<$<CONFIG:Release>:/DEBUG>") target_link_options(MLNQtCore PRIVATE "$<$<CONFIG:Release>:/DEBUG>")
target_link_options(MLNQtCore PRIVATE "$<$<CONFIG:Release>:/OPT:REF>") target_link_options(MLNQtCore PRIVATE "$<$<CONFIG:Release>:/OPT:REF>")
target_link_options(MLNQtCore PRIVATE "$<$<CONFIG:Release>:/OPT:ICF>") target_link_options(MLNQtCore PRIVATE "$<$<CONFIG:Release>:/OPT:ICF>")
# Enable multi-processor compilation
target_compile_options(MLNQtCore PRIVATE "/MP")
target_compile_options(mbgl-core PRIVATE "/MP")
target_compile_options(mbgl-vendor-csscolorparser PRIVATE "/MP")
target_compile_options(mbgl-vendor-nunicode PRIVATE "/MP")
target_compile_options(mbgl-vendor-parsedate PRIVATE "/MP")
if (TARGET mbgl-vendor-sqlite)
target_compile_options(mbgl-vendor-sqlite PRIVATE "/MP")
endif()
else() else()
target_compile_options(mbgl-core PRIVATE "$<$<CONFIG:Release>:-g>") target_compile_options(mbgl-core PRIVATE "$<$<CONFIG:Release>:-g>")
target_compile_options(MLNQtCore PRIVATE "$<$<CONFIG:Release>:-g>") target_compile_options(MLNQtCore PRIVATE "$<$<CONFIG:Release>:-g>")
endif() endif()
if (APPLE)
# Enable GL check error debug
target_compile_definitions(mbgl-core PRIVATE MLN_GL_CHECK_ERRORS=1)
target_compile_definitions(MLNQtCore PRIVATE MLN_GL_CHECK_ERRORS=1)
endif()
set(MLN_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/maplibre-native/include set(MLN_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/maplibre-native/include
${CMAKE_CURRENT_SOURCE_DIR}/maplibre-native-qt/src/core/include ${CMAKE_CURRENT_SOURCE_DIR}/maplibre-native-qt/src/core/include
${CMAKE_CURRENT_BINARY_DIR}/maplibre-native-qt/src/core/include PARENT_SCOPE) ${CMAKE_CURRENT_BINARY_DIR}/maplibre-native-qt/src/core/include PARENT_SCOPE)

1
external/qt6ct vendored

@ -1 +0,0 @@
Subproject commit 2c569c6c4776ea5a1299030c079b16f70473c9e6

62
external/qt6ct.cmake vendored
View file

@ -1,62 +0,0 @@
cmake_minimum_required(VERSION 3.16.0)
set(PROJECT_NAME scwx-qt6ct)
find_package(QT NAMES Qt6
COMPONENTS Gui Widgets
REQUIRED)
find_package(Qt${QT_VERSION_MAJOR}
COMPONENTS Gui Widgets
REQUIRED)
#extract version from qt6ct.h
file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/qt6ct/src/qt6ct-common/qt6ct.h"
QT6CT_VERSION_DATA REGEX "^#define[ \t]+QT6CT_VERSION_[A-Z]+[ \t]+[0-9]+.*$")
if(QT6CT_VERSION_DATA)
foreach(item IN ITEMS MAJOR MINOR)
string(REGEX REPLACE ".*#define[ \t]+QT6CT_VERSION_${item}[ \t]+([0-9]+).*"
"\\1" QT6CT_VERSION_${item} ${QT6CT_VERSION_DATA})
endforeach()
set(QT6CT_VERSION "${QT6CT_VERSION_MAJOR}.${QT6CT_VERSION_MINOR}")
set(QT6CT_SOVERSION "${QT6CT_VERSION_MAJOR}")
message(STATUS "qt6ct version: ${QT6CT_VERSION}")
else()
message(FATAL_ERROR "invalid header")
endif()
set(qt6ct-common-source
qt6ct/src/qt6ct-common/qt6ct.cpp
)
set(qt6ct-widgets-source
qt6ct/src/qt6ct/paletteeditdialog.cpp
qt6ct/src/qt6ct/paletteeditdialog.ui
)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
include_directories(qt6ct/src/qt6ct-common)
add_library(qt6ct-common STATIC ${qt6ct-common-source})
set_target_properties(qt6ct-common PROPERTIES VERSION ${QT6CT_VERSION})
target_link_libraries(qt6ct-common PRIVATE Qt6::Gui)
target_compile_definitions(qt6ct-common PRIVATE QT6CT_LIBRARY)
add_library(qt6ct-widgets STATIC ${qt6ct-widgets-source})
set_target_properties(qt6ct-widgets PROPERTIES VERSION ${QT6CT_VERSION})
target_link_libraries(qt6ct-widgets PRIVATE Qt6::Widgets qt6ct-common)
target_compile_definitions(qt6ct-widgets PRIVATE QT6CT_LIBRARY)
if (MSVC)
# Produce PDB file for debug
target_compile_options(qt6ct-common PRIVATE "$<$<CONFIG:Release>:/Zi>")
target_compile_options(qt6ct-widgets PRIVATE "$<$<CONFIG:Release>:/Zi>")
else()
target_compile_options(qt6ct-common PRIVATE "$<$<CONFIG:Release>:-g>")
target_compile_options(qt6ct-widgets PRIVATE "$<$<CONFIG:Release>:-g>")
endif()
target_include_directories( qt6ct-common INTERFACE qt6ct/src )
target_include_directories( qt6ct-widgets INTERFACE qt6ct/src )

2
external/stb vendored

@ -1 +1 @@
Subproject commit f58f558c120e9b32c217290b80bad1a0729fbb2c Subproject commit beebb24b945efdea3b9bba23affb8eb3ba8982e7

2
external/stb.cmake vendored
View file

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.24) cmake_minimum_required(VERSION 3.20)
set(PROJECT_NAME scwx-stb) set(PROJECT_NAME scwx-stb)
set(STB_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/stb PARENT_SCOPE) set(STB_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/stb PARENT_SCOPE)

View file

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.24) cmake_minimum_required(VERSION 3.20)
set(PROJECT_NAME scwx-textflowcpp) set(PROJECT_NAME scwx-textflowcpp)
set(TEXTFLOWCPP_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/textflowcpp PARENT_SCOPE) set(TEXTFLOWCPP_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/textflowcpp PARENT_SCOPE)

View file

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.24) cmake_minimum_required(VERSION 3.20)
set(PROJECT_NAME scwx-units) set(PROJECT_NAME scwx-units)
add_subdirectory(units) add_subdirectory(units)

View file

@ -1,3 +0,0 @@
conan
geopandas
GitPython

View file

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.24) cmake_minimum_required(VERSION 3.21)
set_property(DIRECTORY set_property(DIRECTORY
APPEND APPEND

View file

@ -26,9 +26,6 @@ void main()
// Always set displayed to true // Always set displayed to true
vsOut.displayed = 1; vsOut.displayed = 1;
// Initialize texCoord to default value
vsOut.texCoord = vec3(0.0f, 0.0f, 0.0f);
// Pass the threshold and time range to the geometry shader // Pass the threshold and time range to the geometry shader
vsOut.threshold = aThreshold; vsOut.threshold = aThreshold;
vsOut.timeRange = aTimeRange; vsOut.timeRange = aTimeRange;

View file

@ -9,14 +9,14 @@ uniform float uDataMomentScale;
uniform bool uCFPEnabled; uniform bool uCFPEnabled;
in float dataMoment; flat in uint dataMoment;
in float cfpMoment; flat in uint cfpMoment;
layout (location = 0) out vec4 fragColor; layout (location = 0) out vec4 fragColor;
void main() void main()
{ {
float texCoord = (dataMoment - float(uDataMomentOffset)) / uDataMomentScale; float texCoord = float(dataMoment - uDataMomentOffset) / uDataMomentScale;
if (uCFPEnabled && cfpMoment > 8u) if (uCFPEnabled && cfpMoment > 8u)
{ {

View file

@ -13,8 +13,8 @@ layout (location = 2) in uint aCfpMoment;
uniform mat4 uMVPMatrix; uniform mat4 uMVPMatrix;
uniform vec2 uMapScreenCoord; uniform vec2 uMapScreenCoord;
out float dataMoment; flat out uint dataMoment;
out float cfpMoment; flat out uint cfpMoment;
vec2 latLngToScreenCoordinate(in vec2 latLng) vec2 latLngToScreenCoordinate(in vec2 latLng)
{ {

View file

@ -21,9 +21,7 @@ smooth out vec4 color;
void main() void main()
{ {
if (gsIn[0].displayed != 0 && if (gsIn[0].displayed != 0 &&
(gsIn[0].threshold == 0 || // If Threshold: 0 was specified, no threshold (gsIn[0].threshold <= 0 || // If Threshold: 0 was specified, no threshold
uMapDistance == 0 || // If uMapDistance is zero, threshold is disabled
(gsIn[0].threshold < 0 && -(gsIn[0].threshold) <= uMapDistance) || // If Threshold is negative and below current map distance
gsIn[0].threshold >= uMapDistance || // If Threshold is above current map distance gsIn[0].threshold >= uMapDistance || // If Threshold is above current map distance
gsIn[0].threshold >= 999) && // If Threshold: 999 was specified (or greater), no threshold gsIn[0].threshold >= 999) && // If Threshold: 999 was specified (or greater), no threshold
(gsIn[0].timeRange[0] == 0 || // If there is no start time specified (gsIn[0].timeRange[0] == 0 || // If there is no start time specified

View file

@ -67,7 +67,7 @@
{ "type": "wsr88d", "id": "KLVX", "lat": 37.9753058, "lon": -85.9438455, "country": "USA", "state": "KY", "place": "Louisville", "tz": "America/New_York", "elevation": 833.0 }, { "type": "wsr88d", "id": "KLVX", "lat": 37.9753058, "lon": -85.9438455, "country": "USA", "state": "KY", "place": "Louisville", "tz": "America/New_York", "elevation": 833.0 },
{ "type": "wsr88d", "id": "KPAH", "lat": 37.068333, "lon": -88.771944, "country": "USA", "state": "KY", "place": "Paducah", "tz": "America/Chicago", "elevation": 506.0 }, { "type": "wsr88d", "id": "KPAH", "lat": 37.068333, "lon": -88.771944, "country": "USA", "state": "KY", "place": "Paducah", "tz": "America/Chicago", "elevation": 506.0 },
{ "type": "wsr88d", "id": "KPOE", "lat": 31.1556923, "lon": -92.9762596, "country": "USA", "state": "LA", "place": "Fort Polk", "tz": "America/Chicago", "elevation": 473.0 }, { "type": "wsr88d", "id": "KPOE", "lat": 31.1556923, "lon": -92.9762596, "country": "USA", "state": "LA", "place": "Fort Polk", "tz": "America/Chicago", "elevation": 473.0 },
{ "type": "wsr88d", "id": "KHDC", "lat": 30.5196, "lon": -90.4074, "country": "USA", "state": "LA", "place": "New Orleans (Hammond)", "tz": "America/Chicago", "elevation": 43.0 }, { "type": "wsr88d", "id": "KHDC", "lat": 30.519306, "lon": -90.424028, "country": "USA", "state": "LA", "place": "New Orleans (Hammond)", "tz": "America/Chicago", "elevation": 43.0 },
{ "type": "wsr88d", "id": "KLCH", "lat": 30.125306, "lon": -93.215889, "country": "USA", "state": "LA", "place": "Lake Charles", "tz": "America/Chicago", "elevation": 137.0 }, { "type": "wsr88d", "id": "KLCH", "lat": 30.125306, "lon": -93.215889, "country": "USA", "state": "LA", "place": "Lake Charles", "tz": "America/Chicago", "elevation": 137.0 },
{ "type": "wsr88d", "id": "KSHV", "lat": 32.450833, "lon": -93.84125, "country": "USA", "state": "LA", "place": "Shreveport", "tz": "America/Chicago", "elevation": 387.0 }, { "type": "wsr88d", "id": "KSHV", "lat": 32.450833, "lon": -93.84125, "country": "USA", "state": "LA", "place": "Shreveport", "tz": "America/Chicago", "elevation": 387.0 },
{ "type": "wsr88d", "id": "KLIX", "lat": 30.3367133, "lon": -89.8256618, "country": "USA", "state": "LA", "place": "New Orleans (Slidell)", "tz": "America/Chicago", "elevation": 179.0 }, { "type": "wsr88d", "id": "KLIX", "lat": 30.3367133, "lon": -89.8256618, "country": "USA", "state": "LA", "place": "New Orleans (Slidell)", "tz": "America/Chicago", "elevation": 179.0 },

View file

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 512 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path fill="#ffffff" d="M184 48l144 0c4.4 0 8 3.6 8 8l0 40L176 96l0-40c0-4.4 3.6-8 8-8zm-56 8l0 40L64 96C28.7 96 0 124.7 0 160l0 96 192 0 128 0 192 0 0-96c0-35.3-28.7-64-64-64l-64 0 0-40c0-30.9-25.1-56-56-56L184 0c-30.9 0-56 25.1-56 56zM512 288l-192 0 0 32c0 17.7-14.3 32-32 32l-64 0c-17.7 0-32-14.3-32-32l0-32L0 288 0 416c0 35.3 28.7 64 64 64l384 0c35.3 0 64-28.7 64-64l0-128z"/></svg>

Before

Width:  |  Height:  |  Size: 623 B

View file

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 512 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path fill="#ffffff" d="M243.4 2.6l-224 96c-14 6-21.8 21-18.7 35.8S16.8 160 32 160l0 8c0 13.3 10.7 24 24 24l400 0c13.3 0 24-10.7 24-24l0-8c15.2 0 28.3-10.7 31.3-25.6s-4.8-29.9-18.7-35.8l-224-96c-8-3.4-17.2-3.4-25.2 0zM128 224l-64 0 0 196.3c-.6 .3-1.2 .7-1.8 1.1l-48 32c-11.7 7.8-17 22.4-12.9 35.9S17.9 512 32 512l448 0c14.1 0 26.5-9.2 30.6-22.7s-1.1-28.1-12.9-35.9l-48-32c-.6-.4-1.2-.7-1.8-1.1L448 224l-64 0 0 192-40 0 0-192-64 0 0 192-48 0 0-192-64 0 0 192-40 0 0-192zM256 64a32 32 0 1 1 0 64 32 32 0 1 1 0-64z"/></svg>

Before

Width:  |  Height:  |  Size: 757 B

View file

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="16" viewBox="0 0 384 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path fill="#ffffff" d="M48 0C21.5 0 0 21.5 0 48L0 464c0 26.5 21.5 48 48 48l96 0 0-80c0-26.5 21.5-48 48-48s48 21.5 48 48l0 80 96 0c26.5 0 48-21.5 48-48l0-416c0-26.5-21.5-48-48-48L48 0zM64 240c0-8.8 7.2-16 16-16l32 0c8.8 0 16 7.2 16 16l0 32c0 8.8-7.2 16-16 16l-32 0c-8.8 0-16-7.2-16-16l0-32zm112-16l32 0c8.8 0 16 7.2 16 16l0 32c0 8.8-7.2 16-16 16l-32 0c-8.8 0-16-7.2-16-16l0-32c0-8.8 7.2-16 16-16zm80 16c0-8.8 7.2-16 16-16l32 0c8.8 0 16 7.2 16 16l0 32c0 8.8-7.2 16-16 16l-32 0c-8.8 0-16-7.2-16-16l0-32zM80 96l32 0c8.8 0 16 7.2 16 16l0 32c0 8.8-7.2 16-16 16l-32 0c-8.8 0-16-7.2-16-16l0-32c0-8.8 7.2-16 16-16zm80 16c0-8.8 7.2-16 16-16l32 0c8.8 0 16 7.2 16 16l0 32c0 8.8-7.2 16-16 16l-32 0c-8.8 0-16-7.2-16-16l0-32zM272 96l32 0c8.8 0 16 7.2 16 16l0 32c0 8.8-7.2 16-16 16l-32 0c-8.8 0-16-7.2-16-16l0-32c0-8.8 7.2-16 16-16z"/></svg>

Before

Width:  |  Height:  |  Size: 1 KiB

View file

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="16" viewBox="0 0 640 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path fill="#ffffff" d="M0 112C0 67.8 35.8 32 80 32l336 0c88.4 0 160 71.6 160 160l0 160 32 0c17.7 0 32 14.3 32 32s-14.3 32-32 32l-32 0-288 0c0 53-43 96-96 96s-96-43-96-96l-16 0c-44.2 0-80-35.8-80-80L0 112zM320 352l128 0 0-96-32 0c-8.8 0-16-7.2-16-16s7.2-16 16-16l32 0 0-64c0-17.7-14.3-32-32-32l-64 0c-17.7 0-32 14.3-32 32l0 192zM96 128c-17.7 0-32 14.3-32 32l0 64c0 17.7 14.3 32 32 32l128 0c17.7 0 32-14.3 32-32l0-64c0-17.7-14.3-32-32-32L96 128zm96 336a48 48 0 1 0 0-96 48 48 0 1 0 0 96z"/></svg>

Before

Width:  |  Height:  |  Size: 732 B

View file

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" height="16" width="18" viewBox="0 0 576 512"><!--!Font Awesome Free 6.5.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2023 Fonticons, Inc.--><path opacity="1" fill="#ffffff" d="M575.8 255.5c0 18-15 32.1-32 32.1h-32l.7 160.2c0 2.7-.2 5.4-.5 8.1V472c0 22.1-17.9 40-40 40H456c-1.1 0-2.2 0-3.3-.1c-1.4 .1-2.8 .1-4.2 .1H416 392c-22.1 0-40-17.9-40-40V448 384c0-17.7-14.3-32-32-32H256c-17.7 0-32 14.3-32 32v64 24c0 22.1-17.9 40-40 40H160 128.1c-1.5 0-3-.1-4.5-.2c-1.2 .1-2.4 .2-3.6 .2H104c-22.1 0-40-17.9-40-40V360c0-.9 0-1.9 .1-2.8V287.6H32c-18 0-32-14-32-32.1c0-9 3-17 10-24L266.4 8c7-7 15-8 22-8s15 2 21 7L564.8 231.5c8 7 12 15 11 24z"/></svg>

Before

Width:  |  Height:  |  Size: 735 B

View file

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 512 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path fill="#ffffff" d="M256 0c17.7 0 32 14.3 32 32l0 34.7C368.4 80.1 431.9 143.6 445.3 224l34.7 0c17.7 0 32 14.3 32 32s-14.3 32-32 32l-34.7 0C431.9 368.4 368.4 431.9 288 445.3l0 34.7c0 17.7-14.3 32-32 32s-32-14.3-32-32l0-34.7C143.6 431.9 80.1 368.4 66.7 288L32 288c-17.7 0-32-14.3-32-32s14.3-32 32-32l34.7 0C80.1 143.6 143.6 80.1 224 66.7L224 32c0-17.7 14.3-32 32-32zM128 256a128 128 0 1 0 256 0 128 128 0 1 0 -256 0zm128-80a80 80 0 1 1 0 160 80 80 0 1 1 0-160z"/></svg>

Before

Width:  |  Height:  |  Size: 708 B

View file

@ -1,4 +0,0 @@
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="12" height="16" viewBox="0 0 384 512">
<!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.-->
<path fill="#ffffff" d="M215.7 499.2C267 435 384 279.4 384 192C384 86 298 0 192 0S0 86 0 192c0 87.4 117 243 168.3 307.2c12.3 15.3 35.1 15.3 47.4 0zM192 128a64 64 0 1 1 0 128 64 64 0 1 1 0-128z"/>
</svg>

Before

Width:  |  Height:  |  Size: 463 B

View file

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" height="16" width="18" viewBox="0 0 576 512"><!--!Font Awesome Free 6.5.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2023 Fonticons, Inc.--><path opacity="1" fill="#ffffff" d="M316.9 18C311.6 7 300.4 0 288.1 0s-23.4 7-28.8 18L195 150.3 51.4 171.5c-12 1.8-22 10.2-25.7 21.7s-.7 24.2 7.9 32.7L137.8 329 113.2 474.7c-2 12 3 24.2 12.9 31.3s23 8 33.8 2.3l128.3-68.5 128.3 68.5c10.8 5.7 23.9 4.9 33.8-2.3s14.9-19.3 12.9-31.3L438.5 329 542.7 225.9c8.6-8.5 11.7-21.2 7.9-32.7s-13.7-19.9-25.7-21.7L381.2 150.3 316.9 18z"/></svg>

Before

Width:  |  Height:  |  Size: 616 B

View file

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="16" viewBox="0 0 576 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path fill="#ffffff" d="M269.4 6C280.5-2 295.5-2 306.6 6l224 160c7.4 5.3 12.2 13.5 13.2 22.5l32 288c1 9-1.9 18.1-8 24.9s-14.7 10.7-23.8 10.7l-80 0-28.2 0c-12.1 0-23.2-6.8-28.6-17.7L306.7 293.5c-1.7-3.4-5.1-5.5-8.8-5.5c-5.5 0-9.9 4.4-9.9 9.9L288 480c0 17.7-14.3 32-32 32l-16 0L32 512c-9.1 0-17.8-3.9-23.8-10.7s-9-15.8-8-24.9l32-288c1-9 5.8-17.2 13.2-22.5L269.4 6z"/></svg>

Before

Width:  |  Height:  |  Size: 608 B

Binary file not shown.

View file

@ -1,7 +0,0 @@
[Desktop Entry]
Type=Application
Name=Supercell Wx
Comment=Weather Radar and Data Viewer
Exec=supercell-wx
Icon=net.supercellwx.app.png
Categories=Network;Science;

View file

@ -1,42 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleName</key>
<string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
<key>CFBundleExecutable</key>
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
<key>CFBundleVersion</key>
<string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
<key>CFBundleShortVersionString</key>
<string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
<key>LSMinimumSystemVersion</key>
<string>${CMAKE_OSX_DEPLOYMENT_TARGET}</string>
<key>NSHumanReadableCopyright</key>
<string>${MACOSX_BUNDLE_COPYRIGHT}</string>
<key>CFBundleIconFile</key>
<string>${MACOSX_BUNDLE_ICON_FILE}</string>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleAllowMixedLocalizations</key>
<true/>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>NSSupportsAutomaticGraphicsSwitching</key>
<true/>
</dict>
</plist>

View file

@ -1,9 +0,0 @@
<svg version="1.1"
viewBox="0 0 100 100"
width="3" height="3"
xmlns="http://www.w3.org/2000/svg">
<circle r="50" cx="50" cy="50" fill="black"></circle>
<circle r="25" cx="50" cy="50" fill="white"></circle>
</svg>

Before

Width:  |  Height:  |  Size: 241 B

View file

@ -1,11 +0,0 @@
<svg version="1.1"
viewBox="0 0 170 150"
width="17" height="15"
xmlns="http://www.w3.org/2000/svg">
<path d="M 40,118 L 85,40 L 130,118 L 40,118 L 85,40 Z"
stroke="black" stroke-width="40" fill="none"/>
<path d="M 40,118 L 85,40 L 130,118 L 40,118 L 85,40 Z"
stroke="#ffffff" stroke-width="20" fill="none"/>
</svg>

Before

Width:  |  Height:  |  Size: 357 B

View file

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.24) cmake_minimum_required(VERSION 3.21)
project(scwx-qt LANGUAGES CXX) project(scwx-qt LANGUAGES CXX)
@ -6,19 +6,17 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC OFF) set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
OPTION(SCWX_DISABLE_CONSOLE "Disables the Windows console in release mode" ON)
find_package(Boost) find_package(Boost)
find_package(Fontconfig) find_package(Fontconfig)
find_package(geographiclib) find_package(geographiclib)
find_package(geos) find_package(geos)
find_package(GLEW)
find_package(glm) find_package(glm)
find_package(OpenGL)
find_package(Python COMPONENTS Interpreter) find_package(Python COMPONENTS Interpreter)
find_package(SQLite3) find_package(SQLite3)
@ -32,9 +30,7 @@ find_package(QT NAMES Qt6
Positioning Positioning
SerialPort SerialPort
Svg Svg
Widgets Widgets REQUIRED)
Sql
REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} find_package(Qt${QT_VERSION_MAJOR}
COMPONENTS Gui COMPONENTS Gui
@ -53,13 +49,9 @@ find_package(Qt${QT_VERSION_MAJOR}
set(SRC_EXE_MAIN source/scwx/qt/main/main.cpp) set(SRC_EXE_MAIN source/scwx/qt/main/main.cpp)
set(HDR_MAIN source/scwx/qt/main/application.hpp set(HDR_MAIN source/scwx/qt/main/application.hpp
source/scwx/qt/main/check_privilege.hpp source/scwx/qt/main/main_window.hpp)
source/scwx/qt/main/main_window.hpp
source/scwx/qt/main/process_validation.hpp)
set(SRC_MAIN source/scwx/qt/main/application.cpp set(SRC_MAIN source/scwx/qt/main/application.cpp
source/scwx/qt/main/check_privilege.cpp source/scwx/qt/main/main_window.cpp)
source/scwx/qt/main/main_window.cpp
source/scwx/qt/main/process_validation.cpp)
set(UI_MAIN source/scwx/qt/main/main_window.ui) set(UI_MAIN source/scwx/qt/main/main_window.ui)
set(HDR_CONFIG source/scwx/qt/config/county_database.hpp set(HDR_CONFIG source/scwx/qt/config/county_database.hpp
source/scwx/qt/config/radar_site.hpp) source/scwx/qt/config/radar_site.hpp)
@ -103,13 +95,11 @@ set(HDR_MANAGER source/scwx/qt/manager/alert_manager.hpp
source/scwx/qt/manager/log_manager.hpp source/scwx/qt/manager/log_manager.hpp
source/scwx/qt/manager/media_manager.hpp source/scwx/qt/manager/media_manager.hpp
source/scwx/qt/manager/placefile_manager.hpp source/scwx/qt/manager/placefile_manager.hpp
source/scwx/qt/manager/marker_manager.hpp
source/scwx/qt/manager/position_manager.hpp source/scwx/qt/manager/position_manager.hpp
source/scwx/qt/manager/radar_product_manager.hpp source/scwx/qt/manager/radar_product_manager.hpp
source/scwx/qt/manager/radar_product_manager_notifier.hpp source/scwx/qt/manager/radar_product_manager_notifier.hpp
source/scwx/qt/manager/resource_manager.hpp source/scwx/qt/manager/resource_manager.hpp
source/scwx/qt/manager/settings_manager.hpp source/scwx/qt/manager/settings_manager.hpp
source/scwx/qt/manager/task_manager.hpp
source/scwx/qt/manager/text_event_manager.hpp source/scwx/qt/manager/text_event_manager.hpp
source/scwx/qt/manager/thread_manager.hpp source/scwx/qt/manager/thread_manager.hpp
source/scwx/qt/manager/timeline_manager.hpp source/scwx/qt/manager/timeline_manager.hpp
@ -121,13 +111,11 @@ set(SRC_MANAGER source/scwx/qt/manager/alert_manager.cpp
source/scwx/qt/manager/log_manager.cpp source/scwx/qt/manager/log_manager.cpp
source/scwx/qt/manager/media_manager.cpp source/scwx/qt/manager/media_manager.cpp
source/scwx/qt/manager/placefile_manager.cpp source/scwx/qt/manager/placefile_manager.cpp
source/scwx/qt/manager/marker_manager.cpp
source/scwx/qt/manager/position_manager.cpp source/scwx/qt/manager/position_manager.cpp
source/scwx/qt/manager/radar_product_manager.cpp source/scwx/qt/manager/radar_product_manager.cpp
source/scwx/qt/manager/radar_product_manager_notifier.cpp source/scwx/qt/manager/radar_product_manager_notifier.cpp
source/scwx/qt/manager/resource_manager.cpp source/scwx/qt/manager/resource_manager.cpp
source/scwx/qt/manager/settings_manager.cpp source/scwx/qt/manager/settings_manager.cpp
source/scwx/qt/manager/task_manager.cpp
source/scwx/qt/manager/text_event_manager.cpp source/scwx/qt/manager/text_event_manager.cpp
source/scwx/qt/manager/thread_manager.cpp source/scwx/qt/manager/thread_manager.cpp
source/scwx/qt/manager/timeline_manager.cpp source/scwx/qt/manager/timeline_manager.cpp
@ -144,7 +132,6 @@ set(HDR_MAP source/scwx/qt/map/alert_layer.hpp
source/scwx/qt/map/overlay_layer.hpp source/scwx/qt/map/overlay_layer.hpp
source/scwx/qt/map/overlay_product_layer.hpp source/scwx/qt/map/overlay_product_layer.hpp
source/scwx/qt/map/placefile_layer.hpp source/scwx/qt/map/placefile_layer.hpp
source/scwx/qt/map/marker_layer.hpp
source/scwx/qt/map/radar_product_layer.hpp source/scwx/qt/map/radar_product_layer.hpp
source/scwx/qt/map/radar_range_layer.hpp source/scwx/qt/map/radar_range_layer.hpp
source/scwx/qt/map/radar_site_layer.hpp) source/scwx/qt/map/radar_site_layer.hpp)
@ -159,7 +146,6 @@ set(SRC_MAP source/scwx/qt/map/alert_layer.cpp
source/scwx/qt/map/overlay_layer.cpp source/scwx/qt/map/overlay_layer.cpp
source/scwx/qt/map/overlay_product_layer.cpp source/scwx/qt/map/overlay_product_layer.cpp
source/scwx/qt/map/placefile_layer.cpp source/scwx/qt/map/placefile_layer.cpp
source/scwx/qt/map/marker_layer.cpp
source/scwx/qt/map/radar_product_layer.cpp source/scwx/qt/map/radar_product_layer.cpp
source/scwx/qt/map/radar_range_layer.cpp source/scwx/qt/map/radar_range_layer.cpp
source/scwx/qt/map/radar_site_layer.cpp) source/scwx/qt/map/radar_site_layer.cpp)
@ -168,7 +154,6 @@ set(HDR_MODEL source/scwx/qt/model/alert_model.hpp
source/scwx/qt/model/imgui_context_model.hpp source/scwx/qt/model/imgui_context_model.hpp
source/scwx/qt/model/layer_model.hpp source/scwx/qt/model/layer_model.hpp
source/scwx/qt/model/placefile_model.hpp source/scwx/qt/model/placefile_model.hpp
source/scwx/qt/model/marker_model.hpp
source/scwx/qt/model/radar_site_model.hpp source/scwx/qt/model/radar_site_model.hpp
source/scwx/qt/model/tree_item.hpp source/scwx/qt/model/tree_item.hpp
source/scwx/qt/model/tree_model.hpp) source/scwx/qt/model/tree_model.hpp)
@ -177,7 +162,6 @@ set(SRC_MODEL source/scwx/qt/model/alert_model.cpp
source/scwx/qt/model/imgui_context_model.cpp source/scwx/qt/model/imgui_context_model.cpp
source/scwx/qt/model/layer_model.cpp source/scwx/qt/model/layer_model.cpp
source/scwx/qt/model/placefile_model.cpp source/scwx/qt/model/placefile_model.cpp
source/scwx/qt/model/marker_model.cpp
source/scwx/qt/model/radar_site_model.cpp source/scwx/qt/model/radar_site_model.cpp
source/scwx/qt/model/tree_item.cpp source/scwx/qt/model/tree_item.cpp
source/scwx/qt/model/tree_model.cpp) source/scwx/qt/model/tree_model.cpp)
@ -185,11 +169,9 @@ set(HDR_REQUEST source/scwx/qt/request/download_request.hpp
source/scwx/qt/request/nexrad_file_request.hpp) source/scwx/qt/request/nexrad_file_request.hpp)
set(SRC_REQUEST source/scwx/qt/request/download_request.cpp set(SRC_REQUEST source/scwx/qt/request/download_request.cpp
source/scwx/qt/request/nexrad_file_request.cpp) source/scwx/qt/request/nexrad_file_request.cpp)
set(HDR_SETTINGS source/scwx/qt/settings/alert_palette_settings.hpp set(HDR_SETTINGS source/scwx/qt/settings/audio_settings.hpp
source/scwx/qt/settings/audio_settings.hpp
source/scwx/qt/settings/general_settings.hpp source/scwx/qt/settings/general_settings.hpp
source/scwx/qt/settings/hotkey_settings.hpp source/scwx/qt/settings/hotkey_settings.hpp
source/scwx/qt/settings/line_settings.hpp
source/scwx/qt/settings/map_settings.hpp source/scwx/qt/settings/map_settings.hpp
source/scwx/qt/settings/palette_settings.hpp source/scwx/qt/settings/palette_settings.hpp
source/scwx/qt/settings/product_settings.hpp source/scwx/qt/settings/product_settings.hpp
@ -203,11 +185,9 @@ set(HDR_SETTINGS source/scwx/qt/settings/alert_palette_settings.hpp
source/scwx/qt/settings/text_settings.hpp source/scwx/qt/settings/text_settings.hpp
source/scwx/qt/settings/ui_settings.hpp source/scwx/qt/settings/ui_settings.hpp
source/scwx/qt/settings/unit_settings.hpp) source/scwx/qt/settings/unit_settings.hpp)
set(SRC_SETTINGS source/scwx/qt/settings/alert_palette_settings.cpp set(SRC_SETTINGS source/scwx/qt/settings/audio_settings.cpp
source/scwx/qt/settings/audio_settings.cpp
source/scwx/qt/settings/general_settings.cpp source/scwx/qt/settings/general_settings.cpp
source/scwx/qt/settings/hotkey_settings.cpp source/scwx/qt/settings/hotkey_settings.cpp
source/scwx/qt/settings/line_settings.cpp
source/scwx/qt/settings/map_settings.cpp source/scwx/qt/settings/map_settings.cpp
source/scwx/qt/settings/palette_settings.cpp source/scwx/qt/settings/palette_settings.cpp
source/scwx/qt/settings/product_settings.cpp source/scwx/qt/settings/product_settings.cpp
@ -230,7 +210,6 @@ set(HDR_TYPES source/scwx/qt/types/alert_types.hpp
source/scwx/qt/types/layer_types.hpp source/scwx/qt/types/layer_types.hpp
source/scwx/qt/types/location_types.hpp source/scwx/qt/types/location_types.hpp
source/scwx/qt/types/map_types.hpp source/scwx/qt/types/map_types.hpp
source/scwx/qt/types/marker_types.hpp
source/scwx/qt/types/media_types.hpp source/scwx/qt/types/media_types.hpp
source/scwx/qt/types/qt_types.hpp source/scwx/qt/types/qt_types.hpp
source/scwx/qt/types/radar_product_record.hpp source/scwx/qt/types/radar_product_record.hpp
@ -259,13 +238,10 @@ set(HDR_UI source/scwx/qt/ui/about_dialog.hpp
source/scwx/qt/ui/alert_dialog.hpp source/scwx/qt/ui/alert_dialog.hpp
source/scwx/qt/ui/alert_dock_widget.hpp source/scwx/qt/ui/alert_dock_widget.hpp
source/scwx/qt/ui/animation_dock_widget.hpp source/scwx/qt/ui/animation_dock_widget.hpp
source/scwx/qt/ui/api_key_edit_widget.hpp
source/scwx/qt/ui/collapsible_group.hpp source/scwx/qt/ui/collapsible_group.hpp
source/scwx/qt/ui/county_dialog.hpp source/scwx/qt/ui/county_dialog.hpp
source/scwx/qt/ui/custom_layer_dialog.hpp source/scwx/qt/ui/wfo_dialog.hpp
source/scwx/qt/ui/download_dialog.hpp source/scwx/qt/ui/download_dialog.hpp
source/scwx/qt/ui/edit_line_dialog.hpp
source/scwx/qt/ui/edit_marker_dialog.hpp
source/scwx/qt/ui/flow_layout.hpp source/scwx/qt/ui/flow_layout.hpp
source/scwx/qt/ui/gps_info_dialog.hpp source/scwx/qt/ui/gps_info_dialog.hpp
source/scwx/qt/ui/hotkey_edit.hpp source/scwx/qt/ui/hotkey_edit.hpp
@ -276,29 +252,22 @@ set(HDR_UI source/scwx/qt/ui/about_dialog.hpp
source/scwx/qt/ui/level2_products_widget.hpp source/scwx/qt/ui/level2_products_widget.hpp
source/scwx/qt/ui/level2_settings_widget.hpp source/scwx/qt/ui/level2_settings_widget.hpp
source/scwx/qt/ui/level3_products_widget.hpp source/scwx/qt/ui/level3_products_widget.hpp
source/scwx/qt/ui/line_label.hpp
source/scwx/qt/ui/open_url_dialog.hpp source/scwx/qt/ui/open_url_dialog.hpp
source/scwx/qt/ui/placefile_dialog.hpp source/scwx/qt/ui/placefile_dialog.hpp
source/scwx/qt/ui/placefile_settings_widget.hpp source/scwx/qt/ui/placefile_settings_widget.hpp
source/scwx/qt/ui/marker_dialog.hpp
source/scwx/qt/ui/marker_settings_widget.hpp
source/scwx/qt/ui/progress_dialog.hpp source/scwx/qt/ui/progress_dialog.hpp
source/scwx/qt/ui/radar_site_dialog.hpp source/scwx/qt/ui/radar_site_dialog.hpp
source/scwx/qt/ui/serial_port_dialog.hpp source/scwx/qt/ui/serial_port_dialog.hpp
source/scwx/qt/ui/settings_dialog.hpp source/scwx/qt/ui/settings_dialog.hpp
source/scwx/qt/ui/update_dialog.hpp source/scwx/qt/ui/update_dialog.hpp)
source/scwx/qt/ui/wfo_dialog.hpp)
set(SRC_UI source/scwx/qt/ui/about_dialog.cpp set(SRC_UI source/scwx/qt/ui/about_dialog.cpp
source/scwx/qt/ui/alert_dialog.cpp source/scwx/qt/ui/alert_dialog.cpp
source/scwx/qt/ui/alert_dock_widget.cpp source/scwx/qt/ui/alert_dock_widget.cpp
source/scwx/qt/ui/animation_dock_widget.cpp source/scwx/qt/ui/animation_dock_widget.cpp
source/scwx/qt/ui/api_key_edit_widget.cpp
source/scwx/qt/ui/collapsible_group.cpp source/scwx/qt/ui/collapsible_group.cpp
source/scwx/qt/ui/county_dialog.cpp source/scwx/qt/ui/county_dialog.cpp
source/scwx/qt/ui/custom_layer_dialog.cpp source/scwx/qt/ui/wfo_dialog.cpp
source/scwx/qt/ui/download_dialog.cpp source/scwx/qt/ui/download_dialog.cpp
source/scwx/qt/ui/edit_line_dialog.cpp
source/scwx/qt/ui/edit_marker_dialog.cpp
source/scwx/qt/ui/flow_layout.cpp source/scwx/qt/ui/flow_layout.cpp
source/scwx/qt/ui/gps_info_dialog.cpp source/scwx/qt/ui/gps_info_dialog.cpp
source/scwx/qt/ui/hotkey_edit.cpp source/scwx/qt/ui/hotkey_edit.cpp
@ -309,47 +278,36 @@ set(SRC_UI source/scwx/qt/ui/about_dialog.cpp
source/scwx/qt/ui/level2_products_widget.cpp source/scwx/qt/ui/level2_products_widget.cpp
source/scwx/qt/ui/level2_settings_widget.cpp source/scwx/qt/ui/level2_settings_widget.cpp
source/scwx/qt/ui/level3_products_widget.cpp source/scwx/qt/ui/level3_products_widget.cpp
source/scwx/qt/ui/line_label.cpp
source/scwx/qt/ui/open_url_dialog.cpp source/scwx/qt/ui/open_url_dialog.cpp
source/scwx/qt/ui/placefile_dialog.cpp source/scwx/qt/ui/placefile_dialog.cpp
source/scwx/qt/ui/placefile_settings_widget.cpp source/scwx/qt/ui/placefile_settings_widget.cpp
source/scwx/qt/ui/marker_dialog.cpp
source/scwx/qt/ui/marker_settings_widget.cpp
source/scwx/qt/ui/progress_dialog.cpp source/scwx/qt/ui/progress_dialog.cpp
source/scwx/qt/ui/radar_site_dialog.cpp source/scwx/qt/ui/radar_site_dialog.cpp
source/scwx/qt/ui/settings_dialog.cpp source/scwx/qt/ui/settings_dialog.cpp
source/scwx/qt/ui/serial_port_dialog.cpp source/scwx/qt/ui/serial_port_dialog.cpp
source/scwx/qt/ui/update_dialog.cpp source/scwx/qt/ui/update_dialog.cpp)
source/scwx/qt/ui/wfo_dialog.cpp)
set(UI_UI source/scwx/qt/ui/about_dialog.ui set(UI_UI source/scwx/qt/ui/about_dialog.ui
source/scwx/qt/ui/alert_dialog.ui source/scwx/qt/ui/alert_dialog.ui
source/scwx/qt/ui/alert_dock_widget.ui source/scwx/qt/ui/alert_dock_widget.ui
source/scwx/qt/ui/animation_dock_widget.ui source/scwx/qt/ui/animation_dock_widget.ui
source/scwx/qt/ui/collapsible_group.ui source/scwx/qt/ui/collapsible_group.ui
source/scwx/qt/ui/county_dialog.ui source/scwx/qt/ui/county_dialog.ui
source/scwx/qt/ui/custom_layer_dialog.ui source/scwx/qt/ui/wfo_dialog.ui
source/scwx/qt/ui/edit_line_dialog.ui
source/scwx/qt/ui/edit_marker_dialog.ui
source/scwx/qt/ui/gps_info_dialog.ui source/scwx/qt/ui/gps_info_dialog.ui
source/scwx/qt/ui/imgui_debug_dialog.ui source/scwx/qt/ui/imgui_debug_dialog.ui
source/scwx/qt/ui/layer_dialog.ui source/scwx/qt/ui/layer_dialog.ui
source/scwx/qt/ui/open_url_dialog.ui source/scwx/qt/ui/open_url_dialog.ui
source/scwx/qt/ui/placefile_dialog.ui source/scwx/qt/ui/placefile_dialog.ui
source/scwx/qt/ui/placefile_settings_widget.ui source/scwx/qt/ui/placefile_settings_widget.ui
source/scwx/qt/ui/marker_dialog.ui
source/scwx/qt/ui/marker_settings_widget.ui
source/scwx/qt/ui/progress_dialog.ui source/scwx/qt/ui/progress_dialog.ui
source/scwx/qt/ui/radar_site_dialog.ui source/scwx/qt/ui/radar_site_dialog.ui
source/scwx/qt/ui/settings_dialog.ui source/scwx/qt/ui/settings_dialog.ui
source/scwx/qt/ui/serial_port_dialog.ui source/scwx/qt/ui/serial_port_dialog.ui
source/scwx/qt/ui/update_dialog.ui source/scwx/qt/ui/update_dialog.ui)
source/scwx/qt/ui/wfo_dialog.ui) set(HDR_UI_SETTINGS source/scwx/qt/ui/settings/hotkey_settings_widget.hpp
set(HDR_UI_SETTINGS source/scwx/qt/ui/settings/alert_palette_settings_widget.hpp
source/scwx/qt/ui/settings/hotkey_settings_widget.hpp
source/scwx/qt/ui/settings/settings_page_widget.hpp source/scwx/qt/ui/settings/settings_page_widget.hpp
source/scwx/qt/ui/settings/unit_settings_widget.hpp) source/scwx/qt/ui/settings/unit_settings_widget.hpp)
set(SRC_UI_SETTINGS source/scwx/qt/ui/settings/alert_palette_settings_widget.cpp set(SRC_UI_SETTINGS source/scwx/qt/ui/settings/hotkey_settings_widget.cpp
source/scwx/qt/ui/settings/hotkey_settings_widget.cpp
source/scwx/qt/ui/settings/settings_page_widget.cpp source/scwx/qt/ui/settings/settings_page_widget.cpp
source/scwx/qt/ui/settings/unit_settings_widget.cpp) source/scwx/qt/ui/settings/unit_settings_widget.cpp)
set(HDR_UI_SETUP source/scwx/qt/ui/setup/audio_codec_page.hpp set(HDR_UI_SETUP source/scwx/qt/ui/setup/audio_codec_page.hpp
@ -364,9 +322,6 @@ set(SRC_UI_SETUP source/scwx/qt/ui/setup/audio_codec_page.cpp
source/scwx/qt/ui/setup/map_provider_page.cpp source/scwx/qt/ui/setup/map_provider_page.cpp
source/scwx/qt/ui/setup/setup_wizard.cpp source/scwx/qt/ui/setup/setup_wizard.cpp
source/scwx/qt/ui/setup/welcome_page.cpp) source/scwx/qt/ui/setup/welcome_page.cpp)
set(HDR_UI_WIDGETS source/scwx/qt/ui/widgets/focused_combo_box.hpp
source/scwx/qt/ui/widgets/focused_double_spin_box.hpp
source/scwx/qt/ui/widgets/focused_spin_box.hpp)
set(HDR_UTIL source/scwx/qt/util/color.hpp set(HDR_UTIL source/scwx/qt/util/color.hpp
source/scwx/qt/util/file.hpp source/scwx/qt/util/file.hpp
source/scwx/qt/util/geographic_lib.hpp source/scwx/qt/util/geographic_lib.hpp
@ -376,10 +331,8 @@ set(HDR_UTIL source/scwx/qt/util/color.hpp
source/scwx/qt/util/network.hpp source/scwx/qt/util/network.hpp
source/scwx/qt/util/streams.hpp source/scwx/qt/util/streams.hpp
source/scwx/qt/util/texture_atlas.hpp source/scwx/qt/util/texture_atlas.hpp
source/scwx/qt/util/q_color_modulate.hpp
source/scwx/qt/util/q_file_buffer.hpp source/scwx/qt/util/q_file_buffer.hpp
source/scwx/qt/util/q_file_input_stream.hpp source/scwx/qt/util/q_file_input_stream.hpp
source/scwx/qt/util/queue_counter.hpp
source/scwx/qt/util/time.hpp source/scwx/qt/util/time.hpp
source/scwx/qt/util/tooltip.hpp) source/scwx/qt/util/tooltip.hpp)
set(SRC_UTIL source/scwx/qt/util/color.cpp set(SRC_UTIL source/scwx/qt/util/color.cpp
@ -390,10 +343,8 @@ set(SRC_UTIL source/scwx/qt/util/color.cpp
source/scwx/qt/util/maplibre.cpp source/scwx/qt/util/maplibre.cpp
source/scwx/qt/util/network.cpp source/scwx/qt/util/network.cpp
source/scwx/qt/util/texture_atlas.cpp source/scwx/qt/util/texture_atlas.cpp
source/scwx/qt/util/q_color_modulate.cpp
source/scwx/qt/util/q_file_buffer.cpp source/scwx/qt/util/q_file_buffer.cpp
source/scwx/qt/util/q_file_input_stream.cpp source/scwx/qt/util/q_file_input_stream.cpp
source/scwx/qt/util/queue_counter.cpp
source/scwx/qt/util/time.cpp source/scwx/qt/util/time.cpp
source/scwx/qt/util/tooltip.cpp) source/scwx/qt/util/tooltip.cpp)
set(HDR_VIEW source/scwx/qt/view/level2_product_view.hpp set(HDR_VIEW source/scwx/qt/view/level2_product_view.hpp
@ -434,13 +385,13 @@ set(JSON_FILES res/config/radar_sites.json)
set(TS_FILES ts/scwx_en_US.ts) set(TS_FILES ts/scwx_en_US.ts)
set(RADAR_SITES_FILE ${scwx-qt_SOURCE_DIR}/res/config/radar_sites.json) set(RADAR_SITES_FILE ${scwx-qt_SOURCE_DIR}/res/config/radar_sites.json)
set(COUNTY_DBF_FILES ${SCWX_DIR}/data/db/c_18mr25.dbf) set(COUNTY_DBF_FILES ${SCWX_DIR}/data/db/c_05mr24.dbf)
set(ZONE_DBF_FILES ${SCWX_DIR}/data/db/fz18mr25.dbf set(ZONE_DBF_FILES ${SCWX_DIR}/data/db/fz05mr24.dbf
${SCWX_DIR}/data/db/mz18mr25.dbf ${SCWX_DIR}/data/db/mz05mr24.dbf
${SCWX_DIR}/data/db/oz18mr25.dbf ${SCWX_DIR}/data/db/oz05mr24.dbf
${SCWX_DIR}/data/db/z_18mr25.dbf) ${SCWX_DIR}/data/db/z_05mr24.dbf)
set(STATE_DBF_FILES ${SCWX_DIR}/data/db/s_18mr25.dbf) set(STATE_DBF_FILES ${SCWX_DIR}/data/db/s_05mr24.dbf)
set(WFO_DBF_FILES ${SCWX_DIR}/data/db/w_18mr25.dbf) set(WFO_DBF_FILES ${SCWX_DIR}/data/db/w_05mr24.dbf)
set(COUNTIES_SQLITE_DB ${scwx-qt_BINARY_DIR}/res/db/counties.db) set(COUNTIES_SQLITE_DB ${scwx-qt_BINARY_DIR}/res/db/counties.db)
set(RESOURCE_INPUT ${scwx-qt_SOURCE_DIR}/res/scwx-qt.rc.in) set(RESOURCE_INPUT ${scwx-qt_SOURCE_DIR}/res/scwx-qt.rc.in)
@ -478,19 +429,17 @@ set(PROJECT_SOURCES ${HDR_MAIN}
${SRC_UI_SETTINGS} ${SRC_UI_SETTINGS}
${HDR_UI_SETUP} ${HDR_UI_SETUP}
${SRC_UI_SETUP} ${SRC_UI_SETUP}
${HDR_UI_WIDGETS}
${HDR_UTIL} ${HDR_UTIL}
${SRC_UTIL} ${SRC_UTIL}
${HDR_VIEW} ${HDR_VIEW}
${SRC_VIEW} ${SRC_VIEW}
${SHADER_FILES} ${SHADER_FILES}
${JSON_FILES} ${JSON_FILES}
${RESOURCE_FILES}
${TS_FILES} ${TS_FILES}
${CMAKE_FILES}) ${CMAKE_FILES})
set(EXECUTABLE_SOURCES ${SRC_EXE_MAIN}) set(EXECUTABLE_SOURCES ${SRC_EXE_MAIN})
qt_add_resources(PROJECT_SOURCES ${RESOURCE_FILES})
source_group("Header Files\\main" FILES ${HDR_MAIN}) source_group("Header Files\\main" FILES ${HDR_MAIN})
source_group("Source Files\\main" FILES ${SRC_MAIN}) source_group("Source Files\\main" FILES ${SRC_MAIN})
source_group("Header Files\\config" FILES ${HDR_CONFIG}) source_group("Header Files\\config" FILES ${HDR_CONFIG})
@ -519,7 +468,6 @@ source_group("Header Files\\ui\\settings" FILES ${HDR_UI_SETTINGS})
source_group("Source Files\\ui\\settings" FILES ${SRC_UI_SETTINGS}) source_group("Source Files\\ui\\settings" FILES ${SRC_UI_SETTINGS})
source_group("Header Files\\ui\\setup" FILES ${HDR_UI_SETUP}) source_group("Header Files\\ui\\setup" FILES ${HDR_UI_SETUP})
source_group("Source Files\\ui\\setup" FILES ${SRC_UI_SETUP}) source_group("Source Files\\ui\\setup" FILES ${SRC_UI_SETUP})
source_group("Header Files\\ui\\widgets" FILES ${HDR_UI_WIDGETS})
source_group("UI Files\\ui" FILES ${UI_UI}) source_group("UI Files\\ui" FILES ${UI_UI})
source_group("Header Files\\util" FILES ${HDR_UTIL}) source_group("Header Files\\util" FILES ${HDR_UTIL})
source_group("Source Files\\util" FILES ${SRC_UTIL}) source_group("Source Files\\util" FILES ${SRC_UTIL})
@ -532,7 +480,6 @@ source_group("I18N Files" FILES ${TS_FILES})
add_library(scwx-qt OBJECT ${PROJECT_SOURCES}) add_library(scwx-qt OBJECT ${PROJECT_SOURCES})
set_property(TARGET scwx-qt PROPERTY AUTOMOC ON) set_property(TARGET scwx-qt PROPERTY AUTOMOC ON)
set_property(TARGET scwx-qt PROPERTY AUTOGEN_ORIGIN_DEPENDS OFF)
add_custom_command(OUTPUT ${COUNTIES_SQLITE_DB} add_custom_command(OUTPUT ${COUNTIES_SQLITE_DB}
COMMAND ${Python_EXECUTABLE} COMMAND ${Python_EXECUTABLE}
@ -579,8 +526,7 @@ else()
-v ${SCWX_VERSION} -v ${SCWX_VERSION}
-c ${VERSIONS_CACHE} -c ${VERSIONS_CACHE}
-i ${VERSIONS_INPUT} -i ${VERSIONS_INPUT}
-o ${VERSIONS_HEADER} -o ${VERSIONS_HEADER})
-b ${SCWX_BUILD_NUM})
endif() endif()
add_custom_target(scwx-qt_generate_versions ALL add_custom_target(scwx-qt_generate_versions ALL
@ -626,29 +572,7 @@ set_target_properties(scwx-qt_update_radar_sites PROPERTIES FOLDER generate)
if (WIN32) if (WIN32)
set(APP_ICON_RESOURCE_WINDOWS ${RESOURCE_OUTPUT}) set(APP_ICON_RESOURCE_WINDOWS ${RESOURCE_OUTPUT})
qt_add_executable(supercell-wx ${EXECUTABLE_SOURCES} ${APP_ICON_RESOURCE_WINDOWS}) qt_add_executable(supercell-wx ${EXECUTABLE_SOURCES} ${APP_ICON_RESOURCE_WINDOWS})
if (SCWX_DISABLE_CONSOLE) set_target_properties(supercell-wx PROPERTIES WIN32_EXECUTABLE $<IF:$<CONFIG:Release>,TRUE,FALSE>)
set_target_properties(supercell-wx PROPERTIES WIN32_EXECUTABLE $<IF:$<CONFIG:Release>,TRUE,FALSE>)
endif()
elseif (APPLE)
set(SCWX_ICON "${scwx-qt_SOURCE_DIR}/res/icons/scwx.icns")
set_source_files_properties(${SCWX_ICON} PROPERTIES MACOSX_PACKAGE_LOCATION "Resources")
qt_add_executable(supercell-wx ${EXECUTABLE_SOURCES} ${SCWX_ICON})
string(TIMESTAMP CURRENT_YEAR "%Y")
set_target_properties(supercell-wx PROPERTIES
MACOSX_BUNDLE TRUE
MACOSX_BUNDLE_INFO_PLIST "${scwx-qt_SOURCE_DIR}/res/scwx-qt.plist.in"
MACOSX_BUNDLE_GUI_IDENTIFIER "net.supercellwx.app"
MACOSX_BUNDLE_BUNDLE_NAME "Supercell Wx"
MACOSX_BUNDLE_BUNDLE_VERSION "${SCWX_VERSION}"
MACOSX_BUNDLE_SHORT_VERSION_STRING "${SCWX_VERSION}"
MACOSX_BUNDLE_COPYRIGHT "Copyright ${CURRENT_YEAR} Dan Paulat"
MACOSX_BUNDLE_ICON_FILE "scwx.icns"
MACOSX_BUNDLE_INFO_STRING "Free and open source advanced weather radar"
RESOURCE ${SCWX_ICON})
else() else()
qt_add_executable(supercell-wx ${EXECUTABLE_SOURCES}) qt_add_executable(supercell-wx ${EXECUTABLE_SOURCES})
endif() endif()
@ -658,17 +582,12 @@ if (WIN32)
target_compile_definitions(supercell-wx PUBLIC WIN32_LEAN_AND_MEAN) target_compile_definitions(supercell-wx PUBLIC WIN32_LEAN_AND_MEAN)
endif() endif()
if (LINUX) if (NOT MSVC)
# Qt emit keyword is incompatible with TBB # Qt emit keyword is incompatible with TBB
target_compile_definitions(scwx-qt PRIVATE QT_NO_EMIT) target_compile_definitions(scwx-qt PRIVATE QT_NO_EMIT)
target_compile_definitions(supercell-wx PRIVATE QT_NO_EMIT) target_compile_definitions(supercell-wx PRIVATE QT_NO_EMIT)
endif() endif()
if (APPLE)
target_compile_definitions(scwx-qt PRIVATE GL_SILENCE_DEPRECATION)
target_compile_definitions(supercell-wx PRIVATE GL_SILENCE_DEPRECATION)
endif()
target_include_directories(scwx-qt PUBLIC ${scwx-qt_SOURCE_DIR}/source target_include_directories(scwx-qt PUBLIC ${scwx-qt_SOURCE_DIR}/source
${FTGL_INCLUDE_DIR} ${FTGL_INCLUDE_DIR}
${IMGUI_INCLUDE_DIRS} ${IMGUI_INCLUDE_DIRS}
@ -724,25 +643,6 @@ else()
target_compile_options(supercell-wx PRIVATE "$<$<CONFIG:Release>:-g>") target_compile_options(supercell-wx PRIVATE "$<$<CONFIG:Release>:-g>")
endif() endif()
if (LINUX)
# Add wayland client packages
find_package(QT NAMES Qt6
COMPONENTS WaylandClient
REQUIRED)
find_package(Qt${QT_VERSION_MAJOR}
COMPONENTS WaylandClient
REQUIRED)
target_link_libraries(scwx-qt PUBLIC Qt${QT_VERSION_MAJOR}::WaylandClient)
endif()
if (LINUX)
find_package(mesa-glu REQUIRED)
target_link_libraries(scwx-qt PUBLIC mesa-glu::mesa-glu)
else()
target_link_libraries(scwx-qt PUBLIC OpenGL::GLU)
endif()
target_link_libraries(scwx-qt PUBLIC Qt${QT_VERSION_MAJOR}::Widgets target_link_libraries(scwx-qt PUBLIC Qt${QT_VERSION_MAJOR}::Widgets
Qt${QT_VERSION_MAJOR}::OpenGLWidgets Qt${QT_VERSION_MAJOR}::OpenGLWidgets
Qt${QT_VERSION_MAJOR}::Multimedia Qt${QT_VERSION_MAJOR}::Multimedia
@ -751,7 +651,6 @@ target_link_libraries(scwx-qt PUBLIC Qt${QT_VERSION_MAJOR}::Widgets
Qt${QT_VERSION_MAJOR}::Svg Qt${QT_VERSION_MAJOR}::Svg
Boost::json Boost::json
Boost::timer Boost::timer
Boost::atomic
QMapLibre::Core QMapLibre::Core
$<$<CXX_COMPILER_ID:MSVC>:opengl32> $<$<CXX_COMPILER_ID:MSVC>:opengl32>
$<$<CXX_COMPILER_ID:MSVC>:SetupAPI> $<$<CXX_COMPILER_ID:MSVC>:SetupAPI>
@ -759,22 +658,18 @@ target_link_libraries(scwx-qt PUBLIC Qt${QT_VERSION_MAJOR}::Widgets
GeographicLib::GeographicLib GeographicLib::GeographicLib
GEOS::geos GEOS::geos
GEOS::geos_cxx_flags GEOS::geos_cxx_flags
glad_gl_core_33 GLEW::GLEW
glm::glm glm::glm
imgui imgui
qt6ct-common
qt6ct-widgets
SQLite::SQLite3 SQLite::SQLite3
wxdata) wxdata)
target_link_libraries(supercell-wx PRIVATE scwx-qt target_link_libraries(supercell-wx PRIVATE scwx-qt
wxdata) wxdata)
if (LINUX) # Set DT_RUNPATH for Linux targets
# Set DT_RUNPATH for Linux targets set_target_properties(MLNQtCore PROPERTIES INSTALL_RPATH "\$ORIGIN/../lib") # QMapLibre::Core
set_target_properties(MLNQtCore PROPERTIES INSTALL_RPATH "\$ORIGIN/../lib") # QMapLibre::Core set_target_properties(supercell-wx PROPERTIES INSTALL_RPATH "\$ORIGIN/../lib")
set_target_properties(supercell-wx PROPERTIES INSTALL_RPATH "\$ORIGIN/../lib")
endif()
install(TARGETS supercell-wx install(TARGETS supercell-wx
MLNQtCore # QMapLibre::Core MLNQtCore # QMapLibre::Core
@ -784,15 +679,7 @@ install(TARGETS supercell-wx
"^(/usr)?/lib/.*\\.so(\\..*)?" "^(/usr)?/lib/.*\\.so(\\..*)?"
RUNTIME RUNTIME
COMPONENT supercell-wx COMPONENT supercell-wx
BUNDLE
DESTINATION .
COMPONENT supercell-wx
OPTIONAL
LIBRARY LIBRARY
COMPONENT supercell-wx
OPTIONAL
FRAMEWORK
DESTINATION Frameworks
COMPONENT supercell-wx COMPONENT supercell-wx
OPTIONAL) OPTIONAL)
@ -814,64 +701,14 @@ install(SCRIPT ${deploy_script_qmaplibre_core}
install(SCRIPT ${deploy_script_scwx} install(SCRIPT ${deploy_script_scwx}
COMPONENT supercell-wx) COMPONENT supercell-wx)
if (APPLE)
# Install additional script to fix up the bundle
install(CODE [[
include (BundleUtilities)
# Define the bundle path
set(BUNDLE_PATH "${CMAKE_INSTALL_PREFIX}/supercell-wx.app")
file(GLOB_RECURSE PLUGIN_DYLIBS "${BUNDLE_PATH}/Contents/PlugIns/**/*.dylib")
# Add the correct rpath for plugins to find bundled frameworks
foreach(PLUGIN_DYLIB ${PLUGIN_DYLIBS})
execute_process(
COMMAND install_name_tool -add_rpath "@loader_path/../../Frameworks"
${PLUGIN_DYLIB}
)
endforeach()
# Fix up the bundle with all dependencies
fixup_bundle(
"${BUNDLE_PATH}"
""
"${CMAKE_INSTALL_PREFIX}/lib;${CMAKE_INSTALL_PREFIX}/Frameworks"
)
# Re-sign the bundle
execute_process(
COMMAND codesign --force --deep --sign - "${BUNDLE_PATH}"
)
# Verify the bundle
verify_app("${BUNDLE_PATH}")
# Rename to "Supercell Wx.app"
file(REMOVE_RECURSE
"${CMAKE_INSTALL_PREFIX}/Supercell Wx.app")
file(RENAME
"${BUNDLE_PATH}"
"${CMAKE_INSTALL_PREFIX}/Supercell Wx.app")
# Remove extra directories
file(REMOVE_RECURSE
"${CMAKE_INSTALL_PREFIX}/Frameworks")
file(REMOVE_RECURSE
"${CMAKE_INSTALL_PREFIX}/lib")
]]
COMPONENT supercell-wx)
endif()
set(CPACK_PACKAGE_NAME "Supercell Wx")
set(CPACK_PACKAGE_VENDOR "Dan Paulat")
set(CPACK_PACKAGE_CHECKSUM SHA256)
set(CPACK_RESOURCE_FILE_LICENSE "${SCWX_DIR}/LICENSE.txt")
if (MSVC) if (MSVC)
set(CPACK_PACKAGE_NAME "Supercell Wx")
set(CPACK_PACKAGE_VENDOR "Dan Paulat")
set(CPACK_PACKAGE_FILE_NAME "supercell-wx-v${SCWX_VERSION}-windows-x64") set(CPACK_PACKAGE_FILE_NAME "supercell-wx-v${SCWX_VERSION}-windows-x64")
set(CPACK_PACKAGE_INSTALL_DIRECTORY "Supercell Wx") set(CPACK_PACKAGE_INSTALL_DIRECTORY "Supercell Wx")
set(CPACK_PACKAGE_ICON "${CMAKE_CURRENT_SOURCE_DIR}/res/icons/scwx-256.ico") set(CPACK_PACKAGE_ICON "${CMAKE_CURRENT_SOURCE_DIR}/res/icons/scwx-256.ico")
set(CPACK_PACKAGE_CHECKSUM SHA256)
set(CPACK_RESOURCE_FILE_LICENSE "${SCWX_DIR}/LICENSE.txt")
set(CPACK_GENERATOR WIX) set(CPACK_GENERATOR WIX)
set(CPACK_PACKAGE_EXECUTABLES "supercell-wx;Supercell Wx") set(CPACK_PACKAGE_EXECUTABLES "supercell-wx;Supercell Wx")
set(CPACK_WIX_UPGRADE_GUID 36AD0F51-4D4F-4B5D-AB61-94C6B4E4FE1C) set(CPACK_WIX_UPGRADE_GUID 36AD0F51-4D4F-4B5D-AB61-94C6B4E4FE1C)
@ -883,15 +720,5 @@ if (MSVC)
set(CPACK_INSTALL_CMAKE_PROJECTS set(CPACK_INSTALL_CMAKE_PROJECTS
"${CMAKE_CURRENT_BINARY_DIR};${CMAKE_PROJECT_NAME};supercell-wx;/") "${CMAKE_CURRENT_BINARY_DIR};${CMAKE_PROJECT_NAME};supercell-wx;/")
include(CPack)
elseif(APPLE)
set(CPACK_PACKAGE_FILE_NAME "supercell-wx-v${SCWX_VERSION}-macos")
set(CPACK_PACKAGE_ICON "${SCWX_ICON}")
set(CPACK_PACKAGE_VERSION "${SCWX_VERSION}")
set(CPACK_GENERATOR DragNDrop)
set(CPACK_COMPONENTS_ALL supercell-wx)
include(CPack) include(CPack)
endif() endif()

View file

@ -32,10 +32,6 @@
<file>res/icons/font-awesome-6/angles-up-solid.svg</file> <file>res/icons/font-awesome-6/angles-up-solid.svg</file>
<file>res/icons/font-awesome-6/backward-step-solid.svg</file> <file>res/icons/font-awesome-6/backward-step-solid.svg</file>
<file>res/icons/font-awesome-6/book-solid.svg</file> <file>res/icons/font-awesome-6/book-solid.svg</file>
<file>res/icons/font-awesome-6/briefcase-solid.svg</file>
<file>res/icons/font-awesome-6/building-columns-solid.svg</file>
<file>res/icons/font-awesome-6/building-solid.svg</file>
<file>res/icons/font-awesome-6/caravan-solid.svg</file>
<file>res/icons/font-awesome-6/copy-regular.svg</file> <file>res/icons/font-awesome-6/copy-regular.svg</file>
<file>res/icons/font-awesome-6/discord.svg</file> <file>res/icons/font-awesome-6/discord.svg</file>
<file>res/icons/font-awesome-6/earth-americas-solid.svg</file> <file>res/icons/font-awesome-6/earth-americas-solid.svg</file>
@ -44,11 +40,8 @@
<file>res/icons/font-awesome-6/gears-solid.svg</file> <file>res/icons/font-awesome-6/gears-solid.svg</file>
<file>res/icons/font-awesome-6/github.svg</file> <file>res/icons/font-awesome-6/github.svg</file>
<file>res/icons/font-awesome-6/house-solid.svg</file> <file>res/icons/font-awesome-6/house-solid.svg</file>
<file>res/icons/font-awesome-6/house-solid-white.svg</file>
<file>res/icons/font-awesome-6/keyboard-regular.svg</file> <file>res/icons/font-awesome-6/keyboard-regular.svg</file>
<file>res/icons/font-awesome-6/layer-group-solid.svg</file> <file>res/icons/font-awesome-6/layer-group-solid.svg</file>
<file>res/icons/font-awesome-6/location-crosshairs-solid.svg</file>
<file>res/icons/font-awesome-6/location-pin.svg</file>
<file>res/icons/font-awesome-6/palette-solid.svg</file> <file>res/icons/font-awesome-6/palette-solid.svg</file>
<file>res/icons/font-awesome-6/pause-solid.svg</file> <file>res/icons/font-awesome-6/pause-solid.svg</file>
<file>res/icons/font-awesome-6/play-solid.svg</file> <file>res/icons/font-awesome-6/play-solid.svg</file>
@ -60,9 +53,7 @@
<file>res/icons/font-awesome-6/square-minus-regular.svg</file> <file>res/icons/font-awesome-6/square-minus-regular.svg</file>
<file>res/icons/font-awesome-6/square-plus-regular.svg</file> <file>res/icons/font-awesome-6/square-plus-regular.svg</file>
<file>res/icons/font-awesome-6/star-solid.svg</file> <file>res/icons/font-awesome-6/star-solid.svg</file>
<file>res/icons/font-awesome-6/star-solid-white.svg</file>
<file>res/icons/font-awesome-6/stop-solid.svg</file> <file>res/icons/font-awesome-6/stop-solid.svg</file>
<file>res/icons/font-awesome-6/tent-solid.svg</file>
<file>res/icons/font-awesome-6/volume-high-solid.svg</file> <file>res/icons/font-awesome-6/volume-high-solid.svg</file>
<file>res/palettes/wct/CC.pal</file> <file>res/palettes/wct/CC.pal</file>
<file>res/palettes/wct/Default16.pal</file> <file>res/palettes/wct/Default16.pal</file>
@ -79,20 +70,11 @@
<file>res/palettes/wct/SW.pal</file> <file>res/palettes/wct/SW.pal</file>
<file>res/palettes/wct/VIL.pal</file> <file>res/palettes/wct/VIL.pal</file>
<file>res/palettes/wct/ZDR.pal</file> <file>res/palettes/wct/ZDR.pal</file>
<file alias="res/qt6ct_colors/airy.conf">../external/qt6ct/colors/airy.conf</file>
<file alias="res/qt6ct_colors/darker.conf">../external/qt6ct/colors/darker.conf</file>
<file alias="res/qt6ct_colors/dusk.conf">../external/qt6ct/colors/dusk.conf</file>
<file alias="res/qt6ct_colors/ia_ora.conf">../external/qt6ct/colors/ia_ora.conf</file>
<file alias="res/qt6ct_colors/sand.conf">../external/qt6ct/colors/sand.conf</file>
<file alias="res/qt6ct_colors/simple.conf">../external/qt6ct/colors/simple.conf</file>
<file alias="res/qt6ct_colors/waves.conf">../external/qt6ct/colors/waves.conf</file>
<file>res/textures/lines/default-1x7.png</file> <file>res/textures/lines/default-1x7.png</file>
<file>res/textures/lines/test-pattern.png</file> <file>res/textures/lines/test-pattern.png</file>
<file>res/textures/images/cursor-17.png</file> <file>res/textures/images/cursor-17.png</file>
<file>res/textures/images/crosshairs-24.png</file> <file>res/textures/images/crosshairs-24.png</file>
<file>res/textures/images/dot-3.png</file> <file>res/textures/images/dot-3.png</file>
<file>res/textures/images/dot.svg</file>
<file>res/textures/images/location-marker.svg</file>
<file>res/textures/images/mapbox-logo.svg</file> <file>res/textures/images/mapbox-logo.svg</file>
<file>res/textures/images/maptiler-logo.svg</file> <file>res/textures/images/maptiler-logo.svg</file>
</qresource> </qresource>

View file

@ -10,7 +10,7 @@
#include <boost/json.hpp> #include <boost/json.hpp>
#if (__cpp_lib_chrono < 201907L) #if !defined(_MSC_VER)
# include <date/date.h> # include <date/date.h>
#endif #endif
@ -51,7 +51,6 @@ public:
std::string state_ {}; std::string state_ {};
std::string place_ {}; std::string place_ {};
std::string tzName_ {}; std::string tzName_ {};
double altitude_ {0.0};
const scwx::util::time_zone* timeZone_ {nullptr}; const scwx::util::time_zone* timeZone_ {nullptr};
}; };
@ -143,11 +142,6 @@ const scwx::util::time_zone* RadarSite::time_zone() const
return p->timeZone_; return p->timeZone_;
} }
units::length::feet<double> RadarSite::altitude() const
{
return units::length::feet<double>(p->altitude_);
}
std::shared_ptr<RadarSite> RadarSite::Get(const std::string& id) std::shared_ptr<RadarSite> RadarSite::Get(const std::string& id)
{ {
std::shared_lock lock(siteMutex_); std::shared_lock lock(siteMutex_);
@ -245,7 +239,7 @@ size_t RadarSite::ReadConfig(const std::string& path)
bool dataValid = true; bool dataValid = true;
size_t sitesAdded = 0; size_t sitesAdded = 0;
boost::json::value j = util::json::ReadJsonQFile(path); boost::json::value j = util::json::ReadJsonFile(path);
dataValid = j.is_array(); dataValid = j.is_array();
@ -274,12 +268,10 @@ size_t RadarSite::ReadConfig(const std::string& path)
site->p->state_ = boost::json::value_to<std::string>(o.at("state")); site->p->state_ = boost::json::value_to<std::string>(o.at("state"));
site->p->place_ = boost::json::value_to<std::string>(o.at("place")); site->p->place_ = boost::json::value_to<std::string>(o.at("place"));
site->p->tzName_ = boost::json::value_to<std::string>(o.at("tz")); site->p->tzName_ = boost::json::value_to<std::string>(o.at("tz"));
site->p->altitude_ =
boost::json::value_to<double>(o.at("elevation"));
try try
{ {
#if (__cpp_lib_chrono >= 201907L) #if defined(_MSC_VER)
using namespace std::chrono; using namespace std::chrono;
#else #else
using namespace date; using namespace date;

View file

@ -6,9 +6,12 @@
#include <optional> #include <optional>
#include <string> #include <string>
#include <vector> #include <vector>
#include <units/length.h>
namespace scwx::qt::config namespace scwx
{
namespace qt
{
namespace config
{ {
class RadarSiteImpl; class RadarSiteImpl;
@ -25,19 +28,18 @@ public:
RadarSite(RadarSite&&) noexcept; RadarSite(RadarSite&&) noexcept;
RadarSite& operator=(RadarSite&&) noexcept; RadarSite& operator=(RadarSite&&) noexcept;
[[nodiscard]] std::string type() const; std::string type() const;
[[nodiscard]] std::string type_name() const; std::string type_name() const;
[[nodiscard]] std::string id() const; std::string id() const;
[[nodiscard]] double latitude() const; double latitude() const;
[[nodiscard]] double longitude() const; double longitude() const;
[[nodiscard]] std::string country() const; std::string country() const;
[[nodiscard]] std::string state() const; std::string state() const;
[[nodiscard]] std::string place() const; std::string place() const;
[[nodiscard]] std::string location_name() const; std::string location_name() const;
[[nodiscard]] std::string tz_name() const; std::string tz_name() const;
[[nodiscard]] units::length::feet<double> altitude() const;
[[nodiscard]] const scwx::util::time_zone* time_zone() const; const scwx::util::time_zone* time_zone() const;
static std::shared_ptr<RadarSite> Get(const std::string& id); static std::shared_ptr<RadarSite> Get(const std::string& id);
static std::vector<std::shared_ptr<RadarSite>> GetAll(); static std::vector<std::shared_ptr<RadarSite>> GetAll();
@ -65,4 +67,6 @@ private:
std::string GetRadarIdFromSiteId(const std::string& siteId); std::string GetRadarIdFromSiteId(const std::string& siteId);
} // namespace scwx::qt::config } // namespace config
} // namespace qt
} // namespace scwx

View file

@ -30,11 +30,13 @@ static const std::string logPrefix_ = "scwx::qt::gl::draw::draw_item";
class DrawItem::Impl class DrawItem::Impl
{ {
public: public:
explicit Impl() = default; explicit Impl(OpenGLFunctions& gl) : gl_ {gl} {}
~Impl() = default; ~Impl() {}
OpenGLFunctions& gl_;
}; };
DrawItem::DrawItem() : p(std::make_unique<Impl>()) {} DrawItem::DrawItem(OpenGLFunctions& gl) : p(std::make_unique<Impl>(gl)) {}
DrawItem::~DrawItem() = default; DrawItem::~DrawItem() = default;
DrawItem::DrawItem(DrawItem&&) noexcept = default; DrawItem::DrawItem(DrawItem&&) noexcept = default;
@ -72,7 +74,7 @@ void DrawItem::UseDefaultProjection(
0.0f, 0.0f,
static_cast<float>(params.height)); static_cast<float>(params.height));
glUniformMatrix4fv( p->gl_.glUniformMatrix4fv(
uMVPMatrixLocation, 1, GL_FALSE, glm::value_ptr(projection)); uMVPMatrixLocation, 1, GL_FALSE, glm::value_ptr(projection));
} }
@ -89,7 +91,7 @@ void DrawItem::UseRotationProjection(
glm::radians<float>(params.bearing), glm::radians<float>(params.bearing),
glm::vec3(0.0f, 0.0f, 1.0f)); glm::vec3(0.0f, 0.0f, 1.0f));
glUniformMatrix4fv( p->gl_.glUniformMatrix4fv(
uMVPMatrixLocation, 1, GL_FALSE, glm::value_ptr(projection)); uMVPMatrixLocation, 1, GL_FALSE, glm::value_ptr(projection));
} }
@ -98,14 +100,16 @@ void DrawItem::UseMapProjection(
GLint uMVPMatrixLocation, GLint uMVPMatrixLocation,
GLint uMapScreenCoordLocation) GLint uMapScreenCoordLocation)
{ {
OpenGLFunctions& gl = p->gl_;
const glm::mat4 uMVPMatrix = util::maplibre::GetMapMatrix(params); const glm::mat4 uMVPMatrix = util::maplibre::GetMapMatrix(params);
glUniform2fv(uMapScreenCoordLocation, gl.glUniform2fv(uMapScreenCoordLocation,
1, 1,
glm::value_ptr(util::maplibre::LatLongToScreenCoordinate( glm::value_ptr(util::maplibre::LatLongToScreenCoordinate(
{params.latitude, params.longitude}))); {params.latitude, params.longitude})));
glUniformMatrix4fv( gl.glUniformMatrix4fv(
uMVPMatrixLocation, 1, GL_FALSE, glm::value_ptr(uMVPMatrix)); uMVPMatrixLocation, 1, GL_FALSE, glm::value_ptr(uMVPMatrix));
} }

View file

@ -21,8 +21,8 @@ namespace draw
class DrawItem class DrawItem
{ {
public: public:
explicit DrawItem(); explicit DrawItem(OpenGLFunctions& gl);
virtual ~DrawItem(); ~DrawItem();
DrawItem(const DrawItem&) = delete; DrawItem(const DrawItem&) = delete;
DrawItem& operator=(const DrawItem&) = delete; DrawItem& operator=(const DrawItem&) = delete;

View file

@ -4,7 +4,6 @@
#include <scwx/qt/util/texture_atlas.hpp> #include <scwx/qt/util/texture_atlas.hpp>
#include <scwx/qt/util/tooltip.hpp> #include <scwx/qt/util/tooltip.hpp>
#include <scwx/util/logger.hpp> #include <scwx/util/logger.hpp>
#include <scwx/util/time.hpp>
#include <execution> #include <execution>
@ -39,7 +38,7 @@ static constexpr std::size_t kIntegersPerVertex_ = 4;
static constexpr std::size_t kIntegerBufferLength_ = static constexpr std::size_t kIntegerBufferLength_ =
kNumTriangles * kVerticesPerTriangle * kIntegersPerVertex_; kNumTriangles * kVerticesPerTriangle * kIntegersPerVertex_;
struct GeoIconDrawItem : types::EventHandler struct GeoIconDrawItem
{ {
units::length::nautical_miles<double> threshold_ {}; units::length::nautical_miles<double> threshold_ {};
std::chrono::sys_time<std::chrono::seconds> startTime_ {}; std::chrono::sys_time<std::chrono::seconds> startTime_ {};
@ -145,7 +144,7 @@ public:
}; };
GeoIcons::GeoIcons(const std::shared_ptr<GlContext>& context) : GeoIcons::GeoIcons(const std::shared_ptr<GlContext>& context) :
DrawItem(), p(std::make_unique<Impl>(context)) DrawItem(context->gl()), p(std::make_unique<Impl>(context))
{ {
} }
GeoIcons::~GeoIcons() = default; GeoIcons::~GeoIcons() = default;
@ -166,6 +165,8 @@ void GeoIcons::set_thresholded(bool thresholded)
void GeoIcons::Initialize() void GeoIcons::Initialize()
{ {
gl::OpenGLFunctions& gl = p->context_->gl();
p->shaderProgram_ = p->context_->GetShaderProgram( p->shaderProgram_ = p->context_->GetShaderProgram(
{{GL_VERTEX_SHADER, ":/gl/geo_texture2d.vert"}, {{GL_VERTEX_SHADER, ":/gl/geo_texture2d.vert"},
{GL_GEOMETRY_SHADER, ":/gl/threshold.geom"}, {GL_GEOMETRY_SHADER, ":/gl/threshold.geom"},
@ -180,95 +181,88 @@ void GeoIcons::Initialize()
p->uSelectedTimeLocation_ = p->uSelectedTimeLocation_ =
p->shaderProgram_->GetUniformLocation("uSelectedTime"); p->shaderProgram_->GetUniformLocation("uSelectedTime");
glGenVertexArrays(1, &p->vao_); gl.glGenVertexArrays(1, &p->vao_);
glGenBuffers(static_cast<GLsizei>(p->vbo_.size()), p->vbo_.data()); gl.glGenBuffers(static_cast<GLsizei>(p->vbo_.size()), p->vbo_.data());
glBindVertexArray(p->vao_); gl.glBindVertexArray(p->vao_);
glBindBuffer(GL_ARRAY_BUFFER, p->vbo_[0]); gl.glBindBuffer(GL_ARRAY_BUFFER, p->vbo_[0]);
glBufferData(GL_ARRAY_BUFFER, 0u, nullptr, GL_DYNAMIC_DRAW); gl.glBufferData(GL_ARRAY_BUFFER, 0u, nullptr, GL_DYNAMIC_DRAW);
// NOLINTBEGIN(modernize-use-nullptr)
// NOLINTBEGIN(performance-no-int-to-ptr)
// NOLINTBEGIN(cppcoreguidelines-avoid-magic-numbers)
// aLatLong // aLatLong
glVertexAttribPointer(0, gl.glVertexAttribPointer(0,
2, 2,
GL_FLOAT, GL_FLOAT,
GL_FALSE, GL_FALSE,
kPointsPerVertex * sizeof(float), kPointsPerVertex * sizeof(float),
static_cast<void*>(0)); static_cast<void*>(0));
glEnableVertexAttribArray(0); gl.glEnableVertexAttribArray(0);
// aXYOffset // aXYOffset
glVertexAttribPointer(1, gl.glVertexAttribPointer(1,
2, 2,
GL_FLOAT, GL_FLOAT,
GL_FALSE, GL_FALSE,
kPointsPerVertex * sizeof(float), kPointsPerVertex * sizeof(float),
reinterpret_cast<void*>(2 * sizeof(float))); reinterpret_cast<void*>(2 * sizeof(float)));
glEnableVertexAttribArray(1); gl.glEnableVertexAttribArray(1);
// aModulate // aModulate
glVertexAttribPointer(3, gl.glVertexAttribPointer(3,
4, 4,
GL_FLOAT, GL_FLOAT,
GL_FALSE, GL_FALSE,
kPointsPerVertex * sizeof(float), kPointsPerVertex * sizeof(float),
reinterpret_cast<void*>(4 * sizeof(float))); reinterpret_cast<void*>(4 * sizeof(float)));
glEnableVertexAttribArray(3); gl.glEnableVertexAttribArray(3);
// aAngle // aAngle
glVertexAttribPointer(4, gl.glVertexAttribPointer(4,
1, 1,
GL_FLOAT, GL_FLOAT,
GL_FALSE, GL_FALSE,
kPointsPerVertex * sizeof(float), kPointsPerVertex * sizeof(float),
reinterpret_cast<void*>(8 * sizeof(float))); reinterpret_cast<void*>(8 * sizeof(float)));
glEnableVertexAttribArray(4); gl.glEnableVertexAttribArray(4);
glBindBuffer(GL_ARRAY_BUFFER, p->vbo_[1]); gl.glBindBuffer(GL_ARRAY_BUFFER, p->vbo_[1]);
glBufferData(GL_ARRAY_BUFFER, 0u, nullptr, GL_DYNAMIC_DRAW); gl.glBufferData(GL_ARRAY_BUFFER, 0u, nullptr, GL_DYNAMIC_DRAW);
// aTexCoord // aTexCoord
glVertexAttribPointer(2, gl.glVertexAttribPointer(2,
3, 3,
GL_FLOAT, GL_FLOAT,
GL_FALSE, GL_FALSE,
kPointsPerTexCoord * sizeof(float), kPointsPerTexCoord * sizeof(float),
static_cast<void*>(0)); static_cast<void*>(0));
glEnableVertexAttribArray(2); gl.glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, p->vbo_[2]); gl.glBindBuffer(GL_ARRAY_BUFFER, p->vbo_[2]);
glBufferData(GL_ARRAY_BUFFER, 0u, nullptr, GL_DYNAMIC_DRAW); gl.glBufferData(GL_ARRAY_BUFFER, 0u, nullptr, GL_DYNAMIC_DRAW);
// aThreshold // aThreshold
glVertexAttribIPointer(5, // gl.glVertexAttribIPointer(5, //
1, 1,
GL_INT, GL_INT,
0, 0,
static_cast<void*>(0)); static_cast<void*>(0));
glEnableVertexAttribArray(5); gl.glEnableVertexAttribArray(5);
// aTimeRange // aTimeRange
glVertexAttribIPointer(6, // gl.glVertexAttribIPointer(6, //
2, 2,
GL_INT, GL_INT,
kIntegersPerVertex_ * sizeof(GLint), kIntegersPerVertex_ * sizeof(GLint),
reinterpret_cast<void*>(1 * sizeof(GLint))); reinterpret_cast<void*>(1 * sizeof(GLint)));
glEnableVertexAttribArray(6); gl.glEnableVertexAttribArray(6);
// aDisplayed // aDisplayed
glVertexAttribIPointer(7, gl.glVertexAttribPointer(7,
1, 1,
GL_INT, GL_INT,
kIntegersPerVertex_ * sizeof(GLint), GL_FALSE,
reinterpret_cast<void*>(3 * sizeof(GLint))); kIntegersPerVertex_ * sizeof(GLint),
glEnableVertexAttribArray(7); reinterpret_cast<void*>(3 * sizeof(float)));
gl.glEnableVertexAttribArray(7);
// NOLINTEND(cppcoreguidelines-avoid-magic-numbers)
// NOLINTEND(performance-no-int-to-ptr)
// NOLINTEND(modernize-use-nullptr)
p->dirty_ = true; p->dirty_ = true;
} }
@ -290,7 +284,9 @@ void GeoIcons::Render(const QMapLibre::CustomLayerRenderParameters& params,
if (!p->currentIconList_.empty()) if (!p->currentIconList_.empty())
{ {
glBindVertexArray(p->vao_); gl::OpenGLFunctions& gl = p->context_->gl();
gl.glBindVertexArray(p->vao_);
p->Update(textureAtlasChanged); p->Update(textureAtlasChanged);
p->shaderProgram_->Use(); p->shaderProgram_->Use();
@ -303,38 +299,40 @@ void GeoIcons::Render(const QMapLibre::CustomLayerRenderParameters& params,
// If thresholding is enabled, set the map distance // If thresholding is enabled, set the map distance
units::length::nautical_miles<float> mapDistance = units::length::nautical_miles<float> mapDistance =
util::maplibre::GetMapDistance(params); util::maplibre::GetMapDistance(params);
glUniform1f(p->uMapDistanceLocation_, mapDistance.value()); gl.glUniform1f(p->uMapDistanceLocation_, mapDistance.value());
} }
else else
{ {
// If thresholding is disabled, set the map distance to 0 // If thresholding is disabled, set the map distance to 0
glUniform1f(p->uMapDistanceLocation_, 0.0f); gl.glUniform1f(p->uMapDistanceLocation_, 0.0f);
} }
// Selected time // Selected time
std::chrono::system_clock::time_point selectedTime = std::chrono::system_clock::time_point selectedTime =
(p->selectedTime_ == std::chrono::system_clock::time_point {}) ? (p->selectedTime_ == std::chrono::system_clock::time_point {}) ?
scwx::util::time::now() : std::chrono::system_clock::now() :
p->selectedTime_; p->selectedTime_;
glUniform1i( gl.glUniform1i(
p->uSelectedTimeLocation_, p->uSelectedTimeLocation_,
static_cast<GLint>(std::chrono::duration_cast<std::chrono::minutes>( static_cast<GLint>(std::chrono::duration_cast<std::chrono::minutes>(
selectedTime.time_since_epoch()) selectedTime.time_since_epoch())
.count())); .count()));
// Interpolate texture coordinates // Interpolate texture coordinates
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR); gl.glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR); gl.glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Draw icons // Draw icons
glDrawArrays(GL_TRIANGLES, 0, p->numVertices_); gl.glDrawArrays(GL_TRIANGLES, 0, p->numVertices_);
} }
} }
void GeoIcons::Deinitialize() void GeoIcons::Deinitialize()
{ {
glDeleteVertexArrays(1, &p->vao_); gl::OpenGLFunctions& gl = p->context_->gl();
glDeleteBuffers(static_cast<GLsizei>(p->vbo_.size()), p->vbo_.data());
gl.glDeleteVertexArrays(1, &p->vao_);
gl.glDeleteBuffers(static_cast<GLsizei>(p->vbo_.size()), p->vbo_.data());
std::unique_lock lock {p->iconMutex_}; std::unique_lock lock {p->iconMutex_};
@ -694,7 +692,7 @@ void GeoIcons::Impl::UpdateSingleBuffer(
hoverIcons.end(), hoverIcons.end(),
[&di](auto& entry) { return entry.di_ == di; }); [&di](auto& entry) { return entry.di_ == di; });
if (di->visible_ && (!di->hoverText_.empty() || di->event_ != nullptr)) if (di->visible_ && !di->hoverText_.empty())
{ {
const units::angle::radians<double> radians = angle; const units::angle::radians<double> radians = angle;
@ -850,6 +848,8 @@ void GeoIcons::Impl::UpdateModifiedIconBuffers()
void GeoIcons::Impl::Update(bool textureAtlasChanged) void GeoIcons::Impl::Update(bool textureAtlasChanged)
{ {
gl::OpenGLFunctions& gl = context_->gl();
UpdateModifiedIconBuffers(); UpdateModifiedIconBuffers();
// If the texture atlas has changed // If the texture atlas has changed
@ -865,12 +865,11 @@ void GeoIcons::Impl::Update(bool textureAtlasChanged)
UpdateTextureBuffer(); UpdateTextureBuffer();
// Buffer texture data // Buffer texture data
glBindBuffer(GL_ARRAY_BUFFER, vbo_[1]); gl.glBindBuffer(GL_ARRAY_BUFFER, vbo_[1]);
glBufferData( gl.glBufferData(GL_ARRAY_BUFFER,
GL_ARRAY_BUFFER, sizeof(float) * textureBuffer_.size(),
static_cast<GLsizeiptr>(sizeof(float) * textureBuffer_.size()), textureBuffer_.data(),
textureBuffer_.data(), GL_DYNAMIC_DRAW);
GL_DYNAMIC_DRAW);
lastTextureAtlasChanged_ = false; lastTextureAtlasChanged_ = false;
} }
@ -879,20 +878,18 @@ void GeoIcons::Impl::Update(bool textureAtlasChanged)
if (dirty_) if (dirty_)
{ {
// Buffer vertex data // Buffer vertex data
glBindBuffer(GL_ARRAY_BUFFER, vbo_[0]); gl.glBindBuffer(GL_ARRAY_BUFFER, vbo_[0]);
glBufferData( gl.glBufferData(GL_ARRAY_BUFFER,
GL_ARRAY_BUFFER, sizeof(float) * currentIconBuffer_.size(),
static_cast<GLsizeiptr>(sizeof(float) * currentIconBuffer_.size()), currentIconBuffer_.data(),
currentIconBuffer_.data(), GL_DYNAMIC_DRAW);
GL_DYNAMIC_DRAW);
// Buffer threshold data // Buffer threshold data
glBindBuffer(GL_ARRAY_BUFFER, vbo_[2]); gl.glBindBuffer(GL_ARRAY_BUFFER, vbo_[2]);
glBufferData( gl.glBufferData(GL_ARRAY_BUFFER,
GL_ARRAY_BUFFER, sizeof(GLint) * currentIntegerBuffer_.size(),
static_cast<GLsizeiptr>(sizeof(GLint) * currentIntegerBuffer_.size()), currentIntegerBuffer_.data(),
currentIntegerBuffer_.data(), GL_DYNAMIC_DRAW);
GL_DYNAMIC_DRAW);
numVertices_ = numVertices_ =
static_cast<GLsizei>(currentIconBuffer_.size() / kPointsPerVertex); static_cast<GLsizei>(currentIconBuffer_.size() / kPointsPerVertex);
@ -907,7 +904,7 @@ bool GeoIcons::RunMousePicking(
const QPointF& mouseGlobalPos, const QPointF& mouseGlobalPos,
const glm::vec2& mouseCoords, const glm::vec2& mouseCoords,
const common::Coordinate& /* mouseGeoCoords */, const common::Coordinate& /* mouseGeoCoords */,
std::shared_ptr<types::EventHandler>& eventHandler) std::shared_ptr<types::EventHandler>& /* eventHandler */)
{ {
std::unique_lock lock {p->iconMutex_}; std::unique_lock lock {p->iconMutex_};
@ -931,7 +928,7 @@ bool GeoIcons::RunMousePicking(
// If no time has been selected, use the current time // If no time has been selected, use the current time
std::chrono::system_clock::time_point selectedTime = std::chrono::system_clock::time_point selectedTime =
(p->selectedTime_ == std::chrono::system_clock::time_point {}) ? (p->selectedTime_ == std::chrono::system_clock::time_point {}) ?
scwx::util::time::now() : std::chrono::system_clock::now() :
p->selectedTime_; p->selectedTime_;
// For each pickable icon // For each pickable icon
@ -950,10 +947,8 @@ bool GeoIcons::RunMousePicking(
units::length::nautical_miles<double> {icon.di_->threshold_} units::length::nautical_miles<double> {icon.di_->threshold_}
.value())) < 999 && .value())) < 999 &&
// Map distance is beyond/within the threshold // Map distance is beyond the threshold
icon.di_->threshold_ < mapDistance && icon.di_->threshold_ < mapDistance) ||
(icon.di_->threshold_.value() >= 0.0 ||
-(icon.di_->threshold_) > mapDistance)) ||
( (
// Geo icon has a start time // Geo icon has a start time
@ -997,27 +992,12 @@ bool GeoIcons::RunMousePicking(
if (it != p->currentHoverIcons_.crend()) if (it != p->currentHoverIcons_.crend())
{ {
itemPicked = true; itemPicked = true;
if (!it->di_->hoverText_.empty()) util::tooltip::Show(it->di_->hoverText_, mouseGlobalPos);
{
// Show tooltip
util::tooltip::Show(it->di_->hoverText_, mouseGlobalPos);
}
if (it->di_->event_ != nullptr)
{
eventHandler = it->di_;
}
} }
return itemPicked; return itemPicked;
} }
void GeoIcons::RegisterEventHandler(
const std::shared_ptr<GeoIconDrawItem>& di,
const std::function<void(QEvent*)>& eventHandler)
{
di->event_ = eventHandler;
}
} // namespace draw } // namespace draw
} // namespace gl } // namespace gl
} // namespace qt } // namespace qt

View file

@ -183,16 +183,6 @@ public:
*/ */
void FinishIcons(); void FinishIcons();
/**
* Registers an event handler for an icon.
*
* @param [in] di Icon draw item
* @param [in] eventHandler Event handler function
*/
static void
RegisterEventHandler(const std::shared_ptr<GeoIconDrawItem>& di,
const std::function<void(QEvent*)>& eventHandler);
private: private:
class Impl; class Impl;

View file

@ -3,7 +3,6 @@
#include <scwx/qt/util/maplibre.hpp> #include <scwx/qt/util/maplibre.hpp>
#include <scwx/qt/util/tooltip.hpp> #include <scwx/qt/util/tooltip.hpp>
#include <scwx/util/logger.hpp> #include <scwx/util/logger.hpp>
#include <scwx/util/time.hpp>
#include <execution> #include <execution>
@ -51,7 +50,6 @@ struct GeoLineDrawItem : types::EventHandler
units::angle::degrees<float> angle_ {}; units::angle::degrees<float> angle_ {};
std::string hoverText_ {}; std::string hoverText_ {};
GeoLines::HoverCallback hoverCallback_ {nullptr}; GeoLines::HoverCallback hoverCallback_ {nullptr};
size_t lineIndex_ {0};
}; };
class GeoLines::Impl class GeoLines::Impl
@ -89,10 +87,10 @@ public:
void UpdateBuffers(); void UpdateBuffers();
void UpdateModifiedLineBuffers(); void UpdateModifiedLineBuffers();
void UpdateSingleBuffer(const std::shared_ptr<GeoLineDrawItem>& di, void UpdateSingleBuffer(const std::shared_ptr<GeoLineDrawItem>& di,
std::size_t lineIndex,
std::vector<float>& linesBuffer, std::vector<float>& linesBuffer,
std::vector<GLint>& integerBuffer, std::vector<GLint>& integerBuffer,
std::unordered_map<std::shared_ptr<GeoLineDrawItem>, std::vector<LineHoverEntry>& hoverLines);
LineHoverEntry>& hoverLines);
std::shared_ptr<GlContext> context_; std::shared_ptr<GlContext> context_;
@ -114,10 +112,8 @@ public:
std::vector<float> newLinesBuffer_ {}; std::vector<float> newLinesBuffer_ {};
std::vector<GLint> newIntegerBuffer_ {}; std::vector<GLint> newIntegerBuffer_ {};
std::unordered_map<std::shared_ptr<GeoLineDrawItem>, LineHoverEntry> std::vector<LineHoverEntry> currentHoverLines_ {};
currentHoverLines_ {}; std::vector<LineHoverEntry> newHoverLines_ {};
std::unordered_map<std::shared_ptr<GeoLineDrawItem>, LineHoverEntry>
newHoverLines_ {};
std::shared_ptr<ShaderProgram> shaderProgram_; std::shared_ptr<ShaderProgram> shaderProgram_;
GLint uMVPMatrixLocation_; GLint uMVPMatrixLocation_;
@ -131,7 +127,7 @@ public:
}; };
GeoLines::GeoLines(std::shared_ptr<GlContext> context) : GeoLines::GeoLines(std::shared_ptr<GlContext> context) :
DrawItem(), p(std::make_unique<Impl>(context)) DrawItem(context->gl()), p(std::make_unique<Impl>(context))
{ {
} }
GeoLines::~GeoLines() = default; GeoLines::~GeoLines() = default;
@ -152,6 +148,8 @@ void GeoLines::set_thresholded(bool thresholded)
void GeoLines::Initialize() void GeoLines::Initialize()
{ {
gl::OpenGLFunctions& gl = p->context_->gl();
p->shaderProgram_ = p->context_->GetShaderProgram( p->shaderProgram_ = p->context_->GetShaderProgram(
{{GL_VERTEX_SHADER, ":/gl/geo_texture2d.vert"}, {{GL_VERTEX_SHADER, ":/gl/geo_texture2d.vert"},
{GL_GEOMETRY_SHADER, ":/gl/threshold.geom"}, {GL_GEOMETRY_SHADER, ":/gl/threshold.geom"},
@ -166,86 +164,79 @@ void GeoLines::Initialize()
p->uSelectedTimeLocation_ = p->uSelectedTimeLocation_ =
p->shaderProgram_->GetUniformLocation("uSelectedTime"); p->shaderProgram_->GetUniformLocation("uSelectedTime");
glGenVertexArrays(1, &p->vao_); gl.glGenVertexArrays(1, &p->vao_);
glGenBuffers(static_cast<GLsizei>(p->vbo_.size()), p->vbo_.data()); gl.glGenBuffers(static_cast<GLsizei>(p->vbo_.size()), p->vbo_.data());
glBindVertexArray(p->vao_); gl.glBindVertexArray(p->vao_);
glBindBuffer(GL_ARRAY_BUFFER, p->vbo_[0]); gl.glBindBuffer(GL_ARRAY_BUFFER, p->vbo_[0]);
glBufferData(GL_ARRAY_BUFFER, gl.glBufferData(GL_ARRAY_BUFFER,
sizeof(float) * kLineBufferLength_, sizeof(float) * kLineBufferLength_,
nullptr, nullptr,
GL_DYNAMIC_DRAW); GL_DYNAMIC_DRAW);
// NOLINTBEGIN(modernize-use-nullptr)
// NOLINTBEGIN(performance-no-int-to-ptr)
// NOLINTBEGIN(cppcoreguidelines-avoid-magic-numbers)
// aLatLong // aLatLong
glVertexAttribPointer(0, gl.glVertexAttribPointer(0,
2, 2,
GL_FLOAT, GL_FLOAT,
GL_FALSE, GL_FALSE,
kPointsPerVertex * sizeof(float), kPointsPerVertex * sizeof(float),
static_cast<void*>(0)); static_cast<void*>(0));
glEnableVertexAttribArray(0); gl.glEnableVertexAttribArray(0);
// aXYOffset // aXYOffset
glVertexAttribPointer(1, gl.glVertexAttribPointer(1,
2, 2,
GL_FLOAT, GL_FLOAT,
GL_FALSE, GL_FALSE,
kPointsPerVertex * sizeof(float), kPointsPerVertex * sizeof(float),
reinterpret_cast<void*>(2 * sizeof(float))); reinterpret_cast<void*>(2 * sizeof(float)));
glEnableVertexAttribArray(1); gl.glEnableVertexAttribArray(1);
// aModulate // aModulate
glVertexAttribPointer(3, gl.glVertexAttribPointer(3,
4, 4,
GL_FLOAT, GL_FLOAT,
GL_FALSE, GL_FALSE,
kPointsPerVertex * sizeof(float), kPointsPerVertex * sizeof(float),
reinterpret_cast<void*>(4 * sizeof(float))); reinterpret_cast<void*>(4 * sizeof(float)));
glEnableVertexAttribArray(3); gl.glEnableVertexAttribArray(3);
// aAngle // aAngle
glVertexAttribPointer(4, gl.glVertexAttribPointer(4,
1, 1,
GL_FLOAT, GL_FLOAT,
GL_FALSE, GL_FALSE,
kPointsPerVertex * sizeof(float), kPointsPerVertex * sizeof(float),
reinterpret_cast<void*>(8 * sizeof(float))); reinterpret_cast<void*>(8 * sizeof(float)));
glEnableVertexAttribArray(4); gl.glEnableVertexAttribArray(4);
glBindBuffer(GL_ARRAY_BUFFER, p->vbo_[1]); gl.glBindBuffer(GL_ARRAY_BUFFER, p->vbo_[1]);
glBufferData(GL_ARRAY_BUFFER, 0u, nullptr, GL_DYNAMIC_DRAW); gl.glBufferData(GL_ARRAY_BUFFER, 0u, nullptr, GL_DYNAMIC_DRAW);
// aThreshold // aThreshold
glVertexAttribIPointer(5, // gl.glVertexAttribIPointer(5, //
1, 1,
GL_INT, GL_INT,
kIntegersPerVertex_ * sizeof(GLint), kIntegersPerVertex_ * sizeof(GLint),
static_cast<void*>(0)); static_cast<void*>(0));
glEnableVertexAttribArray(5); gl.glEnableVertexAttribArray(5);
// aTimeRange // aTimeRange
glVertexAttribIPointer(6, // gl.glVertexAttribIPointer(6, //
2, 2,
GL_INT, GL_INT,
kIntegersPerVertex_ * sizeof(GLint), kIntegersPerVertex_ * sizeof(GLint),
reinterpret_cast<void*>(1 * sizeof(GLint))); reinterpret_cast<void*>(1 * sizeof(GLint)));
glEnableVertexAttribArray(6); gl.glEnableVertexAttribArray(6);
// aDisplayed // aDisplayed
glVertexAttribIPointer(7, gl.glVertexAttribPointer(7,
1, 1,
GL_INT, GL_INT,
kIntegersPerVertex_ * sizeof(GLint), GL_FALSE,
reinterpret_cast<void*>(3 * sizeof(GLint))); kIntegersPerVertex_ * sizeof(GLint),
glEnableVertexAttribArray(7); reinterpret_cast<void*>(3 * sizeof(float)));
gl.glEnableVertexAttribArray(7);
// NOLINTEND(cppcoreguidelines-avoid-magic-numbers)
// NOLINTEND(performance-no-int-to-ptr)
// NOLINTEND(modernize-use-nullptr)
p->dirty_ = true; p->dirty_ = true;
} }
@ -261,7 +252,9 @@ void GeoLines::Render(const QMapLibre::CustomLayerRenderParameters& params)
if (p->newLineList_.size() > 0) if (p->newLineList_.size() > 0)
{ {
glBindVertexArray(p->vao_); gl::OpenGLFunctions& gl = p->context_->gl();
gl.glBindVertexArray(p->vao_);
p->Update(); p->Update();
p->shaderProgram_->Use(); p->shaderProgram_->Use();
@ -274,37 +267,39 @@ void GeoLines::Render(const QMapLibre::CustomLayerRenderParameters& params)
// If thresholding is enabled, set the map distance // If thresholding is enabled, set the map distance
units::length::nautical_miles<float> mapDistance = units::length::nautical_miles<float> mapDistance =
util::maplibre::GetMapDistance(params); util::maplibre::GetMapDistance(params);
glUniform1f(p->uMapDistanceLocation_, mapDistance.value()); gl.glUniform1f(p->uMapDistanceLocation_, mapDistance.value());
} }
else else
{ {
// If thresholding is disabled, set the map distance to 0 // If thresholding is disabled, set the map distance to 0
glUniform1f(p->uMapDistanceLocation_, 0.0f); gl.glUniform1f(p->uMapDistanceLocation_, 0.0f);
} }
// Selected time // Selected time
std::chrono::system_clock::time_point selectedTime = std::chrono::system_clock::time_point selectedTime =
(p->selectedTime_ == std::chrono::system_clock::time_point {}) ? (p->selectedTime_ == std::chrono::system_clock::time_point {}) ?
scwx::util::time::now() : std::chrono::system_clock::now() :
p->selectedTime_; p->selectedTime_;
glUniform1i( gl.glUniform1i(
p->uSelectedTimeLocation_, p->uSelectedTimeLocation_,
static_cast<GLint>(std::chrono::duration_cast<std::chrono::minutes>( static_cast<GLint>(std::chrono::duration_cast<std::chrono::minutes>(
selectedTime.time_since_epoch()) selectedTime.time_since_epoch())
.count())); .count()));
// Draw icons // Draw icons
glDrawArrays(GL_TRIANGLES, gl.glDrawArrays(GL_TRIANGLES,
0, 0,
static_cast<GLsizei>(p->currentLineList_.size() * static_cast<GLsizei>(p->currentLineList_.size() *
kVerticesPerRectangle)); kVerticesPerRectangle));
} }
} }
void GeoLines::Deinitialize() void GeoLines::Deinitialize()
{ {
glDeleteVertexArrays(1, &p->vao_); gl::OpenGLFunctions& gl = p->context_->gl();
glDeleteBuffers(static_cast<GLsizei>(p->vbo_.size()), p->vbo_.data());
gl.glDeleteVertexArrays(1, &p->vao_);
gl.glDeleteBuffers(static_cast<GLsizei>(p->vbo_.size()), p->vbo_.data());
std::unique_lock lock {p->lineMutex_}; std::unique_lock lock {p->lineMutex_};
@ -329,9 +324,7 @@ void GeoLines::StartLines()
std::shared_ptr<GeoLineDrawItem> GeoLines::AddLine() std::shared_ptr<GeoLineDrawItem> GeoLines::AddLine()
{ {
auto& di = p->newLineList_.emplace_back(std::make_shared<GeoLineDrawItem>()); return p->newLineList_.emplace_back(std::make_shared<GeoLineDrawItem>());
di->lineIndex_ = p->newLineList_.size() - 1;
return di;
} }
void GeoLines::SetLineLocation(const std::shared_ptr<GeoLineDrawItem>& di, void GeoLines::SetLineLocation(const std::shared_ptr<GeoLineDrawItem>& di,
@ -478,7 +471,7 @@ void GeoLines::Impl::UpdateBuffers()
// Update line buffer // Update line buffer
UpdateSingleBuffer( UpdateSingleBuffer(
di, newLinesBuffer_, newIntegerBuffer_, newHoverLines_); di, i, newLinesBuffer_, newIntegerBuffer_, newHoverLines_);
} }
// All lines have been updated // All lines have been updated
@ -496,15 +489,23 @@ void GeoLines::Impl::UpdateModifiedLineBuffers()
// Update buffers for modified lines // Update buffers for modified lines
for (auto& di : dirtyLines_) for (auto& di : dirtyLines_)
{ {
// Check if modified line is in the current list // Find modified line in the current list
if (di->lineIndex_ >= currentLineList_.size() || auto it =
currentLineList_[di->lineIndex_] != di) std::find(currentLineList_.cbegin(), currentLineList_.cend(), di);
// Ignore invalid lines
if (it == currentLineList_.cend())
{ {
continue; continue;
} }
UpdateSingleBuffer( auto lineIndex = std::distance(currentLineList_.cbegin(), it);
di, currentLinesBuffer_, currentIntegerBuffer_, currentHoverLines_);
UpdateSingleBuffer(di,
lineIndex,
currentLinesBuffer_,
currentIntegerBuffer_,
currentHoverLines_);
} }
// Clear list of modified lines // Clear list of modified lines
@ -517,10 +518,10 @@ void GeoLines::Impl::UpdateModifiedLineBuffers()
void GeoLines::Impl::UpdateSingleBuffer( void GeoLines::Impl::UpdateSingleBuffer(
const std::shared_ptr<GeoLineDrawItem>& di, const std::shared_ptr<GeoLineDrawItem>& di,
std::size_t lineIndex,
std::vector<float>& lineBuffer, std::vector<float>& lineBuffer,
std::vector<GLint>& integerBuffer, std::vector<GLint>& integerBuffer,
std::unordered_map<std::shared_ptr<GeoLineDrawItem>, LineHoverEntry>& std::vector<LineHoverEntry>& hoverLines)
hoverLines)
{ {
// Threshold value // Threshold value
units::length::nautical_miles<double> threshold = di->threshold_; units::length::nautical_miles<double> threshold = di->threshold_;
@ -588,10 +589,10 @@ void GeoLines::Impl::UpdateSingleBuffer(
// Buffer position data // Buffer position data
auto lineBufferPosition = lineBuffer.end(); auto lineBufferPosition = lineBuffer.end();
auto lineBufferOffset = di->lineIndex_ * kLineBufferLength_; auto lineBufferOffset = lineIndex * kLineBufferLength_;
auto integerBufferPosition = integerBuffer.end(); auto integerBufferPosition = integerBuffer.end();
auto integerBufferOffset = di->lineIndex_ * kIntegerBufferLength_; auto integerBufferOffset = lineIndex * kIntegerBufferLength_;
if (lineBufferOffset < lineBuffer.size()) if (lineBufferOffset < lineBuffer.size())
{ {
@ -620,7 +621,9 @@ void GeoLines::Impl::UpdateSingleBuffer(
std::copy(integerData.begin(), integerData.end(), integerBufferPosition); std::copy(integerData.begin(), integerData.end(), integerBufferPosition);
} }
auto hoverIt = hoverLines.find(di); auto hoverIt = std::find_if(hoverLines.begin(),
hoverLines.end(),
[&di](auto& entry) { return entry.di_ == di; });
if (di->visible_ && (!di->hoverText_.empty() || if (di->visible_ && (!di->hoverText_.empty() ||
di->hoverCallback_ != nullptr || di->event_ != nullptr)) di->hoverCallback_ != nullptr || di->event_ != nullptr))
@ -642,23 +645,17 @@ void GeoLines::Impl::UpdateSingleBuffer(
if (hoverIt == hoverLines.end()) if (hoverIt == hoverLines.end())
{ {
hoverLines.emplace(di, hoverLines.emplace_back(
LineHoverEntry {.di_ = di, LineHoverEntry {di, sc1, sc2, otl, otr, obl, obr});
.p1_ = sc1,
.p2_ = sc2,
.otl_ = otl,
.otr_ = otr,
.obl_ = obl,
.obr_ = obr});
} }
else else
{ {
hoverIt->second.p1_ = sc1; hoverIt->p1_ = sc1;
hoverIt->second.p2_ = sc2; hoverIt->p2_ = sc2;
hoverIt->second.otl_ = otl; hoverIt->otl_ = otl;
hoverIt->second.otr_ = otr; hoverIt->otr_ = otr;
hoverIt->second.obl_ = obl; hoverIt->obl_ = obl;
hoverIt->second.obr_ = obr; hoverIt->obr_ = obr;
} }
} }
else if (hoverIt != hoverLines.end()) else if (hoverIt != hoverLines.end())
@ -674,21 +671,21 @@ void GeoLines::Impl::Update()
// If the lines have been updated // If the lines have been updated
if (dirty_) if (dirty_)
{ {
gl::OpenGLFunctions& gl = context_->gl();
// Buffer lines data // Buffer lines data
glBindBuffer(GL_ARRAY_BUFFER, vbo_[0]); gl.glBindBuffer(GL_ARRAY_BUFFER, vbo_[0]);
glBufferData( gl.glBufferData(GL_ARRAY_BUFFER,
GL_ARRAY_BUFFER, sizeof(float) * currentLinesBuffer_.size(),
static_cast<GLsizeiptr>(sizeof(float) * currentLinesBuffer_.size()), currentLinesBuffer_.data(),
currentLinesBuffer_.data(), GL_DYNAMIC_DRAW);
GL_DYNAMIC_DRAW);
// Buffer threshold data // Buffer threshold data
glBindBuffer(GL_ARRAY_BUFFER, vbo_[1]); gl.glBindBuffer(GL_ARRAY_BUFFER, vbo_[1]);
glBufferData( gl.glBufferData(GL_ARRAY_BUFFER,
GL_ARRAY_BUFFER, sizeof(GLint) * currentIntegerBuffer_.size(),
static_cast<GLsizeiptr>(sizeof(GLint) * currentIntegerBuffer_.size()), currentIntegerBuffer_.data(),
currentIntegerBuffer_.data(), GL_DYNAMIC_DRAW);
GL_DYNAMIC_DRAW);
} }
dirty_ = false; dirty_ = false;
@ -724,18 +721,16 @@ bool GeoLines::RunMousePicking(
// If no time has been selected, use the current time // If no time has been selected, use the current time
std::chrono::system_clock::time_point selectedTime = std::chrono::system_clock::time_point selectedTime =
(p->selectedTime_ == std::chrono::system_clock::time_point {}) ? (p->selectedTime_ == std::chrono::system_clock::time_point {}) ?
scwx::util::time::now() : std::chrono::system_clock::now() :
p->selectedTime_; p->selectedTime_;
// For each pickable line // For each pickable line
auto it = std::find_if( auto it = std::find_if(
std::execution::par_unseq, std::execution::par_unseq,
p->currentHoverLines_.cbegin(), p->currentHoverLines_.rbegin(),
p->currentHoverLines_.cend(), p->currentHoverLines_.rend(),
[&mapDistance, &selectedTime, &mapMatrix, &mouseCoords]( [&mapDistance, &selectedTime, &mapMatrix, &mouseCoords](const auto& line)
const auto& lineIt)
{ {
const auto& line = lineIt.second;
if (( if ((
// Placefile is thresholded // Placefile is thresholded
mapDistance > units::length::meters<double> {0.0} && mapDistance > units::length::meters<double> {0.0} &&
@ -745,10 +740,8 @@ bool GeoLines::RunMousePicking(
units::length::nautical_miles<double> {line.di_->threshold_} units::length::nautical_miles<double> {line.di_->threshold_}
.value())) < 999 && .value())) < 999 &&
// Map distance is beyond/within the threshold // Map distance is beyond the threshold
line.di_->threshold_ < mapDistance && line.di_->threshold_ < mapDistance) ||
(line.di_->threshold_.value() >= 0.0 ||
-(line.di_->threshold_) > mapDistance)) ||
( (
// Line has a start time // Line has a start time
@ -791,24 +784,24 @@ bool GeoLines::RunMousePicking(
return util::maplibre::IsPointInPolygon({tl, bl, br, tr}, mouseCoords); return util::maplibre::IsPointInPolygon({tl, bl, br, tr}, mouseCoords);
}); });
if (it != p->currentHoverLines_.cend()) if (it != p->currentHoverLines_.crend())
{ {
itemPicked = true; itemPicked = true;
if (!it->second.di_->hoverText_.empty()) if (!it->di_->hoverText_.empty())
{ {
// Show tooltip // Show tooltip
util::tooltip::Show(it->second.di_->hoverText_, mouseGlobalPos); util::tooltip::Show(it->di_->hoverText_, mouseGlobalPos);
} }
else if (it->second.di_->hoverCallback_ != nullptr) else if (it->di_->hoverCallback_ != nullptr)
{ {
it->second.di_->hoverCallback_(it->second.di_, mouseGlobalPos); it->di_->hoverCallback_(it->di_, mouseGlobalPos);
} }
if (it->second.di_->event_ != nullptr) if (it->di_->event_ != nullptr)
{ {
// Register event handler // Register event handler
eventHandler = it->second.di_; eventHandler = it->di_;
} }
} }

View file

@ -19,8 +19,9 @@ struct GeoLineDrawItem;
class GeoLines : public DrawItem class GeoLines : public DrawItem
{ {
public: public:
using HoverCallback = std::function<void( typedef std::function<void(std::shared_ptr<GeoLineDrawItem>&,
const std::shared_ptr<GeoLineDrawItem>&, const QPointF&)>; const QPointF&)>
HoverCallback;
explicit GeoLines(std::shared_ptr<GlContext> context); explicit GeoLines(std::shared_ptr<GlContext> context);
~GeoLines(); ~GeoLines();

View file

@ -21,11 +21,12 @@ namespace draw
static const std::string logPrefix_ = "scwx::qt::gl::draw::icons"; static const std::string logPrefix_ = "scwx::qt::gl::draw::icons";
static const auto logger_ = scwx::util::Logger::Create(logPrefix_); static const auto logger_ = scwx::util::Logger::Create(logPrefix_);
static constexpr std::size_t kNumRectangles = 1; static constexpr std::size_t kNumRectangles = 1;
static constexpr std::size_t kNumTriangles = kNumRectangles * 2; static constexpr std::size_t kNumTriangles = kNumRectangles * 2;
static constexpr std::size_t kVerticesPerTriangle = 3; static constexpr std::size_t kVerticesPerTriangle = 3;
static constexpr std::size_t kPointsPerVertex = 10; static constexpr std::size_t kVerticesPerRectangle = kVerticesPerTriangle * 2;
static constexpr std::size_t kPointsPerTexCoord = 3; static constexpr std::size_t kPointsPerVertex = 10;
static constexpr std::size_t kPointsPerTexCoord = 3;
static constexpr std::size_t kIconBufferLength = static constexpr std::size_t kIconBufferLength =
kNumTriangles * kVerticesPerTriangle * kPointsPerVertex; kNumTriangles * kVerticesPerTriangle * kPointsPerVertex;
static constexpr std::size_t kTextureBufferLength = static constexpr std::size_t kTextureBufferLength =
@ -116,7 +117,7 @@ public:
}; };
Icons::Icons(const std::shared_ptr<GlContext>& context) : Icons::Icons(const std::shared_ptr<GlContext>& context) :
DrawItem(), p(std::make_unique<Impl>(context)) DrawItem(context->gl()), p(std::make_unique<Impl>(context))
{ {
} }
Icons::~Icons() = default; Icons::~Icons() = default;
@ -126,6 +127,8 @@ Icons& Icons::operator=(Icons&&) noexcept = default;
void Icons::Initialize() void Icons::Initialize()
{ {
gl::OpenGLFunctions& gl = p->context_->gl();
p->shaderProgram_ = p->context_->GetShaderProgram( p->shaderProgram_ = p->context_->GetShaderProgram(
{{GL_VERTEX_SHADER, ":/gl/texture2d_array.vert"}, {{GL_VERTEX_SHADER, ":/gl/texture2d_array.vert"},
{GL_GEOMETRY_SHADER, ":/gl/threshold.geom"}, {GL_GEOMETRY_SHADER, ":/gl/threshold.geom"},
@ -133,77 +136,69 @@ void Icons::Initialize()
p->uMVPMatrixLocation_ = p->shaderProgram_->GetUniformLocation("uMVPMatrix"); p->uMVPMatrixLocation_ = p->shaderProgram_->GetUniformLocation("uMVPMatrix");
glGenVertexArrays(1, &p->vao_); gl.glGenVertexArrays(1, &p->vao_);
glGenBuffers(static_cast<GLsizei>(p->vbo_.size()), p->vbo_.data()); gl.glGenBuffers(static_cast<GLsizei>(p->vbo_.size()), p->vbo_.data());
glBindVertexArray(p->vao_); gl.glBindVertexArray(p->vao_);
glBindBuffer(GL_ARRAY_BUFFER, p->vbo_[0]); gl.glBindBuffer(GL_ARRAY_BUFFER, p->vbo_[0]);
glBufferData(GL_ARRAY_BUFFER, 0u, nullptr, GL_DYNAMIC_DRAW); gl.glBufferData(GL_ARRAY_BUFFER, 0u, nullptr, GL_DYNAMIC_DRAW);
// NOLINTBEGIN(modernize-use-nullptr)
// NOLINTBEGIN(performance-no-int-to-ptr)
// NOLINTBEGIN(cppcoreguidelines-avoid-magic-numbers)
// aVertex // aVertex
glVertexAttribPointer(0, gl.glVertexAttribPointer(0,
2, 2,
GL_FLOAT, GL_FLOAT,
GL_FALSE, GL_FALSE,
kPointsPerVertex * sizeof(float), kPointsPerVertex * sizeof(float),
reinterpret_cast<void*>(0)); reinterpret_cast<void*>(0));
glEnableVertexAttribArray(0); gl.glEnableVertexAttribArray(0);
// aXYOffset // aXYOffset
glVertexAttribPointer(1, gl.glVertexAttribPointer(1,
2, 2,
GL_FLOAT, GL_FLOAT,
GL_FALSE, GL_FALSE,
kPointsPerVertex * sizeof(float), kPointsPerVertex * sizeof(float),
reinterpret_cast<void*>(2 * sizeof(float))); reinterpret_cast<void*>(2 * sizeof(float)));
glEnableVertexAttribArray(1); gl.glEnableVertexAttribArray(1);
// aModulate // aModulate
glVertexAttribPointer(3, gl.glVertexAttribPointer(3,
4, 4,
GL_FLOAT, GL_FLOAT,
GL_FALSE, GL_FALSE,
kPointsPerVertex * sizeof(float), kPointsPerVertex * sizeof(float),
reinterpret_cast<void*>(4 * sizeof(float))); reinterpret_cast<void*>(4 * sizeof(float)));
glEnableVertexAttribArray(3); gl.glEnableVertexAttribArray(3);
// aAngle // aAngle
glVertexAttribPointer(4, gl.glVertexAttribPointer(4,
1, 1,
GL_FLOAT, GL_FLOAT,
GL_FALSE, GL_FALSE,
kPointsPerVertex * sizeof(float), kPointsPerVertex * sizeof(float),
reinterpret_cast<void*>(8 * sizeof(float))); reinterpret_cast<void*>(8 * sizeof(float)));
glEnableVertexAttribArray(4); gl.glEnableVertexAttribArray(4);
// aDisplayed // aDisplayed
glVertexAttribPointer(5, gl.glVertexAttribPointer(5,
1, 1,
GL_FLOAT, GL_FLOAT,
GL_FALSE, GL_FALSE,
kPointsPerVertex * sizeof(float), kPointsPerVertex * sizeof(float),
reinterpret_cast<void*>(9 * sizeof(float))); reinterpret_cast<void*>(9 * sizeof(float)));
glEnableVertexAttribArray(5); gl.glEnableVertexAttribArray(5);
glBindBuffer(GL_ARRAY_BUFFER, p->vbo_[1]); gl.glBindBuffer(GL_ARRAY_BUFFER, p->vbo_[1]);
glBufferData(GL_ARRAY_BUFFER, 0u, nullptr, GL_DYNAMIC_DRAW); gl.glBufferData(GL_ARRAY_BUFFER, 0u, nullptr, GL_DYNAMIC_DRAW);
// aTexCoord // aTexCoord
glVertexAttribPointer(2, gl.glVertexAttribPointer(2,
3, 3,
GL_FLOAT, GL_FLOAT,
GL_FALSE, GL_FALSE,
kPointsPerTexCoord * sizeof(float), kPointsPerTexCoord * sizeof(float),
static_cast<void*>(0)); static_cast<void*>(0));
glEnableVertexAttribArray(2); gl.glEnableVertexAttribArray(2);
// NOLINTEND(cppcoreguidelines-avoid-magic-numbers)
// NOLINTEND(performance-no-int-to-ptr)
// NOLINTEND(modernize-use-nullptr)
p->dirty_ = true; p->dirty_ = true;
} }
@ -225,25 +220,29 @@ void Icons::Render(const QMapLibre::CustomLayerRenderParameters& params,
if (!p->currentIconList_.empty()) if (!p->currentIconList_.empty())
{ {
glBindVertexArray(p->vao_); gl::OpenGLFunctions& gl = p->context_->gl();
gl.glBindVertexArray(p->vao_);
p->Update(textureAtlasChanged); p->Update(textureAtlasChanged);
p->shaderProgram_->Use(); p->shaderProgram_->Use();
UseDefaultProjection(params, p->uMVPMatrixLocation_); UseDefaultProjection(params, p->uMVPMatrixLocation_);
// Interpolate texture coordinates // Interpolate texture coordinates
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR); gl.glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR); gl.glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Draw icons // Draw icons
glDrawArrays(GL_TRIANGLES, 0, p->numVertices_); gl.glDrawArrays(GL_TRIANGLES, 0, p->numVertices_);
} }
} }
void Icons::Deinitialize() void Icons::Deinitialize()
{ {
glDeleteVertexArrays(1, &p->vao_); gl::OpenGLFunctions& gl = p->context_->gl();
glDeleteBuffers(static_cast<GLsizei>(p->vbo_.size()), p->vbo_.data());
gl.glDeleteVertexArrays(1, &p->vao_);
gl.glDeleteBuffers(static_cast<GLsizei>(p->vbo_.size()), p->vbo_.data());
std::unique_lock lock {p->iconMutex_}; std::unique_lock lock {p->iconMutex_};
@ -681,6 +680,8 @@ void Icons::Impl::UpdateModifiedIconBuffers()
void Icons::Impl::Update(bool textureAtlasChanged) void Icons::Impl::Update(bool textureAtlasChanged)
{ {
gl::OpenGLFunctions& gl = context_->gl();
UpdateModifiedIconBuffers(); UpdateModifiedIconBuffers();
// If the texture atlas has changed // If the texture atlas has changed
@ -696,12 +697,11 @@ void Icons::Impl::Update(bool textureAtlasChanged)
UpdateTextureBuffer(); UpdateTextureBuffer();
// Buffer texture data // Buffer texture data
glBindBuffer(GL_ARRAY_BUFFER, vbo_[1]); gl.glBindBuffer(GL_ARRAY_BUFFER, vbo_[1]);
glBufferData( gl.glBufferData(GL_ARRAY_BUFFER,
GL_ARRAY_BUFFER, sizeof(float) * textureBuffer_.size(),
static_cast<GLsizeiptr>(sizeof(float) * textureBuffer_.size()), textureBuffer_.data(),
textureBuffer_.data(), GL_DYNAMIC_DRAW);
GL_DYNAMIC_DRAW);
lastTextureAtlasChanged_ = false; lastTextureAtlasChanged_ = false;
} }
@ -710,12 +710,11 @@ void Icons::Impl::Update(bool textureAtlasChanged)
if (dirty_) if (dirty_)
{ {
// Buffer vertex data // Buffer vertex data
glBindBuffer(GL_ARRAY_BUFFER, vbo_[0]); gl.glBindBuffer(GL_ARRAY_BUFFER, vbo_[0]);
glBufferData( gl.glBufferData(GL_ARRAY_BUFFER,
GL_ARRAY_BUFFER, sizeof(float) * currentIconBuffer_.size(),
static_cast<GLsizeiptr>(sizeof(float) * currentIconBuffer_.size()), currentIconBuffer_.data(),
currentIconBuffer_.data(), GL_DYNAMIC_DRAW);
GL_DYNAMIC_DRAW);
numVertices_ = numVertices_ =
static_cast<GLsizei>(currentIconBuffer_.size() / kPointsPerVertex); static_cast<GLsizei>(currentIconBuffer_.size() / kPointsPerVertex);
@ -742,7 +741,7 @@ bool Icons::RunMousePicking(
// For each pickable icon // For each pickable icon
auto it = std::find_if( // auto it = std::find_if( //
std::execution::par, std::execution::par_unseq,
p->currentHoverIcons_.crbegin(), p->currentHoverIcons_.crbegin(),
p->currentHoverIcons_.crend(), p->currentHoverIcons_.crend(),
[&mouseLocalCoords](const auto& icon) [&mouseLocalCoords](const auto& icon)

View file

@ -63,12 +63,14 @@ class LinkedVectors::Impl
{ {
public: public:
explicit Impl(std::shared_ptr<GlContext> context) : explicit Impl(std::shared_ptr<GlContext> context) :
geoLines_ {std::make_shared<GeoLines>(context)} context_ {context}, geoLines_ {std::make_shared<GeoLines>(context)}
{ {
} }
~Impl() {} ~Impl() {}
std::shared_ptr<GlContext> context_;
bool borderEnabled_ {true}; bool borderEnabled_ {true};
bool visible_ {true}; bool visible_ {true};
@ -77,7 +79,7 @@ public:
}; };
LinkedVectors::LinkedVectors(std::shared_ptr<GlContext> context) : LinkedVectors::LinkedVectors(std::shared_ptr<GlContext> context) :
DrawItem(), p(std::make_unique<Impl>(context)) DrawItem(context->gl()), p(std::make_unique<Impl>(context))
{ {
} }
LinkedVectors::~LinkedVectors() = default; LinkedVectors::~LinkedVectors() = default;

View file

@ -3,7 +3,6 @@
#include <scwx/qt/util/texture_atlas.hpp> #include <scwx/qt/util/texture_atlas.hpp>
#include <scwx/qt/util/tooltip.hpp> #include <scwx/qt/util/tooltip.hpp>
#include <scwx/util/logger.hpp> #include <scwx/util/logger.hpp>
#include <scwx/util/time.hpp>
#include <execution> #include <execution>
@ -141,7 +140,7 @@ public:
}; };
PlacefileIcons::PlacefileIcons(const std::shared_ptr<GlContext>& context) : PlacefileIcons::PlacefileIcons(const std::shared_ptr<GlContext>& context) :
DrawItem(), p(std::make_unique<Impl>(context)) DrawItem(context->gl()), p(std::make_unique<Impl>(context))
{ {
} }
PlacefileIcons::~PlacefileIcons() = default; PlacefileIcons::~PlacefileIcons() = default;
@ -162,6 +161,9 @@ void PlacefileIcons::set_thresholded(bool thresholded)
void PlacefileIcons::Initialize() void PlacefileIcons::Initialize()
{ {
gl::OpenGLFunctions& gl = p->context_->gl();
auto& gl30 = p->context_->gl30();
p->shaderProgram_ = p->context_->GetShaderProgram( p->shaderProgram_ = p->context_->GetShaderProgram(
{{GL_VERTEX_SHADER, ":/gl/geo_texture2d.vert"}, {{GL_VERTEX_SHADER, ":/gl/geo_texture2d.vert"},
{GL_GEOMETRY_SHADER, ":/gl/threshold.geom"}, {GL_GEOMETRY_SHADER, ":/gl/threshold.geom"},
@ -176,90 +178,82 @@ void PlacefileIcons::Initialize()
p->uSelectedTimeLocation_ = p->uSelectedTimeLocation_ =
p->shaderProgram_->GetUniformLocation("uSelectedTime"); p->shaderProgram_->GetUniformLocation("uSelectedTime");
glGenVertexArrays(1, &p->vao_); gl.glGenVertexArrays(1, &p->vao_);
glGenBuffers(static_cast<GLsizei>(p->vbo_.size()), p->vbo_.data()); gl.glGenBuffers(static_cast<GLsizei>(p->vbo_.size()), p->vbo_.data());
glBindVertexArray(p->vao_); gl.glBindVertexArray(p->vao_);
glBindBuffer(GL_ARRAY_BUFFER, p->vbo_[0]); gl.glBindBuffer(GL_ARRAY_BUFFER, p->vbo_[0]);
glBufferData(GL_ARRAY_BUFFER, 0u, nullptr, GL_DYNAMIC_DRAW); gl.glBufferData(GL_ARRAY_BUFFER, 0u, nullptr, GL_DYNAMIC_DRAW);
// NOLINTBEGIN(modernize-use-nullptr)
// NOLINTBEGIN(performance-no-int-to-ptr)
// NOLINTBEGIN(cppcoreguidelines-avoid-magic-numbers)
// aLatLong // aLatLong
glVertexAttribPointer(0, gl.glVertexAttribPointer(0,
2, 2,
GL_FLOAT, GL_FLOAT,
GL_FALSE, GL_FALSE,
kPointsPerVertex * sizeof(float), kPointsPerVertex * sizeof(float),
static_cast<void*>(0)); static_cast<void*>(0));
glEnableVertexAttribArray(0); gl.glEnableVertexAttribArray(0);
// aXYOffset // aXYOffset
glVertexAttribPointer(1, gl.glVertexAttribPointer(1,
2, 2,
GL_FLOAT, GL_FLOAT,
GL_FALSE, GL_FALSE,
kPointsPerVertex * sizeof(float), kPointsPerVertex * sizeof(float),
reinterpret_cast<void*>(2 * sizeof(float))); reinterpret_cast<void*>(2 * sizeof(float)));
glEnableVertexAttribArray(1); gl.glEnableVertexAttribArray(1);
// aModulate // aModulate
glVertexAttribPointer(3, gl.glVertexAttribPointer(3,
4, 4,
GL_FLOAT, GL_FLOAT,
GL_FALSE, GL_FALSE,
kPointsPerVertex * sizeof(float), kPointsPerVertex * sizeof(float),
reinterpret_cast<void*>(4 * sizeof(float))); reinterpret_cast<void*>(4 * sizeof(float)));
glEnableVertexAttribArray(3); gl.glEnableVertexAttribArray(3);
// aAngle // aAngle
glVertexAttribPointer(4, gl.glVertexAttribPointer(4,
1, 1,
GL_FLOAT, GL_FLOAT,
GL_FALSE, GL_FALSE,
kPointsPerVertex * sizeof(float), kPointsPerVertex * sizeof(float),
reinterpret_cast<void*>(8 * sizeof(float))); reinterpret_cast<void*>(8 * sizeof(float)));
glEnableVertexAttribArray(4); gl.glEnableVertexAttribArray(4);
glBindBuffer(GL_ARRAY_BUFFER, p->vbo_[1]); gl.glBindBuffer(GL_ARRAY_BUFFER, p->vbo_[1]);
glBufferData(GL_ARRAY_BUFFER, 0u, nullptr, GL_DYNAMIC_DRAW); gl.glBufferData(GL_ARRAY_BUFFER, 0u, nullptr, GL_DYNAMIC_DRAW);
// aTexCoord // aTexCoord
glVertexAttribPointer(2, gl.glVertexAttribPointer(2,
3, 3,
GL_FLOAT, GL_FLOAT,
GL_FALSE, GL_FALSE,
kPointsPerTexCoord * sizeof(float), kPointsPerTexCoord * sizeof(float),
static_cast<void*>(0)); static_cast<void*>(0));
glEnableVertexAttribArray(2); gl.glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, p->vbo_[2]); gl.glBindBuffer(GL_ARRAY_BUFFER, p->vbo_[2]);
glBufferData(GL_ARRAY_BUFFER, 0u, nullptr, GL_DYNAMIC_DRAW); gl.glBufferData(GL_ARRAY_BUFFER, 0u, nullptr, GL_DYNAMIC_DRAW);
// aThreshold // aThreshold
glVertexAttribIPointer(5, // gl.glVertexAttribIPointer(5, //
1, 1,
GL_INT, GL_INT,
0, 0,
static_cast<void*>(0)); static_cast<void*>(0));
glEnableVertexAttribArray(5); gl.glEnableVertexAttribArray(5);
// aTimeRange // aTimeRange
glVertexAttribIPointer(6, // gl.glVertexAttribIPointer(6, //
2, 2,
GL_INT, GL_INT,
kIntegersPerVertex_ * sizeof(GLint), kIntegersPerVertex_ * sizeof(GLint),
reinterpret_cast<void*>(1 * sizeof(GLint))); reinterpret_cast<void*>(1 * sizeof(GLint)));
glEnableVertexAttribArray(6); gl.glEnableVertexAttribArray(6);
// aDisplayed // aDisplayed
glVertexAttribI1i(7, 1); gl30.glVertexAttribI1i(7, 1);
// NOLINTEND(cppcoreguidelines-avoid-magic-numbers)
// NOLINTEND(performance-no-int-to-ptr)
// NOLINTEND(modernize-use-nullptr)
p->dirty_ = true; p->dirty_ = true;
} }
@ -272,7 +266,9 @@ void PlacefileIcons::Render(
if (!p->currentIconList_.empty()) if (!p->currentIconList_.empty())
{ {
glBindVertexArray(p->vao_); gl::OpenGLFunctions& gl = p->context_->gl();
gl.glBindVertexArray(p->vao_);
p->Update(textureAtlasChanged); p->Update(textureAtlasChanged);
p->shaderProgram_->Use(); p->shaderProgram_->Use();
@ -285,38 +281,40 @@ void PlacefileIcons::Render(
// If thresholding is enabled, set the map distance // If thresholding is enabled, set the map distance
units::length::nautical_miles<float> mapDistance = units::length::nautical_miles<float> mapDistance =
util::maplibre::GetMapDistance(params); util::maplibre::GetMapDistance(params);
glUniform1f(p->uMapDistanceLocation_, mapDistance.value()); gl.glUniform1f(p->uMapDistanceLocation_, mapDistance.value());
} }
else else
{ {
// If thresholding is disabled, set the map distance to 0 // If thresholding is disabled, set the map distance to 0
glUniform1f(p->uMapDistanceLocation_, 0.0f); gl.glUniform1f(p->uMapDistanceLocation_, 0.0f);
} }
// Selected time // Selected time
std::chrono::system_clock::time_point selectedTime = std::chrono::system_clock::time_point selectedTime =
(p->selectedTime_ == std::chrono::system_clock::time_point {}) ? (p->selectedTime_ == std::chrono::system_clock::time_point {}) ?
scwx::util::time::now() : std::chrono::system_clock::now() :
p->selectedTime_; p->selectedTime_;
glUniform1i( gl.glUniform1i(
p->uSelectedTimeLocation_, p->uSelectedTimeLocation_,
static_cast<GLint>(std::chrono::duration_cast<std::chrono::minutes>( static_cast<GLint>(std::chrono::duration_cast<std::chrono::minutes>(
selectedTime.time_since_epoch()) selectedTime.time_since_epoch())
.count())); .count()));
// Interpolate texture coordinates // Interpolate texture coordinates
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR); gl.glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR); gl.glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Draw icons // Draw icons
glDrawArrays(GL_TRIANGLES, 0, p->numVertices_); gl.glDrawArrays(GL_TRIANGLES, 0, p->numVertices_);
} }
} }
void PlacefileIcons::Deinitialize() void PlacefileIcons::Deinitialize()
{ {
glDeleteVertexArrays(1, &p->vao_); gl::OpenGLFunctions& gl = p->context_->gl();
glDeleteBuffers(static_cast<GLsizei>(p->vbo_.size()), p->vbo_.data());
gl.glDeleteVertexArrays(1, &p->vao_);
gl.glDeleteBuffers(static_cast<GLsizei>(p->vbo_.size()), p->vbo_.data());
std::unique_lock lock {p->iconMutex_}; std::unique_lock lock {p->iconMutex_};
@ -644,6 +642,8 @@ void PlacefileIcons::Impl::UpdateTextureBuffer()
void PlacefileIcons::Impl::Update(bool textureAtlasChanged) void PlacefileIcons::Impl::Update(bool textureAtlasChanged)
{ {
gl::OpenGLFunctions& gl = context_->gl();
// If the texture atlas has changed // If the texture atlas has changed
if (dirty_ || textureAtlasChanged) if (dirty_ || textureAtlasChanged)
{ {
@ -657,32 +657,29 @@ void PlacefileIcons::Impl::Update(bool textureAtlasChanged)
UpdateTextureBuffer(); UpdateTextureBuffer();
// Buffer texture data // Buffer texture data
glBindBuffer(GL_ARRAY_BUFFER, vbo_[1]); gl.glBindBuffer(GL_ARRAY_BUFFER, vbo_[1]);
glBufferData( gl.glBufferData(GL_ARRAY_BUFFER,
GL_ARRAY_BUFFER, sizeof(float) * textureBuffer_.size(),
static_cast<GLsizeiptr>(sizeof(float) * textureBuffer_.size()), textureBuffer_.data(),
textureBuffer_.data(), GL_DYNAMIC_DRAW);
GL_DYNAMIC_DRAW);
} }
// If buffers need updating // If buffers need updating
if (dirty_) if (dirty_)
{ {
// Buffer vertex data // Buffer vertex data
glBindBuffer(GL_ARRAY_BUFFER, vbo_[0]); gl.glBindBuffer(GL_ARRAY_BUFFER, vbo_[0]);
glBufferData( gl.glBufferData(GL_ARRAY_BUFFER,
GL_ARRAY_BUFFER, sizeof(float) * currentIconBuffer_.size(),
static_cast<GLsizeiptr>(sizeof(float) * currentIconBuffer_.size()), currentIconBuffer_.data(),
currentIconBuffer_.data(), GL_DYNAMIC_DRAW);
GL_DYNAMIC_DRAW);
// Buffer threshold data // Buffer threshold data
glBindBuffer(GL_ARRAY_BUFFER, vbo_[2]); gl.glBindBuffer(GL_ARRAY_BUFFER, vbo_[2]);
glBufferData( gl.glBufferData(GL_ARRAY_BUFFER,
GL_ARRAY_BUFFER, sizeof(GLint) * currentIntegerBuffer_.size(),
static_cast<GLsizeiptr>(sizeof(GLint) * currentIntegerBuffer_.size()), currentIntegerBuffer_.data(),
currentIntegerBuffer_.data(), GL_DYNAMIC_DRAW);
GL_DYNAMIC_DRAW);
numVertices_ = numVertices_ =
static_cast<GLsizei>(currentIconBuffer_.size() / kPointsPerVertex); static_cast<GLsizei>(currentIconBuffer_.size() / kPointsPerVertex);
@ -721,7 +718,7 @@ bool PlacefileIcons::RunMousePicking(
// If no time has been selected, use the current time // If no time has been selected, use the current time
std::chrono::system_clock::time_point selectedTime = std::chrono::system_clock::time_point selectedTime =
(p->selectedTime_ == std::chrono::system_clock::time_point {}) ? (p->selectedTime_ == std::chrono::system_clock::time_point {}) ?
scwx::util::time::now() : std::chrono::system_clock::now() :
p->selectedTime_; p->selectedTime_;
// For each pickable icon // For each pickable icon
@ -740,10 +737,8 @@ bool PlacefileIcons::RunMousePicking(
units::length::nautical_miles<double> {icon.di_->threshold_} units::length::nautical_miles<double> {icon.di_->threshold_}
.value())) < 999 && .value())) < 999 &&
// Map distance is beyond/within the threshold // Map distance is beyond the threshold
icon.di_->threshold_ < mapDistance && icon.di_->threshold_ < mapDistance) ||
(icon.di_->threshold_.value() >= 0.0 ||
-(icon.di_->threshold_) > mapDistance)) ||
( (
// Line has a start time // Line has a start time

View file

@ -2,7 +2,6 @@
#include <scwx/qt/util/maplibre.hpp> #include <scwx/qt/util/maplibre.hpp>
#include <scwx/qt/util/texture_atlas.hpp> #include <scwx/qt/util/texture_atlas.hpp>
#include <scwx/util/logger.hpp> #include <scwx/util/logger.hpp>
#include <scwx/util/time.hpp>
#include <QDir> #include <QDir>
#include <QUrl> #include <QUrl>
@ -118,7 +117,7 @@ public:
}; };
PlacefileImages::PlacefileImages(const std::shared_ptr<GlContext>& context) : PlacefileImages::PlacefileImages(const std::shared_ptr<GlContext>& context) :
DrawItem(), p(std::make_unique<Impl>(context)) DrawItem(context->gl()), p(std::make_unique<Impl>(context))
{ {
} }
PlacefileImages::~PlacefileImages() = default; PlacefileImages::~PlacefileImages() = default;
@ -140,6 +139,9 @@ void PlacefileImages::set_thresholded(bool thresholded)
void PlacefileImages::Initialize() void PlacefileImages::Initialize()
{ {
gl::OpenGLFunctions& gl = p->context_->gl();
auto& gl30 = p->context_->gl30();
p->shaderProgram_ = p->context_->GetShaderProgram( p->shaderProgram_ = p->context_->GetShaderProgram(
{{GL_VERTEX_SHADER, ":/gl/geo_texture2d.vert"}, {{GL_VERTEX_SHADER, ":/gl/geo_texture2d.vert"},
{GL_GEOMETRY_SHADER, ":/gl/threshold.geom"}, {GL_GEOMETRY_SHADER, ":/gl/threshold.geom"},
@ -154,81 +156,73 @@ void PlacefileImages::Initialize()
p->uSelectedTimeLocation_ = p->uSelectedTimeLocation_ =
p->shaderProgram_->GetUniformLocation("uSelectedTime"); p->shaderProgram_->GetUniformLocation("uSelectedTime");
glGenVertexArrays(1, &p->vao_); gl.glGenVertexArrays(1, &p->vao_);
glGenBuffers(static_cast<GLsizei>(p->vbo_.size()), p->vbo_.data()); gl.glGenBuffers(static_cast<GLsizei>(p->vbo_.size()), p->vbo_.data());
glBindVertexArray(p->vao_); gl.glBindVertexArray(p->vao_);
glBindBuffer(GL_ARRAY_BUFFER, p->vbo_[0]); gl.glBindBuffer(GL_ARRAY_BUFFER, p->vbo_[0]);
glBufferData(GL_ARRAY_BUFFER, 0u, nullptr, GL_DYNAMIC_DRAW); gl.glBufferData(GL_ARRAY_BUFFER, 0u, nullptr, GL_DYNAMIC_DRAW);
// NOLINTBEGIN(modernize-use-nullptr)
// NOLINTBEGIN(performance-no-int-to-ptr)
// NOLINTBEGIN(cppcoreguidelines-avoid-magic-numbers)
// aLatLong // aLatLong
glVertexAttribPointer(0, gl.glVertexAttribPointer(0,
2, 2,
GL_FLOAT, GL_FLOAT,
GL_FALSE, GL_FALSE,
kPointsPerVertex * sizeof(float), kPointsPerVertex * sizeof(float),
static_cast<void*>(0)); static_cast<void*>(0));
glEnableVertexAttribArray(0); gl.glEnableVertexAttribArray(0);
// aXYOffset // aXYOffset
glVertexAttribPointer(1, gl.glVertexAttribPointer(1,
2, 2,
GL_FLOAT, GL_FLOAT,
GL_FALSE, GL_FALSE,
kPointsPerVertex * sizeof(float), kPointsPerVertex * sizeof(float),
reinterpret_cast<void*>(2 * sizeof(float))); reinterpret_cast<void*>(2 * sizeof(float)));
glEnableVertexAttribArray(1); gl.glEnableVertexAttribArray(1);
// aModulate // aModulate
glVertexAttribPointer(3, gl.glVertexAttribPointer(3,
4, 4,
GL_FLOAT, GL_FLOAT,
GL_FALSE, GL_FALSE,
kPointsPerVertex * sizeof(float), kPointsPerVertex * sizeof(float),
reinterpret_cast<void*>(4 * sizeof(float))); reinterpret_cast<void*>(4 * sizeof(float)));
glEnableVertexAttribArray(3); gl.glEnableVertexAttribArray(3);
glBindBuffer(GL_ARRAY_BUFFER, p->vbo_[1]); gl.glBindBuffer(GL_ARRAY_BUFFER, p->vbo_[1]);
glBufferData(GL_ARRAY_BUFFER, 0u, nullptr, GL_DYNAMIC_DRAW); gl.glBufferData(GL_ARRAY_BUFFER, 0u, nullptr, GL_DYNAMIC_DRAW);
// aTexCoord // aTexCoord
glVertexAttribPointer(2, gl.glVertexAttribPointer(2,
3, 3,
GL_FLOAT, GL_FLOAT,
GL_FALSE, GL_FALSE,
kPointsPerTexCoord * sizeof(float), kPointsPerTexCoord * sizeof(float),
static_cast<void*>(0)); static_cast<void*>(0));
glEnableVertexAttribArray(2); gl.glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, p->vbo_[2]); gl.glBindBuffer(GL_ARRAY_BUFFER, p->vbo_[2]);
glBufferData(GL_ARRAY_BUFFER, 0u, nullptr, GL_DYNAMIC_DRAW); gl.glBufferData(GL_ARRAY_BUFFER, 0u, nullptr, GL_DYNAMIC_DRAW);
// aThreshold // aThreshold
glVertexAttribIPointer(5, // gl.glVertexAttribIPointer(5, //
1, 1,
GL_INT, GL_INT,
kIntegersPerVertex_ * sizeof(GLint), kIntegersPerVertex_ * sizeof(GLint),
static_cast<void*>(0)); static_cast<void*>(0));
glEnableVertexAttribArray(5); gl.glEnableVertexAttribArray(5);
// aTimeRange // aTimeRange
glVertexAttribIPointer(6, // gl.glVertexAttribIPointer(6, //
2, 2,
GL_INT, GL_INT,
kIntegersPerVertex_ * sizeof(GLint), kIntegersPerVertex_ * sizeof(GLint),
reinterpret_cast<void*>(1 * sizeof(GLint))); reinterpret_cast<void*>(1 * sizeof(GLint)));
glEnableVertexAttribArray(6); gl.glEnableVertexAttribArray(6);
// aDisplayed // aDisplayed
glVertexAttribI1i(7, 1); gl30.glVertexAttribI1i(7, 1);
// NOLINTEND(cppcoreguidelines-avoid-magic-numbers)
// NOLINTEND(performance-no-int-to-ptr)
// NOLINTEND(modernize-use-nullptr)
p->dirty_ = true; p->dirty_ = true;
} }
@ -241,7 +235,9 @@ void PlacefileImages::Render(
if (!p->currentImageList_.empty()) if (!p->currentImageList_.empty())
{ {
glBindVertexArray(p->vao_); gl::OpenGLFunctions& gl = p->context_->gl();
gl.glBindVertexArray(p->vao_);
p->Update(textureAtlasChanged); p->Update(textureAtlasChanged);
p->shaderProgram_->Use(); p->shaderProgram_->Use();
@ -254,38 +250,40 @@ void PlacefileImages::Render(
// If thresholding is enabled, set the map distance // If thresholding is enabled, set the map distance
units::length::nautical_miles<float> mapDistance = units::length::nautical_miles<float> mapDistance =
util::maplibre::GetMapDistance(params); util::maplibre::GetMapDistance(params);
glUniform1f(p->uMapDistanceLocation_, mapDistance.value()); gl.glUniform1f(p->uMapDistanceLocation_, mapDistance.value());
} }
else else
{ {
// If thresholding is disabled, set the map distance to 0 // If thresholding is disabled, set the map distance to 0
glUniform1f(p->uMapDistanceLocation_, 0.0f); gl.glUniform1f(p->uMapDistanceLocation_, 0.0f);
} }
// Selected time // Selected time
std::chrono::system_clock::time_point selectedTime = std::chrono::system_clock::time_point selectedTime =
(p->selectedTime_ == std::chrono::system_clock::time_point {}) ? (p->selectedTime_ == std::chrono::system_clock::time_point {}) ?
scwx::util::time::now() : std::chrono::system_clock::now() :
p->selectedTime_; p->selectedTime_;
glUniform1i( gl.glUniform1i(
p->uSelectedTimeLocation_, p->uSelectedTimeLocation_,
static_cast<GLint>(std::chrono::duration_cast<std::chrono::minutes>( static_cast<GLint>(std::chrono::duration_cast<std::chrono::minutes>(
selectedTime.time_since_epoch()) selectedTime.time_since_epoch())
.count())); .count()));
// Interpolate texture coordinates // Interpolate texture coordinates
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR); gl.glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR); gl.glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Draw images // Draw images
glDrawArrays(GL_TRIANGLES, 0, p->numVertices_); gl.glDrawArrays(GL_TRIANGLES, 0, p->numVertices_);
} }
} }
void PlacefileImages::Deinitialize() void PlacefileImages::Deinitialize()
{ {
glDeleteVertexArrays(1, &p->vao_); gl::OpenGLFunctions& gl = p->context_->gl();
glDeleteBuffers(static_cast<GLsizei>(p->vbo_.size()), p->vbo_.data());
gl.glDeleteVertexArrays(1, &p->vao_);
gl.glDeleteBuffers(static_cast<GLsizei>(p->vbo_.size()), p->vbo_.data());
std::unique_lock lock {p->imageMutex_}; std::unique_lock lock {p->imageMutex_};
@ -441,6 +439,8 @@ void PlacefileImages::Impl::UpdateTextureBuffer()
void PlacefileImages::Impl::Update(bool textureAtlasChanged) void PlacefileImages::Impl::Update(bool textureAtlasChanged)
{ {
gl::OpenGLFunctions& gl = context_->gl();
// If the texture atlas has changed // If the texture atlas has changed
if (dirty_ || textureAtlasChanged) if (dirty_ || textureAtlasChanged)
{ {
@ -454,32 +454,29 @@ void PlacefileImages::Impl::Update(bool textureAtlasChanged)
UpdateTextureBuffer(); UpdateTextureBuffer();
// Buffer texture data // Buffer texture data
glBindBuffer(GL_ARRAY_BUFFER, vbo_[1]); gl.glBindBuffer(GL_ARRAY_BUFFER, vbo_[1]);
glBufferData( gl.glBufferData(GL_ARRAY_BUFFER,
GL_ARRAY_BUFFER, sizeof(float) * textureBuffer_.size(),
static_cast<GLsizeiptr>(sizeof(float) * textureBuffer_.size()), textureBuffer_.data(),
textureBuffer_.data(), GL_DYNAMIC_DRAW);
GL_DYNAMIC_DRAW);
} }
// If buffers need updating // If buffers need updating
if (dirty_) if (dirty_)
{ {
// Buffer vertex data // Buffer vertex data
glBindBuffer(GL_ARRAY_BUFFER, vbo_[0]); gl.glBindBuffer(GL_ARRAY_BUFFER, vbo_[0]);
glBufferData( gl.glBufferData(GL_ARRAY_BUFFER,
GL_ARRAY_BUFFER, sizeof(float) * currentImageBuffer_.size(),
static_cast<GLsizeiptr>(sizeof(float) * currentImageBuffer_.size()), currentImageBuffer_.data(),
currentImageBuffer_.data(), GL_DYNAMIC_DRAW);
GL_DYNAMIC_DRAW);
// Buffer threshold data // Buffer threshold data
glBindBuffer(GL_ARRAY_BUFFER, vbo_[2]); gl.glBindBuffer(GL_ARRAY_BUFFER, vbo_[2]);
glBufferData( gl.glBufferData(GL_ARRAY_BUFFER,
GL_ARRAY_BUFFER, sizeof(GLint) * currentIntegerBuffer_.size(),
static_cast<GLsizeiptr>(sizeof(GLint) * currentIntegerBuffer_.size()), currentIntegerBuffer_.data(),
currentIntegerBuffer_.data(), GL_DYNAMIC_DRAW);
GL_DYNAMIC_DRAW);
numVertices_ = numVertices_ =
static_cast<GLsizei>(currentImageBuffer_.size() / kPointsPerVertex); static_cast<GLsizei>(currentImageBuffer_.size() / kPointsPerVertex);

View file

@ -3,7 +3,6 @@
#include <scwx/qt/util/maplibre.hpp> #include <scwx/qt/util/maplibre.hpp>
#include <scwx/qt/util/tooltip.hpp> #include <scwx/qt/util/tooltip.hpp>
#include <scwx/util/logger.hpp> #include <scwx/util/logger.hpp>
#include <scwx/util/time.hpp>
#include <execution> #include <execution>
@ -19,9 +18,13 @@ namespace draw
static const std::string logPrefix_ = "scwx::qt::gl::draw::placefile_lines"; static const std::string logPrefix_ = "scwx::qt::gl::draw::placefile_lines";
static const auto logger_ = scwx::util::Logger::Create(logPrefix_); static const auto logger_ = scwx::util::Logger::Create(logPrefix_);
static constexpr std::size_t kNumRectangles = 1;
static constexpr std::size_t kNumTriangles = kNumRectangles * 2;
static constexpr std::size_t kVerticesPerTriangle = 3; static constexpr std::size_t kVerticesPerTriangle = 3;
static constexpr std::size_t kVerticesPerRectangle = kVerticesPerTriangle * 2; static constexpr std::size_t kVerticesPerRectangle = kVerticesPerTriangle * 2;
static constexpr std::size_t kPointsPerVertex = 9; static constexpr std::size_t kPointsPerVertex = 9;
static constexpr std::size_t kBufferLength =
kNumTriangles * kVerticesPerTriangle * kPointsPerVertex;
// Threshold, start time, end time // Threshold, start time, end time
static constexpr std::size_t kIntegersPerVertex_ = 3; static constexpr std::size_t kIntegersPerVertex_ = 3;
@ -107,7 +110,7 @@ public:
}; };
PlacefileLines::PlacefileLines(const std::shared_ptr<GlContext>& context) : PlacefileLines::PlacefileLines(const std::shared_ptr<GlContext>& context) :
DrawItem(), p(std::make_unique<Impl>(context)) DrawItem(context->gl()), p(std::make_unique<Impl>(context))
{ {
} }
PlacefileLines::~PlacefileLines() = default; PlacefileLines::~PlacefileLines() = default;
@ -128,6 +131,9 @@ void PlacefileLines::set_thresholded(bool thresholded)
void PlacefileLines::Initialize() void PlacefileLines::Initialize()
{ {
gl::OpenGLFunctions& gl = p->context_->gl();
auto& gl30 = p->context_->gl30();
p->shaderProgram_ = p->context_->GetShaderProgram( p->shaderProgram_ = p->context_->GetShaderProgram(
{{GL_VERTEX_SHADER, ":/gl/geo_texture2d.vert"}, {{GL_VERTEX_SHADER, ":/gl/geo_texture2d.vert"},
{GL_GEOMETRY_SHADER, ":/gl/threshold.geom"}, {GL_GEOMETRY_SHADER, ":/gl/threshold.geom"},
@ -142,78 +148,70 @@ void PlacefileLines::Initialize()
p->uSelectedTimeLocation_ = p->uSelectedTimeLocation_ =
p->shaderProgram_->GetUniformLocation("uSelectedTime"); p->shaderProgram_->GetUniformLocation("uSelectedTime");
glGenVertexArrays(1, &p->vao_); gl.glGenVertexArrays(1, &p->vao_);
glGenBuffers(2, p->vbo_.data()); gl.glGenBuffers(2, p->vbo_.data());
glBindVertexArray(p->vao_); gl.glBindVertexArray(p->vao_);
glBindBuffer(GL_ARRAY_BUFFER, p->vbo_[0]); gl.glBindBuffer(GL_ARRAY_BUFFER, p->vbo_[0]);
glBufferData(GL_ARRAY_BUFFER, 0u, nullptr, GL_DYNAMIC_DRAW); gl.glBufferData(GL_ARRAY_BUFFER, 0u, nullptr, GL_DYNAMIC_DRAW);
// NOLINTBEGIN(modernize-use-nullptr)
// NOLINTBEGIN(performance-no-int-to-ptr)
// NOLINTBEGIN(cppcoreguidelines-avoid-magic-numbers)
// aLatLong // aLatLong
glVertexAttribPointer(0, gl.glVertexAttribPointer(0,
2, 2,
GL_FLOAT, GL_FLOAT,
GL_FALSE, GL_FALSE,
kPointsPerVertex * sizeof(float), kPointsPerVertex * sizeof(float),
static_cast<void*>(0)); static_cast<void*>(0));
glEnableVertexAttribArray(0); gl.glEnableVertexAttribArray(0);
// aXYOffset // aXYOffset
glVertexAttribPointer(1, gl.glVertexAttribPointer(1,
2, 2,
GL_FLOAT, GL_FLOAT,
GL_FALSE, GL_FALSE,
kPointsPerVertex * sizeof(float), kPointsPerVertex * sizeof(float),
reinterpret_cast<void*>(2 * sizeof(float))); reinterpret_cast<void*>(2 * sizeof(float)));
glEnableVertexAttribArray(1); gl.glEnableVertexAttribArray(1);
// aModulate // aModulate
glVertexAttribPointer(3, gl.glVertexAttribPointer(3,
4, 4,
GL_FLOAT, GL_FLOAT,
GL_FALSE, GL_FALSE,
kPointsPerVertex * sizeof(float), kPointsPerVertex * sizeof(float),
reinterpret_cast<void*>(4 * sizeof(float))); reinterpret_cast<void*>(4 * sizeof(float)));
glEnableVertexAttribArray(3); gl.glEnableVertexAttribArray(3);
// aAngle // aAngle
glVertexAttribPointer(4, gl.glVertexAttribPointer(4,
1, 1,
GL_FLOAT, GL_FLOAT,
GL_FALSE, GL_FALSE,
kPointsPerVertex * sizeof(float), kPointsPerVertex * sizeof(float),
reinterpret_cast<void*>(8 * sizeof(float))); reinterpret_cast<void*>(8 * sizeof(float)));
glEnableVertexAttribArray(4); gl.glEnableVertexAttribArray(4);
glBindBuffer(GL_ARRAY_BUFFER, p->vbo_[1]); gl.glBindBuffer(GL_ARRAY_BUFFER, p->vbo_[1]);
glBufferData(GL_ARRAY_BUFFER, 0u, nullptr, GL_DYNAMIC_DRAW); gl.glBufferData(GL_ARRAY_BUFFER, 0u, nullptr, GL_DYNAMIC_DRAW);
// aThreshold // aThreshold
glVertexAttribIPointer(5, // gl.glVertexAttribIPointer(5, //
1, 1,
GL_INT, GL_INT,
kIntegersPerVertex_ * sizeof(GLint), kIntegersPerVertex_ * sizeof(GLint),
static_cast<void*>(0)); static_cast<void*>(0));
glEnableVertexAttribArray(5); gl.glEnableVertexAttribArray(5);
// aTimeRange // aTimeRange
glVertexAttribIPointer(6, // gl.glVertexAttribIPointer(6, //
2, 2,
GL_INT, GL_INT,
kIntegersPerVertex_ * sizeof(GLint), kIntegersPerVertex_ * sizeof(GLint),
reinterpret_cast<void*>(1 * sizeof(GLint))); reinterpret_cast<void*>(1 * sizeof(GLint)));
glEnableVertexAttribArray(6); gl.glEnableVertexAttribArray(6);
// aDisplayed // aDisplayed
glVertexAttribI1i(7, 1); gl30.glVertexAttribI1i(7, 1);
// NOLINTEND(cppcoreguidelines-avoid-magic-numbers)
// NOLINTEND(performance-no-int-to-ptr)
// NOLINTEND(modernize-use-nullptr)
p->dirty_ = true; p->dirty_ = true;
} }
@ -225,7 +223,9 @@ void PlacefileLines::Render(
if (p->currentNumLines_ > 0) if (p->currentNumLines_ > 0)
{ {
glBindVertexArray(p->vao_); gl::OpenGLFunctions& gl = p->context_->gl();
gl.glBindVertexArray(p->vao_);
p->Update(); p->Update();
p->shaderProgram_->Use(); p->shaderProgram_->Use();
@ -238,34 +238,36 @@ void PlacefileLines::Render(
// If thresholding is enabled, set the map distance // If thresholding is enabled, set the map distance
units::length::nautical_miles<float> mapDistance = units::length::nautical_miles<float> mapDistance =
util::maplibre::GetMapDistance(params); util::maplibre::GetMapDistance(params);
glUniform1f(p->uMapDistanceLocation_, mapDistance.value()); gl.glUniform1f(p->uMapDistanceLocation_, mapDistance.value());
} }
else else
{ {
// If thresholding is disabled, set the map distance to 0 // If thresholding is disabled, set the map distance to 0
glUniform1f(p->uMapDistanceLocation_, 0.0f); gl.glUniform1f(p->uMapDistanceLocation_, 0.0f);
} }
// Selected time // Selected time
std::chrono::system_clock::time_point selectedTime = std::chrono::system_clock::time_point selectedTime =
(p->selectedTime_ == std::chrono::system_clock::time_point {}) ? (p->selectedTime_ == std::chrono::system_clock::time_point {}) ?
scwx::util::time::now() : std::chrono::system_clock::now() :
p->selectedTime_; p->selectedTime_;
glUniform1i( gl.glUniform1i(
p->uSelectedTimeLocation_, p->uSelectedTimeLocation_,
static_cast<GLint>(std::chrono::duration_cast<std::chrono::minutes>( static_cast<GLint>(std::chrono::duration_cast<std::chrono::minutes>(
selectedTime.time_since_epoch()) selectedTime.time_since_epoch())
.count())); .count()));
// Draw icons // Draw icons
glDrawArrays(GL_TRIANGLES, 0, p->numVertices_); gl.glDrawArrays(GL_TRIANGLES, 0, p->numVertices_);
} }
} }
void PlacefileLines::Deinitialize() void PlacefileLines::Deinitialize()
{ {
glDeleteVertexArrays(1, &p->vao_); gl::OpenGLFunctions& gl = p->context_->gl();
glDeleteBuffers(2, p->vbo_.data());
gl.glDeleteVertexArrays(1, &p->vao_);
gl.glDeleteBuffers(2, p->vbo_.data());
std::unique_lock lock {p->lineMutex_}; std::unique_lock lock {p->lineMutex_};
@ -477,21 +479,21 @@ void PlacefileLines::Impl::Update()
// If the placefile has been updated // If the placefile has been updated
if (dirty_) if (dirty_)
{ {
gl::OpenGLFunctions& gl = context_->gl();
// Buffer lines data // Buffer lines data
glBindBuffer(GL_ARRAY_BUFFER, vbo_[0]); gl.glBindBuffer(GL_ARRAY_BUFFER, vbo_[0]);
glBufferData( gl.glBufferData(GL_ARRAY_BUFFER,
GL_ARRAY_BUFFER, sizeof(float) * currentLinesBuffer_.size(),
static_cast<GLsizeiptr>(sizeof(float) * currentLinesBuffer_.size()), currentLinesBuffer_.data(),
currentLinesBuffer_.data(), GL_DYNAMIC_DRAW);
GL_DYNAMIC_DRAW);
// Buffer threshold data // Buffer threshold data
glBindBuffer(GL_ARRAY_BUFFER, vbo_[1]); gl.glBindBuffer(GL_ARRAY_BUFFER, vbo_[1]);
glBufferData( gl.glBufferData(GL_ARRAY_BUFFER,
GL_ARRAY_BUFFER, sizeof(GLint) * currentIntegerBuffer_.size(),
static_cast<GLsizeiptr>(sizeof(GLint) * currentIntegerBuffer_.size()), currentIntegerBuffer_.data(),
currentIntegerBuffer_.data(), GL_DYNAMIC_DRAW);
GL_DYNAMIC_DRAW);
} }
dirty_ = false; dirty_ = false;
@ -527,7 +529,7 @@ bool PlacefileLines::RunMousePicking(
// If no time has been selected, use the current time // If no time has been selected, use the current time
std::chrono::system_clock::time_point selectedTime = std::chrono::system_clock::time_point selectedTime =
(p->selectedTime_ == std::chrono::system_clock::time_point {}) ? (p->selectedTime_ == std::chrono::system_clock::time_point {}) ?
scwx::util::time::now() : std::chrono::system_clock::now() :
p->selectedTime_; p->selectedTime_;
// For each pickable line // For each pickable line
@ -546,10 +548,8 @@ bool PlacefileLines::RunMousePicking(
units::length::nautical_miles<double> {line.di_->threshold_} units::length::nautical_miles<double> {line.di_->threshold_}
.value())) < 999 && .value())) < 999 &&
// Map distance is beyond/within the threshold // Map distance is beyond the threshold
line.di_->threshold_ < mapDistance && line.di_->threshold_ < mapDistance) ||
(line.di_->threshold_.value() >= 0.0 ||
-(line.di_->threshold_) > mapDistance)) ||
( (
// Line has a start time // Line has a start time

View file

@ -1,19 +1,13 @@
#include <scwx/qt/gl/draw/placefile_polygons.hpp> #include <scwx/qt/gl/draw/placefile_polygons.hpp>
#include <scwx/qt/util/maplibre.hpp> #include <scwx/qt/util/maplibre.hpp>
#include <scwx/util/logger.hpp> #include <scwx/util/logger.hpp>
#include <scwx/util/time.hpp>
#include <mutex> #include <mutex>
#include <GL/glu.h>
#include <boost/container/stable_vector.hpp> #include <boost/container/stable_vector.hpp>
#if !defined(__APPLE__) #if defined(_WIN32)
# include <GL/glu.h>
#else
# include <OpenGL/glu.h>
#endif
#if defined(_WIN32) || defined(__APPLE__)
typedef void (*_GLUfuncptr)(void); typedef void (*_GLUfuncptr)(void);
#endif #endif
@ -37,6 +31,7 @@ static constexpr std::size_t kIntegersPerVertex_ = 3;
static constexpr std::size_t kTessVertexScreenX_ = 0; static constexpr std::size_t kTessVertexScreenX_ = 0;
static constexpr std::size_t kTessVertexScreenY_ = 1; static constexpr std::size_t kTessVertexScreenY_ = 1;
static constexpr std::size_t kTessVertexScreenZ_ = 2;
static constexpr std::size_t kTessVertexXOffset_ = 3; static constexpr std::size_t kTessVertexXOffset_ = 3;
static constexpr std::size_t kTessVertexYOffset_ = 4; static constexpr std::size_t kTessVertexYOffset_ = 4;
static constexpr std::size_t kTessVertexR_ = 5; static constexpr std::size_t kTessVertexR_ = 5;
@ -131,7 +126,7 @@ public:
PlacefilePolygons::PlacefilePolygons( PlacefilePolygons::PlacefilePolygons(
const std::shared_ptr<GlContext>& context) : const std::shared_ptr<GlContext>& context) :
DrawItem(), p(std::make_unique<Impl>(context)) DrawItem(context->gl()), p(std::make_unique<Impl>(context))
{ {
} }
PlacefilePolygons::~PlacefilePolygons() = default; PlacefilePolygons::~PlacefilePolygons() = default;
@ -153,6 +148,8 @@ void PlacefilePolygons::set_thresholded(bool thresholded)
void PlacefilePolygons::Initialize() void PlacefilePolygons::Initialize()
{ {
gl::OpenGLFunctions& gl = p->context_->gl();
p->shaderProgram_ = p->context_->GetShaderProgram( p->shaderProgram_ = p->context_->GetShaderProgram(
{{GL_VERTEX_SHADER, ":/gl/map_color.vert"}, {{GL_VERTEX_SHADER, ":/gl/map_color.vert"},
{GL_GEOMETRY_SHADER, ":/gl/threshold.geom"}, {GL_GEOMETRY_SHADER, ":/gl/threshold.geom"},
@ -167,66 +164,58 @@ void PlacefilePolygons::Initialize()
p->uSelectedTimeLocation_ = p->uSelectedTimeLocation_ =
p->shaderProgram_->GetUniformLocation("uSelectedTime"); p->shaderProgram_->GetUniformLocation("uSelectedTime");
glGenVertexArrays(1, &p->vao_); gl.glGenVertexArrays(1, &p->vao_);
glGenBuffers(2, p->vbo_.data()); gl.glGenBuffers(2, p->vbo_.data());
glBindVertexArray(p->vao_); gl.glBindVertexArray(p->vao_);
glBindBuffer(GL_ARRAY_BUFFER, p->vbo_[0]); gl.glBindBuffer(GL_ARRAY_BUFFER, p->vbo_[0]);
glBufferData(GL_ARRAY_BUFFER, 0u, nullptr, GL_DYNAMIC_DRAW); gl.glBufferData(GL_ARRAY_BUFFER, 0u, nullptr, GL_DYNAMIC_DRAW);
// NOLINTBEGIN(modernize-use-nullptr)
// NOLINTBEGIN(performance-no-int-to-ptr)
// NOLINTBEGIN(cppcoreguidelines-avoid-magic-numbers)
// aScreenCoord // aScreenCoord
glVertexAttribPointer(0, gl.glVertexAttribPointer(0,
2, 2,
GL_FLOAT, GL_FLOAT,
GL_FALSE, GL_FALSE,
kPointsPerVertex * sizeof(float), kPointsPerVertex * sizeof(float),
static_cast<void*>(0)); static_cast<void*>(0));
glEnableVertexAttribArray(0); gl.glEnableVertexAttribArray(0);
// aXYOffset // aXYOffset
glVertexAttribPointer(1, gl.glVertexAttribPointer(1,
2, 2,
GL_FLOAT, GL_FLOAT,
GL_FALSE, GL_FALSE,
kPointsPerVertex * sizeof(float), kPointsPerVertex * sizeof(float),
reinterpret_cast<void*>(2 * sizeof(float))); reinterpret_cast<void*>(2 * sizeof(float)));
glEnableVertexAttribArray(1); gl.glEnableVertexAttribArray(1);
// aColor // aColor
glVertexAttribPointer(2, gl.glVertexAttribPointer(2,
4, 4,
GL_FLOAT, GL_FLOAT,
GL_FALSE, GL_FALSE,
kPointsPerVertex * sizeof(float), kPointsPerVertex * sizeof(float),
reinterpret_cast<void*>(4 * sizeof(float))); reinterpret_cast<void*>(4 * sizeof(float)));
glEnableVertexAttribArray(2); gl.glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, p->vbo_[1]); gl.glBindBuffer(GL_ARRAY_BUFFER, p->vbo_[1]);
glBufferData(GL_ARRAY_BUFFER, 0u, nullptr, GL_DYNAMIC_DRAW); gl.glBufferData(GL_ARRAY_BUFFER, 0u, nullptr, GL_DYNAMIC_DRAW);
// aThreshold // aThreshold
glVertexAttribIPointer(3, // gl.glVertexAttribIPointer(3, //
1, 1,
GL_INT, GL_INT,
kIntegersPerVertex_ * sizeof(GLint), kIntegersPerVertex_ * sizeof(GLint),
static_cast<void*>(0)); static_cast<void*>(0));
glEnableVertexAttribArray(3); gl.glEnableVertexAttribArray(3);
// aTimeRange // aTimeRange
glVertexAttribIPointer(4, // gl.glVertexAttribIPointer(4, //
2, 2,
GL_INT, GL_INT,
kIntegersPerVertex_ * sizeof(GLint), kIntegersPerVertex_ * sizeof(GLint),
reinterpret_cast<void*>(1 * sizeof(GLint))); reinterpret_cast<void*>(1 * sizeof(GLint)));
glEnableVertexAttribArray(4); gl.glEnableVertexAttribArray(4);
// NOLINTEND(cppcoreguidelines-avoid-magic-numbers)
// NOLINTEND(performance-no-int-to-ptr)
// NOLINTEND(modernize-use-nullptr)
p->dirty_ = true; p->dirty_ = true;
} }
@ -236,7 +225,9 @@ void PlacefilePolygons::Render(
{ {
if (!p->currentBuffer_.empty()) if (!p->currentBuffer_.empty())
{ {
glBindVertexArray(p->vao_); gl::OpenGLFunctions& gl = p->context_->gl();
gl.glBindVertexArray(p->vao_);
p->Update(); p->Update();
p->shaderProgram_->Use(); p->shaderProgram_->Use();
@ -249,34 +240,36 @@ void PlacefilePolygons::Render(
// If thresholding is enabled, set the map distance // If thresholding is enabled, set the map distance
units::length::nautical_miles<float> mapDistance = units::length::nautical_miles<float> mapDistance =
util::maplibre::GetMapDistance(params); util::maplibre::GetMapDistance(params);
glUniform1f(p->uMapDistanceLocation_, mapDistance.value()); gl.glUniform1f(p->uMapDistanceLocation_, mapDistance.value());
} }
else else
{ {
// If thresholding is disabled, set the map distance to 0 // If thresholding is disabled, set the map distance to 0
glUniform1f(p->uMapDistanceLocation_, 0.0f); gl.glUniform1f(p->uMapDistanceLocation_, 0.0f);
} }
// Selected time // Selected time
std::chrono::system_clock::time_point selectedTime = std::chrono::system_clock::time_point selectedTime =
(p->selectedTime_ == std::chrono::system_clock::time_point {}) ? (p->selectedTime_ == std::chrono::system_clock::time_point {}) ?
scwx::util::time::now() : std::chrono::system_clock::now() :
p->selectedTime_; p->selectedTime_;
glUniform1i( gl.glUniform1i(
p->uSelectedTimeLocation_, p->uSelectedTimeLocation_,
static_cast<GLint>(std::chrono::duration_cast<std::chrono::minutes>( static_cast<GLint>(std::chrono::duration_cast<std::chrono::minutes>(
selectedTime.time_since_epoch()) selectedTime.time_since_epoch())
.count())); .count()));
// Draw icons // Draw icons
glDrawArrays(GL_TRIANGLES, 0, p->numVertices_); gl.glDrawArrays(GL_TRIANGLES, 0, p->numVertices_);
} }
} }
void PlacefilePolygons::Deinitialize() void PlacefilePolygons::Deinitialize()
{ {
glDeleteVertexArrays(1, &p->vao_); gl::OpenGLFunctions& gl = p->context_->gl();
glDeleteBuffers(2, p->vbo_.data());
gl.glDeleteVertexArrays(1, &p->vao_);
gl.glDeleteBuffers(2, p->vbo_.data());
std::unique_lock lock {p->bufferMutex_}; std::unique_lock lock {p->bufferMutex_};
@ -321,23 +314,23 @@ void PlacefilePolygons::Impl::Update()
{ {
if (dirty_) if (dirty_)
{ {
gl::OpenGLFunctions& gl = context_->gl();
std::unique_lock lock {bufferMutex_}; std::unique_lock lock {bufferMutex_};
// Buffer vertex data // Buffer vertex data
glBindBuffer(GL_ARRAY_BUFFER, vbo_[0]); gl.glBindBuffer(GL_ARRAY_BUFFER, vbo_[0]);
glBufferData( gl.glBufferData(GL_ARRAY_BUFFER,
GL_ARRAY_BUFFER, sizeof(GLfloat) * currentBuffer_.size(),
static_cast<GLsizeiptr>(sizeof(GLfloat) * currentBuffer_.size()), currentBuffer_.data(),
currentBuffer_.data(), GL_DYNAMIC_DRAW);
GL_DYNAMIC_DRAW);
// Buffer threshold data // Buffer threshold data
glBindBuffer(GL_ARRAY_BUFFER, vbo_[1]); gl.glBindBuffer(GL_ARRAY_BUFFER, vbo_[1]);
glBufferData( gl.glBufferData(GL_ARRAY_BUFFER,
GL_ARRAY_BUFFER, sizeof(GLint) * currentIntegerBuffer_.size(),
static_cast<GLsizeiptr>(sizeof(GLint) * currentIntegerBuffer_.size()), currentIntegerBuffer_.data(),
currentIntegerBuffer_.data(), GL_DYNAMIC_DRAW);
GL_DYNAMIC_DRAW);
numVertices_ = numVertices_ =
static_cast<GLsizei>(currentBuffer_.size() / kPointsPerVertex); static_cast<GLsizei>(currentBuffer_.size() / kPointsPerVertex);

View file

@ -1,16 +1,22 @@
#include <scwx/qt/gl/draw/placefile_text.hpp> #include <scwx/qt/gl/draw/placefile_text.hpp>
#include <scwx/qt/manager/font_manager.hpp> #include <scwx/qt/manager/font_manager.hpp>
#include <scwx/qt/manager/placefile_manager.hpp>
#include <scwx/qt/settings/text_settings.hpp> #include <scwx/qt/settings/text_settings.hpp>
#include <scwx/qt/util/maplibre.hpp> #include <scwx/qt/util/maplibre.hpp>
#include <scwx/qt/util/tooltip.hpp> #include <scwx/qt/util/tooltip.hpp>
#include <scwx/util/logger.hpp> #include <scwx/util/logger.hpp>
#include <scwx/util/time.hpp>
#include <fmt/format.h> #include <fmt/format.h>
#include <imgui.h> #include <imgui.h>
#include <mbgl/util/constants.hpp> #include <mbgl/util/constants.hpp>
namespace scwx::qt::gl::draw namespace scwx
{
namespace qt
{
namespace gl
{
namespace draw
{ {
static const std::string logPrefix_ = "scwx::qt::gl::draw::placefile_text"; static const std::string logPrefix_ = "scwx::qt::gl::draw::placefile_text";
@ -19,16 +25,13 @@ static const auto logger_ = scwx::util::Logger::Create(logPrefix_);
class PlacefileText::Impl class PlacefileText::Impl
{ {
public: public:
explicit Impl(std::string placefileName) : explicit Impl(const std::shared_ptr<GlContext>& context,
placefileName_ {std::move(placefileName)} const std::string& placefileName) :
context_ {context}, placefileName_ {placefileName}
{ {
} }
~Impl() = default;
Impl(const Impl&) = delete; ~Impl() {}
Impl& operator=(const Impl&) = delete;
Impl(const Impl&&) = delete;
Impl& operator=(const Impl&&) = delete;
void RenderTextDrawItem( void RenderTextDrawItem(
const QMapLibre::CustomLayerRenderParameters& params, const QMapLibre::CustomLayerRenderParameters& params,
@ -40,6 +43,8 @@ public:
float x, float x,
float y); float y);
std::shared_ptr<GlContext> context_;
std::string placefileName_; std::string placefileName_;
bool thresholded_ {false}; bool thresholded_ {false};
@ -61,16 +66,13 @@ public:
std::vector<std::shared_ptr<const gr::Placefile::TextDrawItem>> textList_ {}; std::vector<std::shared_ptr<const gr::Placefile::TextDrawItem>> textList_ {};
std::vector<std::shared_ptr<const gr::Placefile::TextDrawItem>> newList_ {}; std::vector<std::shared_ptr<const gr::Placefile::TextDrawItem>> newList_ {};
std::vector<std::pair<std::shared_ptr<types::ImGuiFont>, std::vector<std::shared_ptr<types::ImGuiFont>> fonts_ {};
units::font_size::pixels<float>>> std::vector<std::shared_ptr<types::ImGuiFont>> newFonts_ {};
fonts_ {};
std::vector<std::pair<std::shared_ptr<types::ImGuiFont>,
units::font_size::pixels<float>>>
newFonts_ {};
}; };
PlacefileText::PlacefileText(const std::string& placefileName) : PlacefileText::PlacefileText(const std::shared_ptr<GlContext>& context,
DrawItem(), p(std::make_unique<Impl>(placefileName)) const std::string& placefileName) :
DrawItem(context->gl()), p(std::make_unique<Impl>(context, placefileName))
{ {
} }
PlacefileText::~PlacefileText() = default; PlacefileText::~PlacefileText() = default;
@ -131,14 +133,10 @@ void PlacefileText::Impl::RenderTextDrawItem(
// If no time has been selected, use the current time // If no time has been selected, use the current time
std::chrono::system_clock::time_point selectedTime = std::chrono::system_clock::time_point selectedTime =
(selectedTime_ == std::chrono::system_clock::time_point {}) ? (selectedTime_ == std::chrono::system_clock::time_point {}) ?
scwx::util::time::now() : std::chrono::system_clock::now() :
selectedTime_; selectedTime_;
const bool thresholdMet = if ((!thresholded_ || mapDistance_ <= di->threshold_) &&
!thresholded_ || mapDistance_ <= di->threshold_ ||
(di->threshold_.value() < 0.0 && mapDistance_ >= -(di->threshold_));
if (thresholdMet &&
(di->startTime_ == std::chrono::system_clock::time_point {} || (di->startTime_ == std::chrono::system_clock::time_point {} ||
(di->startTime_ <= selectedTime && selectedTime < di->endTime_))) (di->startTime_ <= selectedTime && selectedTime < di->endTime_)))
{ {
@ -162,8 +160,7 @@ void PlacefileText::Impl::RenderTextDrawItem(
std::size_t fontNumber = std::clamp<std::size_t>(di->fontNumber_, 0, 8); std::size_t fontNumber = std::clamp<std::size_t>(di->fontNumber_, 0, 8);
// Set the font for the drop shadow and text // Set the font for the drop shadow and text
ImGui::PushFont(fonts_[fontNumber].first->font(), ImGui::PushFont(fonts_[fontNumber]->font());
fonts_[fontNumber].second.value());
if (settings::TextSettings::Instance() if (settings::TextSettings::Instance()
.placefile_text_drop_shadow_enabled() .placefile_text_drop_shadow_enabled()
@ -265,7 +262,9 @@ void PlacefileText::StartText()
p->newList_.clear(); p->newList_.clear();
} }
void PlacefileText::SetFonts(const manager::PlacefileManager::FontMap& fonts) void PlacefileText::SetFonts(
const boost::unordered_flat_map<std::size_t,
std::shared_ptr<types::ImGuiFont>>& fonts)
{ {
auto defaultFont = manager::FontManager::Instance().GetImGuiFont( auto defaultFont = manager::FontManager::Instance().GetImGuiFont(
types::FontCategory::Default); types::FontCategory::Default);
@ -307,4 +306,7 @@ void PlacefileText::FinishText()
p->newFonts_.clear(); p->newFonts_.clear();
} }
} // namespace scwx::qt::gl::draw } // namespace draw
} // namespace gl
} // namespace qt
} // namespace scwx

View file

@ -2,7 +2,6 @@
#include <scwx/qt/gl/gl_context.hpp> #include <scwx/qt/gl/gl_context.hpp>
#include <scwx/qt/gl/draw/draw_item.hpp> #include <scwx/qt/gl/draw/draw_item.hpp>
#include <scwx/qt/manager/placefile_manager.hpp>
#include <scwx/qt/types/imgui_font.hpp> #include <scwx/qt/types/imgui_font.hpp>
#include <scwx/gr/placefile.hpp> #include <scwx/gr/placefile.hpp>
@ -20,7 +19,8 @@ namespace draw
class PlacefileText : public DrawItem class PlacefileText : public DrawItem
{ {
public: public:
explicit PlacefileText(const std::string& placefileName); explicit PlacefileText(const std::shared_ptr<GlContext>& context,
const std::string& placefileName);
~PlacefileText(); ~PlacefileText();
PlacefileText(const PlacefileText&) = delete; PlacefileText(const PlacefileText&) = delete;
@ -55,7 +55,10 @@ public:
* *
* @param [in] fonts A map of ImGui fonts * @param [in] fonts A map of ImGui fonts
*/ */
void SetFonts(const manager::PlacefileManager::FontMap& fonts); void
SetFonts(const boost::unordered_flat_map<std::size_t,
std::shared_ptr<types::ImGuiFont>>&
fonts);
/** /**
* Adds placefile text to the internal draw list. * Adds placefile text to the internal draw list.

View file

@ -1,7 +1,6 @@
#include <scwx/qt/gl/draw/placefile_triangles.hpp> #include <scwx/qt/gl/draw/placefile_triangles.hpp>
#include <scwx/qt/util/maplibre.hpp> #include <scwx/qt/util/maplibre.hpp>
#include <scwx/util/logger.hpp> #include <scwx/util/logger.hpp>
#include <scwx/util/time.hpp>
#include <mutex> #include <mutex>
@ -75,7 +74,7 @@ public:
PlacefileTriangles::PlacefileTriangles( PlacefileTriangles::PlacefileTriangles(
const std::shared_ptr<GlContext>& context) : const std::shared_ptr<GlContext>& context) :
DrawItem(), p(std::make_unique<Impl>(context)) DrawItem(context->gl()), p(std::make_unique<Impl>(context))
{ {
} }
PlacefileTriangles::~PlacefileTriangles() = default; PlacefileTriangles::~PlacefileTriangles() = default;
@ -97,6 +96,8 @@ void PlacefileTriangles::set_thresholded(bool thresholded)
void PlacefileTriangles::Initialize() void PlacefileTriangles::Initialize()
{ {
gl::OpenGLFunctions& gl = p->context_->gl();
p->shaderProgram_ = p->context_->GetShaderProgram( p->shaderProgram_ = p->context_->GetShaderProgram(
{{GL_VERTEX_SHADER, ":/gl/map_color.vert"}, {{GL_VERTEX_SHADER, ":/gl/map_color.vert"},
{GL_GEOMETRY_SHADER, ":/gl/threshold.geom"}, {GL_GEOMETRY_SHADER, ":/gl/threshold.geom"},
@ -111,66 +112,58 @@ void PlacefileTriangles::Initialize()
p->uSelectedTimeLocation_ = p->uSelectedTimeLocation_ =
p->shaderProgram_->GetUniformLocation("uSelectedTime"); p->shaderProgram_->GetUniformLocation("uSelectedTime");
glGenVertexArrays(1, &p->vao_); gl.glGenVertexArrays(1, &p->vao_);
glGenBuffers(2, p->vbo_.data()); gl.glGenBuffers(2, p->vbo_.data());
glBindVertexArray(p->vao_); gl.glBindVertexArray(p->vao_);
glBindBuffer(GL_ARRAY_BUFFER, p->vbo_[0]); gl.glBindBuffer(GL_ARRAY_BUFFER, p->vbo_[0]);
glBufferData(GL_ARRAY_BUFFER, 0u, nullptr, GL_DYNAMIC_DRAW); gl.glBufferData(GL_ARRAY_BUFFER, 0u, nullptr, GL_DYNAMIC_DRAW);
// NOLINTBEGIN(modernize-use-nullptr)
// NOLINTBEGIN(performance-no-int-to-ptr)
// NOLINTBEGIN(cppcoreguidelines-avoid-magic-numbers)
// aScreenCoord // aScreenCoord
glVertexAttribPointer(0, gl.glVertexAttribPointer(0,
2, 2,
GL_FLOAT, GL_FLOAT,
GL_FALSE, GL_FALSE,
kPointsPerVertex * sizeof(float), kPointsPerVertex * sizeof(float),
static_cast<void*>(0)); static_cast<void*>(0));
glEnableVertexAttribArray(0); gl.glEnableVertexAttribArray(0);
// aXYOffset // aXYOffset
glVertexAttribPointer(1, gl.glVertexAttribPointer(1,
2, 2,
GL_FLOAT, GL_FLOAT,
GL_FALSE, GL_FALSE,
kPointsPerVertex * sizeof(float), kPointsPerVertex * sizeof(float),
reinterpret_cast<void*>(2 * sizeof(float))); reinterpret_cast<void*>(2 * sizeof(float)));
glEnableVertexAttribArray(1); gl.glEnableVertexAttribArray(1);
// aColor // aColor
glVertexAttribPointer(2, gl.glVertexAttribPointer(2,
4, 4,
GL_FLOAT, GL_FLOAT,
GL_FALSE, GL_FALSE,
kPointsPerVertex * sizeof(float), kPointsPerVertex * sizeof(float),
reinterpret_cast<void*>(4 * sizeof(float))); reinterpret_cast<void*>(4 * sizeof(float)));
glEnableVertexAttribArray(2); gl.glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, p->vbo_[1]); gl.glBindBuffer(GL_ARRAY_BUFFER, p->vbo_[1]);
glBufferData(GL_ARRAY_BUFFER, 0u, nullptr, GL_DYNAMIC_DRAW); gl.glBufferData(GL_ARRAY_BUFFER, 0u, nullptr, GL_DYNAMIC_DRAW);
// aThreshold // aThreshold
glVertexAttribIPointer(3, // gl.glVertexAttribIPointer(3, //
1, 1,
GL_INT, GL_INT,
kIntegersPerVertex_ * sizeof(GLint), kIntegersPerVertex_ * sizeof(GLint),
static_cast<void*>(0)); static_cast<void*>(0));
glEnableVertexAttribArray(3); gl.glEnableVertexAttribArray(3);
// aTimeRange // aTimeRange
glVertexAttribIPointer(4, // gl.glVertexAttribIPointer(4, //
2, 2,
GL_INT, GL_INT,
kIntegersPerVertex_ * sizeof(GLint), kIntegersPerVertex_ * sizeof(GLint),
reinterpret_cast<void*>(1 * sizeof(GLint))); reinterpret_cast<void*>(1 * sizeof(GLint)));
glEnableVertexAttribArray(4); gl.glEnableVertexAttribArray(4);
// NOLINTEND(cppcoreguidelines-avoid-magic-numbers)
// NOLINTEND(performance-no-int-to-ptr)
// NOLINTEND(modernize-use-nullptr)
p->dirty_ = true; p->dirty_ = true;
} }
@ -180,7 +173,9 @@ void PlacefileTriangles::Render(
{ {
if (!p->currentBuffer_.empty()) if (!p->currentBuffer_.empty())
{ {
glBindVertexArray(p->vao_); gl::OpenGLFunctions& gl = p->context_->gl();
gl.glBindVertexArray(p->vao_);
p->Update(); p->Update();
p->shaderProgram_->Use(); p->shaderProgram_->Use();
@ -193,34 +188,36 @@ void PlacefileTriangles::Render(
// If thresholding is enabled, set the map distance // If thresholding is enabled, set the map distance
units::length::nautical_miles<float> mapDistance = units::length::nautical_miles<float> mapDistance =
util::maplibre::GetMapDistance(params); util::maplibre::GetMapDistance(params);
glUniform1f(p->uMapDistanceLocation_, mapDistance.value()); gl.glUniform1f(p->uMapDistanceLocation_, mapDistance.value());
} }
else else
{ {
// If thresholding is disabled, set the map distance to 0 // If thresholding is disabled, set the map distance to 0
glUniform1f(p->uMapDistanceLocation_, 0.0f); gl.glUniform1f(p->uMapDistanceLocation_, 0.0f);
} }
// Selected time // Selected time
std::chrono::system_clock::time_point selectedTime = std::chrono::system_clock::time_point selectedTime =
(p->selectedTime_ == std::chrono::system_clock::time_point {}) ? (p->selectedTime_ == std::chrono::system_clock::time_point {}) ?
scwx::util::time::now() : std::chrono::system_clock::now() :
p->selectedTime_; p->selectedTime_;
glUniform1i( gl.glUniform1i(
p->uSelectedTimeLocation_, p->uSelectedTimeLocation_,
static_cast<GLint>(std::chrono::duration_cast<std::chrono::minutes>( static_cast<GLint>(std::chrono::duration_cast<std::chrono::minutes>(
selectedTime.time_since_epoch()) selectedTime.time_since_epoch())
.count())); .count()));
// Draw icons // Draw icons
glDrawArrays(GL_TRIANGLES, 0, p->numVertices_); gl.glDrawArrays(GL_TRIANGLES, 0, p->numVertices_);
} }
} }
void PlacefileTriangles::Deinitialize() void PlacefileTriangles::Deinitialize()
{ {
glDeleteVertexArrays(1, &p->vao_); gl::OpenGLFunctions& gl = p->context_->gl();
glDeleteBuffers(2, p->vbo_.data());
gl.glDeleteVertexArrays(1, &p->vao_);
gl.glDeleteBuffers(2, p->vbo_.data());
std::unique_lock lock {p->bufferMutex_}; std::unique_lock lock {p->bufferMutex_};
@ -323,23 +320,23 @@ void PlacefileTriangles::Impl::Update()
{ {
if (dirty_) if (dirty_)
{ {
gl::OpenGLFunctions& gl = context_->gl();
std::unique_lock lock {bufferMutex_}; std::unique_lock lock {bufferMutex_};
// Buffer vertex data // Buffer vertex data
glBindBuffer(GL_ARRAY_BUFFER, vbo_[0]); gl.glBindBuffer(GL_ARRAY_BUFFER, vbo_[0]);
glBufferData( gl.glBufferData(GL_ARRAY_BUFFER,
GL_ARRAY_BUFFER, sizeof(GLfloat) * currentBuffer_.size(),
static_cast<GLsizeiptr>(sizeof(GLfloat) * currentBuffer_.size()), currentBuffer_.data(),
currentBuffer_.data(), GL_DYNAMIC_DRAW);
GL_DYNAMIC_DRAW);
// Buffer threshold data // Buffer threshold data
glBindBuffer(GL_ARRAY_BUFFER, vbo_[1]); gl.glBindBuffer(GL_ARRAY_BUFFER, vbo_[1]);
glBufferData( gl.glBufferData(GL_ARRAY_BUFFER,
GL_ARRAY_BUFFER, sizeof(GLint) * currentIntegerBuffer_.size(),
static_cast<GLsizeiptr>(sizeof(GLint) * currentIntegerBuffer_.size()), currentIntegerBuffer_.data(),
currentIntegerBuffer_.data(), GL_DYNAMIC_DRAW);
GL_DYNAMIC_DRAW);
numVertices_ = numVertices_ =
static_cast<GLsizei>(currentBuffer_.size() / kPointsPerVertex); static_cast<GLsizei>(currentBuffer_.size() / kPointsPerVertex);

View file

@ -3,7 +3,13 @@
#include <optional> #include <optional>
namespace scwx::qt::gl::draw namespace scwx
{
namespace qt
{
namespace gl
{
namespace draw
{ {
static const std::string logPrefix_ = "scwx::qt::gl::draw::rectangle"; static const std::string logPrefix_ = "scwx::qt::gl::draw::rectangle";
@ -21,7 +27,7 @@ class Rectangle::Impl
{ {
public: public:
explicit Impl(std::shared_ptr<GlContext> context) : explicit Impl(std::shared_ptr<GlContext> context) :
context_ {std::move(context)}, context_ {context},
dirty_ {false}, dirty_ {false},
visible_ {true}, visible_ {true},
x_ {0.0f}, x_ {0.0f},
@ -38,12 +44,8 @@ public:
vbo_ {GL_INVALID_INDEX} vbo_ {GL_INVALID_INDEX}
{ {
} }
~Impl() = default;
Impl(const Impl&) = delete; ~Impl() {}
Impl& operator=(const Impl&) = delete;
Impl(const Impl&&) = delete;
Impl& operator=(const Impl&&) = delete;
std::shared_ptr<GlContext> context_; std::shared_ptr<GlContext> context_;
@ -71,7 +73,7 @@ public:
}; };
Rectangle::Rectangle(std::shared_ptr<GlContext> context) : Rectangle::Rectangle(std::shared_ptr<GlContext> context) :
DrawItem(), p(std::make_unique<Impl>(context)) DrawItem(context->gl()), p(std::make_unique<Impl>(context))
{ {
} }
Rectangle::~Rectangle() = default; Rectangle::~Rectangle() = default;
@ -81,45 +83,41 @@ Rectangle& Rectangle::operator=(Rectangle&&) noexcept = default;
void Rectangle::Initialize() void Rectangle::Initialize()
{ {
gl::OpenGLFunctions& gl = p->context_->gl();
p->shaderProgram_ = p->shaderProgram_ =
p->context_->GetShaderProgram(":/gl/color.vert", ":/gl/color.frag"); p->context_->GetShaderProgram(":/gl/color.vert", ":/gl/color.frag");
p->uMVPMatrixLocation_ = p->uMVPMatrixLocation_ =
glGetUniformLocation(p->shaderProgram_->id(), "uMVPMatrix"); gl.glGetUniformLocation(p->shaderProgram_->id(), "uMVPMatrix");
if (p->uMVPMatrixLocation_ == -1) if (p->uMVPMatrixLocation_ == -1)
{ {
logger_->warn("Could not find uMVPMatrix"); logger_->warn("Could not find uMVPMatrix");
} }
glGenVertexArrays(1, &p->vao_); gl.glGenVertexArrays(1, &p->vao_);
glGenBuffers(1, &p->vbo_); gl.glGenBuffers(1, &p->vbo_);
glBindVertexArray(p->vao_); gl.glBindVertexArray(p->vao_);
glBindBuffer(GL_ARRAY_BUFFER, p->vbo_); gl.glBindBuffer(GL_ARRAY_BUFFER, p->vbo_);
glBufferData( gl.glBufferData(
GL_ARRAY_BUFFER, sizeof(float) * BUFFER_LENGTH, nullptr, GL_DYNAMIC_DRAW); GL_ARRAY_BUFFER, sizeof(float) * BUFFER_LENGTH, nullptr, GL_DYNAMIC_DRAW);
// NOLINTBEGIN(modernize-use-nullptr) gl.glVertexAttribPointer(0,
// NOLINTBEGIN(performance-no-int-to-ptr) 3,
GL_FLOAT,
GL_FALSE,
POINTS_PER_VERTEX * sizeof(float),
static_cast<void*>(0));
gl.glEnableVertexAttribArray(0);
glVertexAttribPointer(0, gl.glVertexAttribPointer(1,
3, 4,
GL_FLOAT, GL_FLOAT,
GL_FALSE, GL_FALSE,
POINTS_PER_VERTEX * sizeof(float), POINTS_PER_VERTEX * sizeof(float),
static_cast<void*>(0)); reinterpret_cast<void*>(3 * sizeof(float)));
glEnableVertexAttribArray(0); gl.glEnableVertexAttribArray(1);
glVertexAttribPointer(1,
4,
GL_FLOAT,
GL_FALSE,
POINTS_PER_VERTEX * sizeof(float),
reinterpret_cast<void*>(3 * sizeof(float)));
glEnableVertexAttribArray(1);
// NOLINTEND(performance-no-int-to-ptr)
// NOLINTEND(modernize-use-nullptr)
p->dirty_ = true; p->dirty_ = true;
} }
@ -128,8 +126,10 @@ void Rectangle::Render(const QMapLibre::CustomLayerRenderParameters& params)
{ {
if (p->visible_) if (p->visible_)
{ {
glBindVertexArray(p->vao_); gl::OpenGLFunctions& gl = p->context_->gl();
glBindBuffer(GL_ARRAY_BUFFER, p->vbo_);
gl.glBindVertexArray(p->vao_);
gl.glBindBuffer(GL_ARRAY_BUFFER, p->vbo_);
p->Update(); p->Update();
p->shaderProgram_->Use(); p->shaderProgram_->Use();
@ -138,23 +138,23 @@ void Rectangle::Render(const QMapLibre::CustomLayerRenderParameters& params)
if (p->fillColor_.has_value()) if (p->fillColor_.has_value())
{ {
// Draw fill // Draw fill
// NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers) gl.glDrawArrays(GL_TRIANGLES, 24, 6);
glDrawArrays(GL_TRIANGLES, 24, 6);
} }
if (p->borderWidth_ > 0.0f) if (p->borderWidth_ > 0.0f)
{ {
// Draw border // Draw border
// NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers) gl.glDrawArrays(GL_TRIANGLES, 0, 24);
glDrawArrays(GL_TRIANGLES, 0, 24);
} }
} }
} }
void Rectangle::Deinitialize() void Rectangle::Deinitialize()
{ {
glDeleteVertexArrays(1, &p->vao_); gl::OpenGLFunctions& gl = p->context_->gl();
glDeleteBuffers(1, &p->vbo_);
gl.glDeleteVertexArrays(1, &p->vao_);
gl.glDeleteBuffers(1, &p->vbo_);
} }
void Rectangle::SetBorder(float width, boost::gil::rgba8_pixel_t color) void Rectangle::SetBorder(float width, boost::gil::rgba8_pixel_t color)
@ -206,6 +206,8 @@ void Rectangle::Impl::Update()
{ {
if (dirty_) if (dirty_)
{ {
gl::OpenGLFunctions& gl = context_->gl();
const float lox = x_; const float lox = x_;
const float rox = x_ + width_; const float rox = x_ + width_;
const float boy = y_; const float boy = y_;
@ -287,13 +289,16 @@ void Rectangle::Impl::Update()
{lox, toy, z_, fc0, fc1, fc2, fc3} // TL {lox, toy, z_, fc0, fc1, fc2, fc3} // TL
}}; }};
glBufferData(GL_ARRAY_BUFFER, gl.glBufferData(GL_ARRAY_BUFFER,
sizeof(float) * BUFFER_LENGTH, sizeof(float) * BUFFER_LENGTH,
static_cast<const void*>(buffer), buffer,
GL_DYNAMIC_DRAW); GL_DYNAMIC_DRAW);
dirty_ = false; dirty_ = false;
} }
} }
} // namespace scwx::qt::gl::draw } // namespace draw
} // namespace gl
} // namespace qt
} // namespace scwx

View file

@ -1,12 +1,25 @@
#pragma once #pragma once
#include <glad/gl.h> #include <QOpenGLFunctions_3_3_Core>
#define SCWX_GL_CHECK_ERROR() \ #define SCWX_GL_CHECK_ERROR() \
{ \ { \
GLenum err; \ GLenum err; \
while ((err = glGetError()) != GL_NO_ERROR) \ while ((err = gl.glGetError()) != GL_NO_ERROR) \
{ \ { \
logger_->error("GL Error: {}, {}: {}", err, __FILE__, __LINE__); \ logger_->error("GL Error: {}, {}: {}", err, __FILE__, __LINE__); \
} \ } \
} }
namespace scwx
{
namespace qt
{
namespace gl
{
using OpenGLFunctions = QOpenGLFunctions_3_3_Core;
}
} // namespace qt
} // namespace scwx

View file

@ -3,38 +3,45 @@
#include <scwx/util/logger.hpp> #include <scwx/util/logger.hpp>
#include <boost/container_hash/hash.hpp> #include <boost/container_hash/hash.hpp>
#include <QMessageBox>
namespace scwx::qt::gl namespace scwx
{
namespace qt
{
namespace gl
{ {
static const std::string logPrefix_ = "scwx::qt::gl::gl_context"; static const std::string logPrefix_ = "scwx::qt::gl::gl_context";
static const auto logger_ = scwx::util::Logger::Create(logPrefix_);
class GlContext::Impl class GlContext::Impl
{ {
public: public:
explicit Impl() = default; explicit Impl() :
~Impl() = default; gl_ {},
shaderProgramMap_ {},
Impl(const Impl&) = delete; shaderProgramMutex_ {},
Impl& operator=(const Impl&) = delete; textureAtlas_ {GL_INVALID_INDEX},
Impl(const Impl&&) = delete; textureMutex_ {}
Impl& operator=(const Impl&&) = delete; {
}
~Impl() {}
void InitializeGL(); void InitializeGL();
static std::size_t static std::size_t
GetShaderKey(std::initializer_list<std::pair<GLenum, std::string>> shaders); GetShaderKey(std::initializer_list<std::pair<GLenum, std::string>> shaders);
gl::OpenGLFunctions gl_;
QOpenGLFunctions_3_0 gl30_;
bool glInitialized_ {false}; bool glInitialized_ {false};
std::unordered_map<std::size_t, std::shared_ptr<gl::ShaderProgram>> std::unordered_map<std::size_t, std::shared_ptr<gl::ShaderProgram>>
shaderProgramMap_ {}; shaderProgramMap_;
std::mutex shaderProgramMutex_ {}; std::mutex shaderProgramMutex_;
GLuint textureAtlas_ {GL_INVALID_INDEX}; GLuint textureAtlas_;
std::mutex textureMutex_ {}; std::mutex textureMutex_;
std::uint64_t textureBufferCount_ {}; std::uint64_t textureBufferCount_ {};
}; };
@ -45,6 +52,16 @@ GlContext::~GlContext() = default;
GlContext::GlContext(GlContext&&) noexcept = default; GlContext::GlContext(GlContext&&) noexcept = default;
GlContext& GlContext::operator=(GlContext&&) noexcept = default; GlContext& GlContext::operator=(GlContext&&) noexcept = default;
gl::OpenGLFunctions& GlContext::gl()
{
return p->gl_;
}
QOpenGLFunctions_3_0& GlContext::gl30()
{
return p->gl30_;
}
std::uint64_t GlContext::texture_buffer_count() const std::uint64_t GlContext::texture_buffer_count() const
{ {
return p->textureBufferCount_; return p->textureBufferCount_;
@ -57,54 +74,10 @@ void GlContext::Impl::InitializeGL()
return; return;
} }
const int gladVersion = gladLoaderLoadGL(); gl_.initializeOpenGLFunctions();
if (!gladVersion) gl30_.initializeOpenGLFunctions();
{
logger_->error("gladLoaderLoadGL failed");
QMessageBox::critical( gl_.glGenTextures(1, &textureAtlas_);
nullptr, "Supercell Wx", "Unable to initialize OpenGL");
throw std::runtime_error("Unable to initialize OpenGL");
}
logger_->info("GLAD initialization complete: OpenGL {}.{}",
GLAD_VERSION_MAJOR(gladVersion),
GLAD_VERSION_MINOR(gladVersion));
auto glVersion = reinterpret_cast<const char*>(glGetString(GL_VERSION));
auto glVendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
auto glRenderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER));
logger_->info("OpenGL Version: {}", glVersion);
logger_->info("OpenGL Vendor: {}", glVendor);
logger_->info("OpenGL Renderer: {}", glRenderer);
// Get OpenGL version
GLint major = 0;
GLint minor = 0;
glGetIntegerv(GL_MAJOR_VERSION, &major);
glGetIntegerv(GL_MINOR_VERSION, &minor);
if (major < 3 || (major == 3 && minor < 3) || !GLAD_GL_VERSION_3_3)
{
logger_->error(
"OpenGL 3.3 or greater is required, found {}.{}", major, minor);
QMessageBox::critical(
nullptr,
"Supercell Wx",
QString("OpenGL 3.3 or greater is required, found %1.%2\n\n%3\n%4\n%5")
.arg(major)
.arg(minor)
.arg(glVersion)
.arg(glVendor)
.arg(glRenderer));
throw std::runtime_error("OpenGL version too low");
}
glGenTextures(1, &textureAtlas_);
glInitialized_ = true; glInitialized_ = true;
} }
@ -129,7 +102,7 @@ std::shared_ptr<gl::ShaderProgram> GlContext::GetShaderProgram(
if (it == p->shaderProgramMap_.end()) if (it == p->shaderProgramMap_.end())
{ {
shaderProgram = std::make_shared<gl::ShaderProgram>(); shaderProgram = std::make_shared<gl::ShaderProgram>(p->gl_);
shaderProgram->Load(shaders); shaderProgram->Load(shaders);
p->shaderProgramMap_[key] = shaderProgram; p->shaderProgramMap_[key] = shaderProgram;
} }
@ -152,7 +125,7 @@ GLuint GlContext::GetTextureAtlas()
if (p->textureBufferCount_ != textureAtlas.BuildCount()) if (p->textureBufferCount_ != textureAtlas.BuildCount())
{ {
p->textureBufferCount_ = textureAtlas.BuildCount(); p->textureBufferCount_ = textureAtlas.BuildCount();
textureAtlas.BufferAtlas(p->textureAtlas_); textureAtlas.BufferAtlas(p->gl_, p->textureAtlas_);
} }
return p->textureAtlas_; return p->textureAtlas_;
@ -165,8 +138,10 @@ void GlContext::Initialize()
void GlContext::StartFrame() void GlContext::StartFrame()
{ {
glClearColor(0.0f, 0.0f, 0.0f, 1.0f); auto& gl = p->gl_;
glClear(GL_COLOR_BUFFER_BIT);
gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
gl.glClear(GL_COLOR_BUFFER_BIT);
} }
std::size_t GlContext::Impl::GetShaderKey( std::size_t GlContext::Impl::GetShaderKey(
@ -181,4 +156,6 @@ std::size_t GlContext::Impl::GetShaderKey(
return seed; return seed;
} }
} // namespace scwx::qt::gl } // namespace gl
} // namespace qt
} // namespace scwx

View file

@ -3,6 +3,8 @@
#include <scwx/qt/gl/gl.hpp> #include <scwx/qt/gl/gl.hpp>
#include <scwx/qt/gl/shader_program.hpp> #include <scwx/qt/gl/shader_program.hpp>
#include <QOpenGLFunctions_3_0>
namespace scwx namespace scwx
{ {
namespace qt namespace qt
@ -22,6 +24,9 @@ public:
GlContext(GlContext&&) noexcept; GlContext(GlContext&&) noexcept;
GlContext& operator=(GlContext&&) noexcept; GlContext& operator=(GlContext&&) noexcept;
gl::OpenGLFunctions& gl();
QOpenGLFunctions_3_0& gl30();
std::uint64_t texture_buffer_count() const; std::uint64_t texture_buffer_count() const;
std::shared_ptr<gl::ShaderProgram> std::shared_ptr<gl::ShaderProgram>

View file

@ -2,9 +2,12 @@
#include <scwx/util/logger.hpp> #include <scwx/util/logger.hpp>
#include <QFile> #include <QFile>
#include <QTextStream>
namespace scwx::qt::gl namespace scwx
{
namespace qt
{
namespace gl
{ {
static const std::string logPrefix_ = "scwx::qt::gl::shader_program"; static const std::string logPrefix_ = "scwx::qt::gl::shader_program";
@ -20,25 +23,29 @@ static const std::unordered_map<GLenum, std::string> kShaderNames_ {
class ShaderProgram::Impl class ShaderProgram::Impl
{ {
public: public:
explicit Impl() : id_ {glCreateProgram()} {} explicit Impl(OpenGLFunctions& gl) : gl_(gl), id_ {GL_INVALID_INDEX}
{
// Create shader program
id_ = gl_.glCreateProgram();
}
~Impl() ~Impl()
{ {
// Delete shader program // Delete shader program
glDeleteProgram(id_); gl_.glDeleteProgram(id_);
} }
Impl(const Impl&) = delete;
Impl& operator=(const Impl&) = delete;
Impl(const Impl&&) = delete;
Impl& operator=(const Impl&&) = delete;
static std::string ShaderName(GLenum type); static std::string ShaderName(GLenum type);
OpenGLFunctions& gl_;
GLuint id_; GLuint id_;
}; };
ShaderProgram::ShaderProgram() : p(std::make_unique<Impl>()) {} ShaderProgram::ShaderProgram(OpenGLFunctions& gl) :
p(std::make_unique<Impl>(gl))
{
}
ShaderProgram::~ShaderProgram() = default; ShaderProgram::~ShaderProgram() = default;
ShaderProgram::ShaderProgram(ShaderProgram&&) noexcept = default; ShaderProgram::ShaderProgram(ShaderProgram&&) noexcept = default;
@ -51,7 +58,7 @@ GLuint ShaderProgram::id() const
GLint ShaderProgram::GetUniformLocation(const std::string& name) GLint ShaderProgram::GetUniformLocation(const std::string& name)
{ {
const GLint location = glGetUniformLocation(p->id_, name.c_str()); GLint location = p->gl_.glGetUniformLocation(p->id_, name.c_str());
if (location == -1) if (location == -1)
{ {
logger_->warn("Could not find {}", name); logger_->warn("Could not find {}", name);
@ -81,6 +88,8 @@ bool ShaderProgram::Load(
{ {
logger_->debug("Load()"); logger_->debug("Load()");
OpenGLFunctions& gl = p->gl_;
GLint glSuccess; GLint glSuccess;
bool success = true; bool success = true;
char infoLog[kInfoLogBufSize]; char infoLog[kInfoLogBufSize];
@ -111,17 +120,16 @@ bool ShaderProgram::Load(
const char* shaderSourceC = shaderSource.c_str(); const char* shaderSourceC = shaderSource.c_str();
// Create a shader // Create a shader
const GLuint shaderId = glCreateShader(shader.first); GLuint shaderId = gl.glCreateShader(shader.first);
shaderIds.push_back(shaderId); shaderIds.push_back(shaderId);
// Attach the shader source code and compile the shader // Attach the shader source code and compile the shader
glShaderSource(shaderId, 1, &shaderSourceC, nullptr); gl.glShaderSource(shaderId, 1, &shaderSourceC, NULL);
glCompileShader(shaderId); gl.glCompileShader(shaderId);
// Check for errors // Check for errors
glGetShaderiv(shaderId, GL_COMPILE_STATUS, &glSuccess); gl.glGetShaderiv(shaderId, GL_COMPILE_STATUS, &glSuccess);
glGetShaderInfoLog( gl.glGetShaderInfoLog(shaderId, kInfoLogBufSize, &logLength, infoLog);
shaderId, kInfoLogBufSize, &logLength, static_cast<GLchar*>(infoLog));
if (!glSuccess) if (!glSuccess)
{ {
logger_->error("Shader compilation failed: {}", infoLog); logger_->error("Shader compilation failed: {}", infoLog);
@ -130,7 +138,7 @@ bool ShaderProgram::Load(
} }
else if (logLength > 0) else if (logLength > 0)
{ {
logger_->warn("Shader compiled with warnings: {}", infoLog); logger_->error("Shader compiled with warnings: {}", infoLog);
} }
} }
@ -138,14 +146,13 @@ bool ShaderProgram::Load(
{ {
for (auto& shaderId : shaderIds) for (auto& shaderId : shaderIds)
{ {
glAttachShader(p->id_, shaderId); gl.glAttachShader(p->id_, shaderId);
} }
glLinkProgram(p->id_); gl.glLinkProgram(p->id_);
// Check for errors // Check for errors
glGetProgramiv(p->id_, GL_LINK_STATUS, &glSuccess); gl.glGetProgramiv(p->id_, GL_LINK_STATUS, &glSuccess);
glGetProgramInfoLog( gl.glGetProgramInfoLog(p->id_, kInfoLogBufSize, &logLength, infoLog);
p->id_, kInfoLogBufSize, &logLength, static_cast<GLchar*>(infoLog));
if (!glSuccess) if (!glSuccess)
{ {
logger_->error("Shader program link failed: {}", infoLog); logger_->error("Shader program link failed: {}", infoLog);
@ -153,14 +160,14 @@ bool ShaderProgram::Load(
} }
else if (logLength > 0) else if (logLength > 0)
{ {
logger_->warn("Shader program linked with warnings: {}", infoLog); logger_->error("Shader program linked with warnings: {}", infoLog);
} }
} }
// Delete shaders // Delete shaders
for (auto& shaderId : shaderIds) for (auto& shaderId : shaderIds)
{ {
glDeleteShader(shaderId); gl.glDeleteShader(shaderId);
} }
return success; return success;
@ -168,7 +175,9 @@ bool ShaderProgram::Load(
void ShaderProgram::Use() const void ShaderProgram::Use() const
{ {
glUseProgram(p->id_); p->gl_.glUseProgram(p->id_);
} }
} // namespace scwx::qt::gl } // namespace gl
} // namespace qt
} // namespace scwx

View file

@ -19,7 +19,7 @@ namespace gl
class ShaderProgram class ShaderProgram
{ {
public: public:
explicit ShaderProgram(); explicit ShaderProgram(OpenGLFunctions& gl);
virtual ~ShaderProgram(); virtual ~ShaderProgram();
ShaderProgram(const ShaderProgram&) = delete; ShaderProgram(const ShaderProgram&) = delete;

View file

@ -44,14 +44,6 @@ void WaitForInitialization()
} }
} }
// Only use for test cases
void ResetInitilization()
{
logger_->debug("Application initialization reset");
std::unique_lock lock(initializationMutex_);
initialized_ = false;
}
} // namespace Application } // namespace Application
} // namespace main } // namespace main
} // namespace qt } // namespace qt

View file

@ -11,8 +11,6 @@ namespace Application
void FinishInitialization(); void FinishInitialization();
void WaitForInitialization(); void WaitForInitialization();
// Only use for test cases
void ResetInitilization();
} // namespace Application } // namespace Application
} // namespace main } // namespace main

View file

@ -1,136 +0,0 @@
#include <scwx/qt/settings/general_settings.hpp>
#include <scwx/qt/main/check_privilege.hpp>
#include <QtGlobal>
#include <QStandardPaths>
#include <filesystem>
#include <QObject>
#include <QMessageBox>
#include <QCheckBox>
#ifdef _WIN32
# include <windows.h>
#else
# include <unistd.h>
#endif
namespace scwx::qt::main
{
bool is_high_privilege()
{
#if defined(_WIN32)
bool isAdmin = false;
HANDLE token = NULL;
TOKEN_ELEVATION elevation;
DWORD elevationSize = sizeof(TOKEN_ELEVATION);
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token))
{
return false;
}
if (!GetTokenInformation(
token, TokenElevation, &elevation, elevationSize, &elevationSize))
{
CloseHandle(token);
return false;
}
isAdmin = elevation.TokenIsElevated;
CloseHandle(token);
return isAdmin;
#elif defined(Q_OS_UNIX)
// On UNIX root is always uid 0. On Linux this is enforced by the kernel.
return geteuid() == 0;
#else
return false;
#endif
}
#if defined(_WIN32)
static const QString message = QObject::tr(
"Supercell Wx has been run with administrator permissions. It is "
"recommended to run it without administrator permissions Do you wish to "
"continue?");
#elif defined(Q_OS_UNIX)
static const QString message = QObject::tr(
"Supercell Wx has been run as root. It is recommended to run it as a normal "
"user. Do you wish to continue?");
#else
static const QString message = QObject::tr("");
#endif
static const QString title = QObject::tr("Supercell Wx");
static const QString checkBoxText =
QObject::tr("Do not show this warning again.");
class PrivilegeChecker::Impl
{
public:
explicit Impl() :
highPrivilege_ {is_high_privilege()},
dialog_ {QMessageBox::Icon::Warning, title, message},
checkBox_(new QCheckBox(checkBoxText, &dialog_))
{
const std::string appDataPath {
QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)
.toStdString()};
hasAppData_ = std::filesystem::exists(appDataPath);
dialog_.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
dialog_.setDefaultButton(QMessageBox::No);
dialog_.setCheckBox(checkBox_);
};
bool hasAppData_;
bool firstCheckCheckBoxState_ {true};
bool highPrivilege_;
QMessageBox dialog_;
QCheckBox* checkBox_;
};
PrivilegeChecker::PrivilegeChecker() :
p(std::make_unique<PrivilegeChecker::Impl>())
{
}
PrivilegeChecker::~PrivilegeChecker() = default;
bool PrivilegeChecker::pre_settings_check()
{
if (p->hasAppData_ || !p->highPrivilege_)
{
return false;
}
const int result = p->dialog_.exec();
p->firstCheckCheckBoxState_ = p->checkBox_->isChecked();
return result != QMessageBox::Yes;
}
bool PrivilegeChecker::post_settings_check()
{
auto& highPrivilegeWarningEnabled =
settings::GeneralSettings::Instance().high_privilege_warning_enabled();
if (!highPrivilegeWarningEnabled.GetValue() || !p->highPrivilege_)
{
return false;
}
else if (!p->hasAppData_)
{
highPrivilegeWarningEnabled.StageValue(!p->firstCheckCheckBoxState_);
return false;
}
switch (p->dialog_.exec())
{
case QMessageBox::Yes:
highPrivilegeWarningEnabled.StageValue(!p->checkBox_->isChecked());
return false;
case QMessageBox::No:
default:
return true;
}
}
} // namespace scwx::qt::main

View file

@ -1,30 +0,0 @@
#pragma once
#include <memory>
namespace scwx::qt::main
{
bool is_high_privilege();
class PrivilegeChecker
{
public:
explicit PrivilegeChecker();
~PrivilegeChecker();
PrivilegeChecker(const PrivilegeChecker&) = delete;
PrivilegeChecker& operator=(const PrivilegeChecker&) = delete;
PrivilegeChecker(const PrivilegeChecker&&) = delete;
PrivilegeChecker& operator=(const PrivilegeChecker&&) = delete;
// returning true means check failed.
bool pre_settings_check();
bool post_settings_check();
private:
class Impl;
std::unique_ptr<Impl> p;
};
} // namespace scwx::qt::main

View file

@ -3,18 +3,15 @@
#include <scwx/qt/config/county_database.hpp> #include <scwx/qt/config/county_database.hpp>
#include <scwx/qt/config/radar_site.hpp> #include <scwx/qt/config/radar_site.hpp>
#include <scwx/qt/main/main_window.hpp> #include <scwx/qt/main/main_window.hpp>
#include <scwx/qt/main/process_validation.hpp>
#include <scwx/qt/main/versions.hpp> #include <scwx/qt/main/versions.hpp>
#include <scwx/qt/manager/log_manager.hpp> #include <scwx/qt/manager/log_manager.hpp>
#include <scwx/qt/manager/radar_product_manager.hpp> #include <scwx/qt/manager/radar_product_manager.hpp>
#include <scwx/qt/manager/resource_manager.hpp> #include <scwx/qt/manager/resource_manager.hpp>
#include <scwx/qt/manager/settings_manager.hpp> #include <scwx/qt/manager/settings_manager.hpp>
#include <scwx/qt/manager/task_manager.hpp>
#include <scwx/qt/manager/thread_manager.hpp> #include <scwx/qt/manager/thread_manager.hpp>
#include <scwx/qt/settings/general_settings.hpp> #include <scwx/qt/settings/general_settings.hpp>
#include <scwx/qt/types/qt_types.hpp> #include <scwx/qt/types/qt_types.hpp>
#include <scwx/qt/ui/setup/setup_wizard.hpp> #include <scwx/qt/ui/setup/setup_wizard.hpp>
#include <scwx/qt/main/check_privilege.hpp>
#include <scwx/network/cpr.hpp> #include <scwx/network/cpr.hpp>
#include <scwx/util/environment.hpp> #include <scwx/util/environment.hpp>
#include <scwx/util/logger.hpp> #include <scwx/util/logger.hpp>
@ -28,21 +25,11 @@
#include <fmt/format.h> #include <fmt/format.h>
#include <QApplication> #include <QApplication>
#include <QStandardPaths> #include <QStandardPaths>
#include <QStyleHints>
#include <QSurfaceFormat>
#include <QTranslator> #include <QTranslator>
#include <QPalette>
#include <QStyle>
#define QT6CT_LIBRARY
#include <qt6ct-common/qt6ct.h>
#undef QT6CT_LIBRARY
static const std::string logPrefix_ = "scwx::main"; static const std::string logPrefix_ = "scwx::main";
static const auto logger_ = scwx::util::Logger::Create(logPrefix_); static const auto logger_ = scwx::util::Logger::Create(logPrefix_);
static void ConfigureTheme(const std::vector<std::string>& args);
static void InitializeOpenGL();
static void OverrideDefaultStyle(const std::vector<std::string>& args); static void OverrideDefaultStyle(const std::vector<std::string>& args);
int main(int argc, char* argv[]) int main(int argc, char* argv[])
@ -54,28 +41,19 @@ int main(int argc, char* argv[])
args.push_back(argv[i]); args.push_back(argv[i]);
} }
if (!scwx::util::GetEnvironment("SCWX_TEST").empty())
{
QStandardPaths::setTestModeEnabled(true);
}
// Initialize logger // Initialize logger
auto& logManager = scwx::qt::manager::LogManager::Instance(); auto& logManager = scwx::qt::manager::LogManager::Instance();
logManager.Initialize(); logManager.Initialize();
QCoreApplication::setApplicationName("Supercell Wx"); logger_->info("Supercell Wx v{} ({})",
logManager.InitializeLogFile();
logger_->info("Supercell Wx v{}.{} ({})",
scwx::qt::main::kVersionString_, scwx::qt::main::kVersionString_,
scwx::qt::main::kBuildNumber_,
scwx::qt::main::kCommitString_); scwx::qt::main::kCommitString_);
InitializeOpenGL(); QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts, true);
QApplication a(argc, argv); QApplication a(argc, argv);
QCoreApplication::setApplicationName("Supercell Wx");
scwx::network::cpr::SetUserAgent( scwx::network::cpr::SetUserAgent(
fmt::format("SupercellWx/{}", scwx::qt::main::kVersionString_)); fmt::format("SupercellWx/{}", scwx::qt::main::kVersionString_));
@ -86,11 +64,9 @@ int main(int argc, char* argv[])
QCoreApplication::installTranslator(&translator); QCoreApplication::installTranslator(&translator);
} }
// Test to see if scwx was run with high privilege if (!scwx::util::GetEnvironment("SCWX_TEST").empty())
scwx::qt::main::PrivilegeChecker privilegeChecker;
if (privilegeChecker.pre_settings_check())
{ {
return 0; QStandardPaths::setTestModeEnabled(true);
} }
// Start the io_context main loop // Start the io_context main loop
@ -120,54 +96,40 @@ int main(int argc, char* argv[])
Aws::InitAPI(awsSdkOptions); Aws::InitAPI(awsSdkOptions);
// Initialize application // Initialize application
logManager.InitializeLogFile();
scwx::qt::config::RadarSite::Initialize(); scwx::qt::config::RadarSite::Initialize();
scwx::qt::config::CountyDatabase::Initialize(); scwx::qt::config::CountyDatabase::Initialize();
scwx::qt::manager::TaskManager::Initialize();
scwx::qt::manager::SettingsManager::Instance().Initialize(); scwx::qt::manager::SettingsManager::Instance().Initialize();
scwx::qt::manager::ResourceManager::Initialize(); scwx::qt::manager::ResourceManager::Initialize();
// Theme // Theme
ConfigureTheme(args); auto uiStyle = scwx::qt::types::GetUiStyle(
scwx::qt::settings::GeneralSettings::Instance().theme().GetValue());
// Check process modules for compatibility if (uiStyle == scwx::qt::types::UiStyle::Default)
scwx::qt::main::CheckProcessModules();
int result = 0;
if (privilegeChecker.post_settings_check())
{ {
result = 1; OverrideDefaultStyle(args);
} }
else else
{ {
// Run initial setup if required QApplication::setStyle(
if (scwx::qt::ui::setup::SetupWizard::IsSetupRequired()) QString::fromStdString(scwx::qt::types::GetUiStyleName(uiStyle)));
{ }
scwx::qt::ui::setup::SetupWizard w;
w.show();
a.exec();
}
// Run Qt main loop // Run initial setup if required
{ if (scwx::qt::ui::setup::SetupWizard::IsSetupRequired())
scwx::qt::main::MainWindow w; {
scwx::qt::ui::setup::SetupWizard w;
w.show();
a.exec();
}
bool initialized = false; // Run Qt main loop
int result;
try {
{ scwx::qt::main::MainWindow w;
w.show(); w.show();
initialized = true; result = a.exec();
}
catch (const std::exception& ex)
{
logger_->critical(ex.what());
}
if (initialized)
{
result = a.exec();
}
}
} }
// Deinitialize application // Deinitialize application
@ -183,7 +145,6 @@ int main(int argc, char* argv[])
// Shutdown application // Shutdown application
scwx::qt::manager::ResourceManager::Shutdown(); scwx::qt::manager::ResourceManager::Shutdown();
scwx::qt::manager::SettingsManager::Instance().Shutdown(); scwx::qt::manager::SettingsManager::Instance().Shutdown();
scwx::qt::manager::TaskManager::Shutdown();
// Shutdown AWS SDK // Shutdown AWS SDK
Aws::ShutdownAPI(awsSdkOptions); Aws::ShutdownAPI(awsSdkOptions);
@ -191,73 +152,6 @@ int main(int argc, char* argv[])
return result; return result;
} }
static void ConfigureTheme(const std::vector<std::string>& args)
{
auto& generalSettings = scwx::qt::settings::GeneralSettings::Instance();
auto uiStyle =
scwx::qt::types::GetUiStyle(generalSettings.theme().GetValue());
auto qtColorScheme = scwx::qt::types::GetQtColorScheme(uiStyle);
if (uiStyle == scwx::qt::types::UiStyle::Default)
{
OverrideDefaultStyle(args);
}
else
{
QApplication::setStyle(
QString::fromStdString(scwx::qt::types::GetQtStyleName(uiStyle)));
}
QGuiApplication::styleHints()->setColorScheme(qtColorScheme);
std::optional<std::string> paletteFile;
if (uiStyle == scwx::qt::types::UiStyle::FusionCustom)
{
paletteFile = generalSettings.theme_file().GetValue();
}
else
{
paletteFile = scwx::qt::types::GetQtPaletteFile(uiStyle);
}
if (paletteFile)
{
QPalette defaultPalette = QApplication::style()->standardPalette();
QPalette palette = Qt6CT::loadColorScheme(
QString::fromStdString(*paletteFile), defaultPalette);
if (defaultPalette == palette)
{
logger_->warn("Failed to load palette file '{}'", *paletteFile);
}
else
{
logger_->info("Loaded palette file '{}'", *paletteFile);
}
QApplication::setPalette(palette);
}
}
static void InitializeOpenGL()
{
QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts, true);
QSurfaceFormat surfaceFormat = QSurfaceFormat::defaultFormat();
surfaceFormat.setProfile(QSurfaceFormat::OpenGLContextProfile::CoreProfile);
surfaceFormat.setRenderableType(QSurfaceFormat::RenderableType::OpenGL);
#if defined(__APPLE__)
// For macOS, we must choose between OpenGL 4.1 Core and OpenGL 2.1
// Compatibility. OpenGL 2.1 does not meet requirements for shaders used by
// Supercell Wx.
surfaceFormat.setVersion(4, 1);
#endif
QSurfaceFormat::setDefaultFormat(surfaceFormat);
}
static void static void
OverrideDefaultStyle([[maybe_unused]] const std::vector<std::string>& args) OverrideDefaultStyle([[maybe_unused]] const std::vector<std::string>& args)
{ {

View file

@ -1,13 +1,11 @@
#include "main_window.hpp" #include "main_window.hpp"
#include "./ui_main_window.h" #include "./ui_main_window.h"
#include <scwx/qt/gl/gl_context.hpp>
#include <scwx/qt/main/application.hpp> #include <scwx/qt/main/application.hpp>
#include <scwx/qt/main/versions.hpp> #include <scwx/qt/main/versions.hpp>
#include <scwx/qt/manager/alert_manager.hpp> #include <scwx/qt/manager/alert_manager.hpp>
#include <scwx/qt/manager/hotkey_manager.hpp> #include <scwx/qt/manager/hotkey_manager.hpp>
#include <scwx/qt/manager/placefile_manager.hpp> #include <scwx/qt/manager/placefile_manager.hpp>
#include <scwx/qt/manager/marker_manager.hpp>
#include <scwx/qt/manager/position_manager.hpp> #include <scwx/qt/manager/position_manager.hpp>
#include <scwx/qt/manager/radar_product_manager.hpp> #include <scwx/qt/manager/radar_product_manager.hpp>
#include <scwx/qt/manager/text_event_manager.hpp> #include <scwx/qt/manager/text_event_manager.hpp>
@ -32,7 +30,6 @@
#include <scwx/qt/ui/level2_settings_widget.hpp> #include <scwx/qt/ui/level2_settings_widget.hpp>
#include <scwx/qt/ui/level3_products_widget.hpp> #include <scwx/qt/ui/level3_products_widget.hpp>
#include <scwx/qt/ui/placefile_dialog.hpp> #include <scwx/qt/ui/placefile_dialog.hpp>
#include <scwx/qt/ui/marker_dialog.hpp>
#include <scwx/qt/ui/radar_site_dialog.hpp> #include <scwx/qt/ui/radar_site_dialog.hpp>
#include <scwx/qt/ui/settings_dialog.hpp> #include <scwx/qt/ui/settings_dialog.hpp>
#include <scwx/qt/ui/update_dialog.hpp> #include <scwx/qt/ui/update_dialog.hpp>
@ -55,6 +52,10 @@
#include <QTimer> #include <QTimer>
#include <QToolButton> #include <QToolButton>
#if !defined(_MSC_VER)
# include <date/date.h>
#endif
namespace scwx namespace scwx
{ {
namespace qt namespace qt
@ -89,13 +90,11 @@ public:
imGuiDebugDialog_ {nullptr}, imGuiDebugDialog_ {nullptr},
layerDialog_ {nullptr}, layerDialog_ {nullptr},
placefileDialog_ {nullptr}, placefileDialog_ {nullptr},
markerDialog_ {nullptr},
radarSiteDialog_ {nullptr}, radarSiteDialog_ {nullptr},
settingsDialog_ {nullptr}, settingsDialog_ {nullptr},
updateDialog_ {nullptr}, updateDialog_ {nullptr},
alertManager_ {manager::AlertManager::Instance()}, alertManager_ {manager::AlertManager::Instance()},
placefileManager_ {manager::PlacefileManager::Instance()}, placefileManager_ {manager::PlacefileManager::Instance()},
markerManager_ {manager::MarkerManager::Instance()},
positionManager_ {manager::PositionManager::Instance()}, positionManager_ {manager::PositionManager::Instance()},
textEventManager_ {manager::TextEventManager::Instance()}, textEventManager_ {manager::TextEventManager::Instance()},
timelineManager_ {manager::TimelineManager::Instance()}, timelineManager_ {manager::TimelineManager::Instance()},
@ -140,9 +139,6 @@ public:
} }
~MainWindowImpl() ~MainWindowImpl()
{ {
homeRadarConnection_.disconnect();
defaultTimeZoneConnection_.disconnect();
auto& generalSettings = settings::GeneralSettings::Instance(); auto& generalSettings = settings::GeneralSettings::Instance();
auto& customStyleUrl = generalSettings.custom_style_url(); auto& customStyleUrl = generalSettings.custom_style_url();
@ -191,8 +187,6 @@ public:
map::MapProvider mapProvider_; map::MapProvider mapProvider_;
map::MapWidget* activeMap_; map::MapWidget* activeMap_;
std::shared_ptr<gl::GlContext> glContext_ {nullptr};
ui::CollapsibleGroup* mapSettingsGroup_; ui::CollapsibleGroup* mapSettingsGroup_;
ui::CollapsibleGroup* level2ProductsGroup_; ui::CollapsibleGroup* level2ProductsGroup_;
ui::CollapsibleGroup* level2SettingsGroup_; ui::CollapsibleGroup* level2SettingsGroup_;
@ -213,7 +207,6 @@ public:
ui::ImGuiDebugDialog* imGuiDebugDialog_; ui::ImGuiDebugDialog* imGuiDebugDialog_;
ui::LayerDialog* layerDialog_; ui::LayerDialog* layerDialog_;
ui::PlacefileDialog* placefileDialog_; ui::PlacefileDialog* placefileDialog_;
ui::MarkerDialog* markerDialog_;
ui::RadarSiteDialog* radarSiteDialog_; ui::RadarSiteDialog* radarSiteDialog_;
ui::SettingsDialog* settingsDialog_; ui::SettingsDialog* settingsDialog_;
ui::UpdateDialog* updateDialog_; ui::UpdateDialog* updateDialog_;
@ -228,7 +221,6 @@ public:
std::shared_ptr<manager::HotkeyManager> hotkeyManager_ { std::shared_ptr<manager::HotkeyManager> hotkeyManager_ {
manager::HotkeyManager::Instance()}; manager::HotkeyManager::Instance()};
std::shared_ptr<manager::PlacefileManager> placefileManager_; std::shared_ptr<manager::PlacefileManager> placefileManager_;
std::shared_ptr<manager::MarkerManager> markerManager_;
std::shared_ptr<manager::PositionManager> positionManager_; std::shared_ptr<manager::PositionManager> positionManager_;
std::shared_ptr<manager::TextEventManager> textEventManager_; std::shared_ptr<manager::TextEventManager> textEventManager_;
std::shared_ptr<manager::TimelineManager> timelineManager_; std::shared_ptr<manager::TimelineManager> timelineManager_;
@ -245,12 +237,9 @@ public:
layerActions_ {}; layerActions_ {};
bool layerActionsInitialized_ {false}; bool layerActionsInitialized_ {false};
boost::signals2::scoped_connection homeRadarConnection_ {};
boost::signals2::scoped_connection defaultTimeZoneConnection_ {};
std::vector<map::MapWidget*> maps_; std::vector<map::MapWidget*> maps_;
std::chrono::system_clock::time_point selectedTime_ {}; std::chrono::system_clock::time_point volumeTime_ {};
public slots: public slots:
void UpdateMapParameters(double latitude, void UpdateMapParameters(double latitude,
@ -276,7 +265,6 @@ MainWindow::MainWindow(QWidget* parent) :
ui->vcpLabel->setVisible(false); ui->vcpLabel->setVisible(false);
ui->vcpValueLabel->setVisible(false); ui->vcpValueLabel->setVisible(false);
ui->vcpDescriptionLabel->setVisible(false); ui->vcpDescriptionLabel->setVisible(false);
ui->saveRadarProductsButton->setVisible(true);
p->radarSitePresetsMenu_ = new QMenu(this); p->radarSitePresetsMenu_ = new QMenu(this);
ui->radarSitePresetsButton->setMenu(p->radarSitePresetsMenu_); ui->radarSitePresetsButton->setMenu(p->radarSitePresetsMenu_);
@ -291,6 +279,7 @@ MainWindow::MainWindow(QWidget* parent) :
// Configure Alert Dock // Configure Alert Dock
p->alertDockWidget_ = new ui::AlertDockWidget(this); p->alertDockWidget_ = new ui::AlertDockWidget(this);
p->alertDockWidget_->setVisible(false);
addDockWidget(Qt::BottomDockWidgetArea, p->alertDockWidget_); addDockWidget(Qt::BottomDockWidgetArea, p->alertDockWidget_);
// GPS Info Dialog // GPS Info Dialog
@ -319,25 +308,18 @@ MainWindow::MainWindow(QWidget* parent) :
// Placefile Manager Dialog // Placefile Manager Dialog
p->placefileDialog_ = new ui::PlacefileDialog(this); p->placefileDialog_ = new ui::PlacefileDialog(this);
// Marker Manager Dialog
p->markerDialog_ = new ui::MarkerDialog(this);
// Layer Dialog // Layer Dialog
p->layerDialog_ = new ui::LayerDialog(this); p->layerDialog_ = new ui::LayerDialog(this);
// Settings Dialog // Settings Dialog
p->settingsDialog_ = new ui::SettingsDialog(p->settings_, this); p->settingsDialog_ = new ui::SettingsDialog(this);
// Map Settings // Map Settings
p->mapSettingsGroup_ = new ui::CollapsibleGroup(tr("Map Settings"), this); p->mapSettingsGroup_ = new ui::CollapsibleGroup(tr("Map Settings"), this);
p->mapSettingsGroup_->GetContentsLayout()->addWidget(ui->mapStyleLabel); p->mapSettingsGroup_->GetContentsLayout()->addWidget(ui->mapStyleLabel);
p->mapSettingsGroup_->GetContentsLayout()->addWidget(ui->mapStyleComboBox); p->mapSettingsGroup_->GetContentsLayout()->addWidget(ui->mapStyleComboBox);
p->mapSettingsGroup_->GetContentsLayout()->addWidget(
ui->smoothRadarDataCheckBox);
p->mapSettingsGroup_->GetContentsLayout()->addWidget( p->mapSettingsGroup_->GetContentsLayout()->addWidget(
ui->trackLocationCheckBox); ui->trackLocationCheckBox);
p->mapSettingsGroup_->GetContentsLayout()->addWidget(
ui->saveRadarProductsButton);
ui->radarToolboxScrollAreaContents->layout()->replaceWidget( ui->radarToolboxScrollAreaContents->layout()->replaceWidget(
ui->mapSettingsGroupBox, p->mapSettingsGroup_); ui->mapSettingsGroupBox, p->mapSettingsGroup_);
ui->mapSettingsGroupBox->setVisible(false); ui->mapSettingsGroupBox->setVisible(false);
@ -379,7 +361,6 @@ MainWindow::MainWindow(QWidget* parent) :
p->animationDockWidget_ = new ui::AnimationDockWidget(this); p->animationDockWidget_ = new ui::AnimationDockWidget(this);
p->timelineGroup_->GetContentsLayout()->addWidget(p->animationDockWidget_); p->timelineGroup_->GetContentsLayout()->addWidget(p->animationDockWidget_);
ui->radarToolboxScrollAreaContents->layout()->addWidget(p->timelineGroup_); ui->radarToolboxScrollAreaContents->layout()->addWidget(p->timelineGroup_);
p->animationDockWidget_->UpdateTimeZone(p->activeMap_->GetDefaultTimeZone());
// Reset toolbox spacer at the bottom // Reset toolbox spacer at the bottom
ui->radarToolboxScrollAreaContents->layout()->removeItem( ui->radarToolboxScrollAreaContents->layout()->removeItem(
@ -463,37 +444,8 @@ void MainWindow::keyReleaseEvent(QKeyEvent* ev)
void MainWindow::showEvent(QShowEvent* event) void MainWindow::showEvent(QShowEvent* event)
{ {
QMainWindow::showEvent(event); QMainWindow::showEvent(event);
auto& uiSettings = settings::UiSettings::Instance();
// restore the geometry state resizeDocks({ui->radarToolboxDock}, {194}, Qt::Horizontal);
std::string uiGeometry = uiSettings.main_ui_geometry().GetValue();
restoreGeometry(
QByteArray::fromBase64(QByteArray::fromStdString(uiGeometry)));
// restore the UI state
std::string uiState = uiSettings.main_ui_state().GetValue();
bool restored =
restoreState(QByteArray::fromBase64(QByteArray::fromStdString(uiState)));
if (!restored)
{
resizeDocks({ui->radarToolboxDock}, {194}, Qt::Horizontal);
}
}
void MainWindow::closeEvent(QCloseEvent* event)
{
auto& uiSettings = settings::UiSettings::Instance();
// save the UI geometry
QByteArray uiGeometry = saveGeometry().toBase64();
uiSettings.main_ui_geometry().StageValue(uiGeometry.data());
// save the UI state
QByteArray uiState = saveState().toBase64();
uiSettings.main_ui_state().StageValue(uiState.data());
QMainWindow::closeEvent(event);
} }
void MainWindow::on_actionOpenNexrad_triggered() void MainWindow::on_actionOpenNexrad_triggered()
@ -509,11 +461,12 @@ void MainWindow::on_actionOpenNexrad_triggered()
map::MapWidget* currentMap = p->activeMap_; map::MapWidget* currentMap = p->activeMap_;
// Make sure the parent window properly repaints on close // Make sure the parent window properly repaints on close
connect(dialog, connect(
&QFileDialog::finished, dialog,
this, &QFileDialog::finished,
static_cast<void (MainWindow::*)()>(&MainWindow::update), this,
Qt::QueuedConnection); [this]() { update(); },
Qt::QueuedConnection);
connect( connect(
dialog, dialog,
@ -574,11 +527,12 @@ void MainWindow::on_actionOpenTextEvent_triggered()
dialog->setAttribute(Qt::WA_DeleteOnClose); dialog->setAttribute(Qt::WA_DeleteOnClose);
// Make sure the parent window properly repaints on close // Make sure the parent window properly repaints on close
connect(dialog, connect(
&QFileDialog::finished, dialog,
this, &QFileDialog::finished,
static_cast<void (MainWindow::*)()>(&MainWindow::update), this,
Qt::QueuedConnection); [this]() { update(); },
Qt::QueuedConnection);
connect(dialog, connect(dialog,
&QFileDialog::fileSelected, &QFileDialog::fileSelected,
@ -632,11 +586,6 @@ void MainWindow::on_actionPlacefileManager_triggered()
p->placefileDialog_->show(); p->placefileDialog_->show();
} }
void MainWindow::on_actionMarkerManager_triggered()
{
p->markerDialog_->show();
}
void MainWindow::on_actionLayerManager_triggered() void MainWindow::on_actionLayerManager_triggered()
{ {
p->layerDialog_->show(); p->layerDialog_->show();
@ -657,11 +606,6 @@ void MainWindow::on_actionDumpRadarProductRecords_triggered()
manager::RadarProductManager::DumpRecords(); manager::RadarProductManager::DumpRecords();
} }
void MainWindow::on_actionRadarWireframe_triggered(bool checked)
{
p->activeMap_->SetRadarWireframeEnabled(checked);
}
void MainWindow::on_actionUserManual_triggered() void MainWindow::on_actionUserManual_triggered()
{ {
QDesktopServices::openUrl(QUrl {"https://supercell-wx.readthedocs.io/"}); QDesktopServices::openUrl(QUrl {"https://supercell-wx.readthedocs.io/"});
@ -782,8 +726,6 @@ void MainWindowImpl::ConfigureMapLayout()
} }
}; };
glContext_ = std::make_shared<gl::GlContext>();
for (int64_t y = 0; y < gridHeight; y++) for (int64_t y = 0; y < gridHeight; y++)
{ {
QSplitter* hs = new QSplitter(vs); QSplitter* hs = new QSplitter(vs);
@ -793,9 +735,7 @@ void MainWindowImpl::ConfigureMapLayout()
{ {
if (maps_.at(mapIndex) == nullptr) if (maps_.at(mapIndex) == nullptr)
{ {
// NOLINTNEXTLINE(cppcoreguidelines-owning-memory): Owned by parent maps_[mapIndex] = new map::MapWidget(mapIndex, settings_);
maps_[mapIndex] =
new map::MapWidget(mapIndex, settings_, glContext_);
} }
hs->addWidget(maps_[mapIndex]); hs->addWidget(maps_[mapIndex]);
@ -828,9 +768,9 @@ void MainWindowImpl::ConfigureMapStyles()
if ((customStyleAvailable_ && styleName == "Custom") || if ((customStyleAvailable_ && styleName == "Custom") ||
std::find_if(mapProviderInfo.mapStyles_.cbegin(), std::find_if(mapProviderInfo.mapStyles_.cbegin(),
mapProviderInfo.mapStyles_.cend(), mapProviderInfo.mapStyles_.cend(),
[&](const auto& mapStyle) [&](const auto& mapStyle) {
{ return mapStyle.name_ == styleName; }) != return mapStyle.name_ == styleName;
mapProviderInfo.mapStyles_.cend()) }) != mapProviderInfo.mapStyles_.cend())
{ {
// Initialize map style from settings // Initialize map style from settings
maps_.at(i)->SetInitialMapStyle(styleName); maps_.at(i)->SetInitialMapStyle(styleName);
@ -973,28 +913,11 @@ void MainWindowImpl::ConnectMapSignals()
} }
}, },
Qt::QueuedConnection); Qt::QueuedConnection);
connect(
mapWidget,
&map::MapWidget::IncomingLevel2ElevationChanged,
this,
[this](std::optional<float>)
{ level2SettingsWidget_->UpdateSettings(activeMap_); },
Qt::QueuedConnection);
} }
} }
void MainWindowImpl::ConnectAnimationSignals() void MainWindowImpl::ConnectAnimationSignals()
{ {
defaultTimeZoneConnection_ = settings::GeneralSettings::Instance()
.default_time_zone()
.changed_signal()
.connect(
[this]()
{
animationDockWidget_->UpdateTimeZone(
activeMap_->GetDefaultTimeZone());
});
connect(animationDockWidget_, connect(animationDockWidget_,
&ui::AnimationDockWidget::DateTimeChanged, &ui::AnimationDockWidget::DateTimeChanged,
timelineManager_.get(), timelineManager_.get(),
@ -1038,16 +961,21 @@ void MainWindowImpl::ConnectAnimationSignals()
connect(timelineManager_.get(), connect(timelineManager_.get(),
&manager::TimelineManager::SelectedTimeUpdated, &manager::TimelineManager::SelectedTimeUpdated,
[this]()
{
for (auto map : maps_)
{
map->update();
}
});
connect(timelineManager_.get(),
&manager::TimelineManager::VolumeTimeUpdated,
[this](std::chrono::system_clock::time_point dateTime) [this](std::chrono::system_clock::time_point dateTime)
{ {
selectedTime_ = dateTime; volumeTime_ = dateTime;
for (auto map : maps_) for (auto map : maps_)
{ {
map->SelectTime(dateTime); map->SelectTime(dateTime);
textEventManager_->SelectTime(dateTime);
QMetaObject::invokeMethod(
map, static_cast<void (QWidget::*)()>(&QWidget::update));
} }
}); });
@ -1127,29 +1055,10 @@ void MainWindowImpl::ConnectOtherSignals()
} }
} }
}); });
connect(
mainWindow_->ui->smoothRadarDataCheckBox,
&QCheckBox::checkStateChanged,
mainWindow_,
[this](Qt::CheckState state)
{
const bool smoothingEnabled = (state == Qt::CheckState::Checked);
auto it = std::find(maps_.cbegin(), maps_.cend(), activeMap_);
if (it != maps_.cend())
{
const std::size_t i = std::distance(maps_.cbegin(), it);
settings::MapSettings::Instance().smoothing_enabled(i).StageValue(
smoothingEnabled);
}
// Turn on smoothing
activeMap_->SetSmoothingEnabled(smoothingEnabled);
});
connect(mainWindow_->ui->trackLocationCheckBox, connect(mainWindow_->ui->trackLocationCheckBox,
&QCheckBox::checkStateChanged, &QCheckBox::stateChanged,
mainWindow_, mainWindow_,
[this](Qt::CheckState state) [this](int state)
{ {
bool trackingEnabled = (state == Qt::CheckState::Checked); bool trackingEnabled = (state == Qt::CheckState::Checked);
@ -1159,37 +1068,22 @@ void MainWindowImpl::ConnectOtherSignals()
// Turn on location tracking // Turn on location tracking
positionManager_->TrackLocation(trackingEnabled); positionManager_->TrackLocation(trackingEnabled);
}); });
connect( connect(level2ProductsWidget_,
mainWindow_->ui->saveRadarProductsButton, &ui::Level2ProductsWidget::RadarProductSelected,
&QAbstractButton::clicked, mainWindow_,
mainWindow_, [&](common::RadarProductGroup group,
[this]() const std::string& productName,
{ int16_t productCode) {
auto& mapSettings = settings::MapSettings::Instance(); SelectRadarProduct(activeMap_, group, productName, productCode);
for (std::size_t i = 0; i < maps_.size(); i++) });
{ connect(level3ProductsWidget_,
const auto& map = maps_.at(i); &ui::Level3ProductsWidget::RadarProductSelected,
mapSettings.radar_product_group(i).StageValue( mainWindow_,
common::GetRadarProductGroupName(map->GetRadarProductGroup())); [&](common::RadarProductGroup group,
mapSettings.radar_product(i).StageValue(map->GetRadarProductName()); const std::string& productName,
} int16_t productCode) {
}); SelectRadarProduct(activeMap_, group, productName, productCode);
connect( });
level2ProductsWidget_,
&ui::Level2ProductsWidget::RadarProductSelected,
mainWindow_,
[&](common::RadarProductGroup group,
const std::string& productName,
int16_t productCode)
{ SelectRadarProduct(activeMap_, group, productName, productCode); });
connect(
level3ProductsWidget_,
&ui::Level3ProductsWidget::RadarProductSelected,
mainWindow_,
[&](common::RadarProductGroup group,
const std::string& productName,
int16_t productCode)
{ SelectRadarProduct(activeMap_, group, productName, productCode); });
connect(level2SettingsWidget_, connect(level2SettingsWidget_,
&ui::Level2SettingsWidget::ElevationSelected, &ui::Level2SettingsWidget::ElevationSelected,
mainWindow_, mainWindow_,
@ -1300,33 +1194,11 @@ void MainWindowImpl::ConnectOtherSignals()
this, this,
[this]() [this]()
{ {
timeLabel_->setText( timeLabel_->setText(QString::fromStdString(
QString::fromStdString(util::TimeString(util::time::now()))); util::TimeString(std::chrono::system_clock::now())));
timeLabel_->setVisible(true); timeLabel_->setVisible(true);
}); });
clockTimer_.start(1000); clockTimer_.start(1000);
auto& generalSettings = settings::GeneralSettings::Instance();
homeRadarConnection_ =
generalSettings.default_radar_site().changed_signal().connect(
[this]()
{
const std::shared_ptr<config::RadarSite> radarSite =
activeMap_->GetRadarSite();
const std::string homeRadarSite =
settings::GeneralSettings::Instance()
.default_radar_site()
.GetValue();
if (radarSite == nullptr)
{
mainWindow_->ui->saveRadarProductsButton->setVisible(false);
}
else
{
mainWindow_->ui->saveRadarProductsButton->setVisible(
radarSite->id() == homeRadarSite);
}
});
} }
void MainWindowImpl::InitializeLayerDisplayActions() void MainWindowImpl::InitializeLayerDisplayActions()
@ -1491,8 +1363,7 @@ void MainWindowImpl::SelectRadarProduct(map::MapWidget* mapWidget,
UpdateRadarProductSettings(); UpdateRadarProductSettings();
} }
mapWidget->SelectRadarProduct( mapWidget->SelectRadarProduct(group, productName, productCode, volumeTime_);
group, productName, productCode, selectedTime_);
} }
void MainWindowImpl::SetActiveMap(map::MapWidget* mapWidget) void MainWindowImpl::SetActiveMap(map::MapWidget* mapWidget)
@ -1562,28 +1433,18 @@ void MainWindowImpl::UpdateRadarProductSettings()
{ {
if (activeMap_->GetRadarProductGroup() == common::RadarProductGroup::Level2) if (activeMap_->GetRadarProductGroup() == common::RadarProductGroup::Level2)
{ {
level2SettingsGroup_->setVisible(true);
// This should be done after setting visible for correct sizing
level2SettingsWidget_->UpdateSettings(activeMap_); level2SettingsWidget_->UpdateSettings(activeMap_);
level2SettingsGroup_->setVisible(true);
} }
else else
{ {
level2SettingsGroup_->setVisible(false); level2SettingsGroup_->setVisible(false);
} }
mainWindow_->ui->smoothRadarDataCheckBox->setCheckState(
activeMap_->GetSmoothingEnabled() ? Qt::CheckState::Checked :
Qt::CheckState::Unchecked);
mainWindow_->ui->actionRadarWireframe->setChecked(
activeMap_->GetRadarWireframeEnabled());
} }
void MainWindowImpl::UpdateRadarSite() void MainWindowImpl::UpdateRadarSite()
{ {
std::shared_ptr<config::RadarSite> radarSite = activeMap_->GetRadarSite(); std::shared_ptr<config::RadarSite> radarSite = activeMap_->GetRadarSite();
const std::string homeRadarSite =
settings::GeneralSettings::Instance().default_radar_site().GetValue();
if (radarSite != nullptr) if (radarSite != nullptr)
{ {
@ -1598,9 +1459,6 @@ void MainWindowImpl::UpdateRadarSite()
radarSite->location_name().c_str()); radarSite->location_name().c_str());
timelineManager_->SetRadarSite(radarSite->id()); timelineManager_->SetRadarSite(radarSite->id());
mainWindow_->ui->saveRadarProductsButton->setVisible(radarSite->id() ==
homeRadarSite);
} }
else else
{ {
@ -1608,15 +1466,12 @@ void MainWindowImpl::UpdateRadarSite()
mainWindow_->ui->radarSiteValueLabel->setVisible(false); mainWindow_->ui->radarSiteValueLabel->setVisible(false);
mainWindow_->ui->radarLocationLabel->setVisible(false); mainWindow_->ui->radarLocationLabel->setVisible(false);
mainWindow_->ui->saveRadarProductsButton->setVisible(false);
timelineManager_->SetRadarSite("?"); timelineManager_->SetRadarSite("?");
} }
alertManager_->SetRadarSite(radarSite); alertManager_->SetRadarSite(radarSite);
placefileManager_->SetRadarSite(radarSite); placefileManager_->SetRadarSite(radarSite);
animationDockWidget_->UpdateTimeZone(activeMap_->GetDefaultTimeZone());
} }
void MainWindowImpl::UpdateVcp() void MainWindowImpl::UpdateVcp()

View file

@ -29,7 +29,6 @@ public:
void keyPressEvent(QKeyEvent* ev) override final; void keyPressEvent(QKeyEvent* ev) override final;
void keyReleaseEvent(QKeyEvent* ev) override final; void keyReleaseEvent(QKeyEvent* ev) override final;
void showEvent(QShowEvent* event) override; void showEvent(QShowEvent* event) override;
void closeEvent(QCloseEvent* event) override;
signals: signals:
void ActiveMapMoved(double latitude, double longitude); void ActiveMapMoved(double latitude, double longitude);
@ -44,12 +43,10 @@ private slots:
void on_actionRadarRange_triggered(bool checked); void on_actionRadarRange_triggered(bool checked);
void on_actionRadarSites_triggered(bool checked); void on_actionRadarSites_triggered(bool checked);
void on_actionPlacefileManager_triggered(); void on_actionPlacefileManager_triggered();
void on_actionMarkerManager_triggered();
void on_actionLayerManager_triggered(); void on_actionLayerManager_triggered();
void on_actionImGuiDebug_triggered(); void on_actionImGuiDebug_triggered();
void on_actionDumpLayerList_triggered(); void on_actionDumpLayerList_triggered();
void on_actionDumpRadarProductRecords_triggered(); void on_actionDumpRadarProductRecords_triggered();
void on_actionRadarWireframe_triggered(bool checked);
void on_actionUserManual_triggered(); void on_actionUserManual_triggered();
void on_actionDiscord_triggered(); void on_actionDiscord_triggered();
void on_actionGitHubRepository_triggered(); void on_actionGitHubRepository_triggered();

View file

@ -39,7 +39,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>1024</width> <width>1024</width>
<height>21</height> <height>33</height>
</rect> </rect>
</property> </property>
<widget class="QMenu" name="menuFile"> <widget class="QMenu" name="menuFile">
@ -97,8 +97,6 @@
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="actionDumpLayerList"/> <addaction name="actionDumpLayerList"/>
<addaction name="actionDumpRadarProductRecords"/> <addaction name="actionDumpRadarProductRecords"/>
<addaction name="separator"/>
<addaction name="actionRadarWireframe"/>
</widget> </widget>
<widget class="QMenu" name="menuTools"> <widget class="QMenu" name="menuTools">
<property name="title"> <property name="title">
@ -106,7 +104,6 @@
</property> </property>
<addaction name="actionPlacefileManager"/> <addaction name="actionPlacefileManager"/>
<addaction name="actionLayerManager"/> <addaction name="actionLayerManager"/>
<addaction name="actionMarkerManager"/>
</widget> </widget>
<addaction name="menuFile"/> <addaction name="menuFile"/>
<addaction name="menuView"/> <addaction name="menuView"/>
@ -155,8 +152,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>191</width> <width>190</width>
<height>703</height> <height>686</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_6"> <layout class="QVBoxLayout" name="verticalLayout_6">
@ -174,25 +171,39 @@
</property> </property>
<item> <item>
<widget class="QFrame" name="radarInfoFrame"> <widget class="QFrame" name="radarInfoFrame">
<property name="frameShape">
<enum>QFrame::Shape::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Shadow::Raised</enum>
</property>
<layout class="QGridLayout" name="gridLayout" columnstretch="0,0,0,0,0"> <layout class="QGridLayout" name="gridLayout" columnstretch="0,0,0,0,0">
<item row="3" column="2" colspan="3"> <item row="0" column="2">
<widget class="QLabel" name="vcpValueLabel"> <widget class="QLabel" name="radarSiteValueLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text"> <property name="text">
<string notr="true">35</string> <string notr="true">KLSX</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="2" colspan="3"> <item row="3" column="0" colspan="2">
<widget class="QLabel" name="vcpDescriptionLabel"> <widget class="QLabel" name="vcpLabel">
<property name="text"> <property name="sizePolicy">
<string>Clear Air Mode</string> <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Volume Coverage Pattern</string>
</property> </property>
</widget>
</item>
<item row="1" column="2" colspan="3">
<widget class="QLabel" name="radarLocationLabel">
<property name="text"> <property name="text">
<string notr="true">St. Louis, MO</string> <string>VCP</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -257,6 +268,34 @@
</layout> </layout>
</widget> </widget>
</item> </item>
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="radarSiteLabel">
<property name="text">
<string>Radar Site</string>
</property>
</widget>
</item>
<item row="1" column="2" colspan="3">
<widget class="QLabel" name="radarLocationLabel">
<property name="text">
<string notr="true">St. Louis, MO</string>
</property>
</widget>
</item>
<item row="3" column="2" colspan="3">
<widget class="QLabel" name="vcpValueLabel">
<property name="text">
<string notr="true">35</string>
</property>
</widget>
</item>
<item row="4" column="2" colspan="3">
<widget class="QLabel" name="vcpDescriptionLabel">
<property name="text">
<string>Clear Air Mode</string>
</property>
</widget>
</item>
<item row="0" column="3"> <item row="0" column="3">
<widget class="QToolButton" name="radarSiteSelectButton"> <widget class="QToolButton" name="radarSiteSelectButton">
<property name="maximumSize"> <property name="maximumSize">
@ -270,42 +309,6 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="0" colspan="2">
<widget class="QLabel" name="vcpLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Volume Coverage Pattern</string>
</property>
<property name="text">
<string>VCP</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="radarSiteLabel">
<property name="text">
<string>Radar Site</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="radarSiteValueLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string notr="true">KLSX</string>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>
@ -325,13 +328,6 @@
<item> <item>
<widget class="QComboBox" name="mapStyleComboBox"/> <widget class="QComboBox" name="mapStyleComboBox"/>
</item> </item>
<item>
<widget class="QCheckBox" name="smoothRadarDataCheckBox">
<property name="text">
<string>Smooth Radar Data</string>
</property>
</widget>
</item>
<item> <item>
<widget class="QCheckBox" name="trackLocationCheckBox"> <widget class="QCheckBox" name="trackLocationCheckBox">
<property name="text"> <property name="text">
@ -339,13 +335,6 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QPushButton" name="saveRadarProductsButton">
<property name="text">
<string>Set As Default Products</string>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>
@ -498,23 +487,6 @@
<string>&amp;GPS Info</string> <string>&amp;GPS Info</string>
</property> </property>
</action> </action>
<action name="actionMarkerManager">
<property name="icon">
<iconset resource="../../../../scwx-qt.qrc">
<normaloff>:/res/icons/font-awesome-6/house-solid.svg</normaloff>:/res/icons/font-awesome-6/house-solid.svg</iconset>
</property>
<property name="text">
<string>Location &amp;Marker Manager</string>
</property>
</action>
<action name="actionRadarWireframe">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Radar &amp;Wireframe</string>
</property>
</action>
</widget> </widget>
<resources> <resources>
<include location="../../../../scwx-qt.qrc"/> <include location="../../../../scwx-qt.qrc"/>

View file

@ -1,109 +0,0 @@
#include <scwx/qt/main/process_validation.hpp>
#include <scwx/util/logger.hpp>
#if defined(_WIN32)
# include <scwx/qt/settings/general_settings.hpp>
# include <wtypes.h>
# include <Psapi.h>
# include <boost/algorithm/string/predicate.hpp>
# include <boost/locale.hpp>
# include <fmt/ranges.h>
# include <QCheckBox>
# include <QMessageBox>
#endif
namespace scwx::qt::main
{
static const std::string logPrefix_ = "scwx::qt::main::process_validation";
static const auto logger_ = util::Logger::Create(logPrefix_);
void CheckProcessModules()
{
#if defined(_WIN32)
HANDLE process = GetCurrentProcess();
HMODULE modules[1024];
DWORD cbNeeded = 0;
std::vector<std::string> incompatibleDlls {};
std::vector<std::string> descriptions {};
auto& processModuleWarningsEnabled =
settings::GeneralSettings::Instance().process_module_warnings_enabled();
if (EnumProcessModules(process, modules, sizeof(modules), &cbNeeded))
{
std::uint32_t numModules = cbNeeded / sizeof(HMODULE);
for (std::uint32_t i = 0; i < numModules; ++i)
{
char modulePath[MAX_PATH];
if (GetModuleFileNameExA(process, modules[i], modulePath, MAX_PATH))
{
std::string path = modulePath;
logger_->trace("DLL Found: {}", path);
if (boost::algorithm::iends_with(path, "NahimicOSD.dll"))
{
std::string description =
QObject::tr(
"ASUS Sonic Studio injects a Nahimic driver, which causes "
"Supercell Wx to hang. It is suggested to disable the "
"Nahimic service, or to uninstall ASUS Sonic Studio and "
"the Nahimic driver.")
.toStdString();
logger_->warn("Incompatible DLL found: {}", path);
logger_->warn("{}", description);
// Only populate vectors for the message box if warnings are
// enabled
if (processModuleWarningsEnabled.GetValue())
{
incompatibleDlls.push_back(path);
descriptions.push_back(description);
}
}
}
}
}
if (!incompatibleDlls.empty())
{
const std::string header =
QObject::tr(
"The following DLLs have been injected into the Supercell Wx "
"process:")
.toStdString();
const std::string defaultMessage =
QObject::tr(
"Supercell Wx is known to not run correctly with these DLLs "
"injected. We suggest stopping or uninstalling these services if "
"you experience crashes or unexpected behavior while using "
"Supercell Wx.")
.toStdString();
std::string message = fmt::format("{}\n\n{}\n\n{}\n\n{}",
header,
fmt::join(incompatibleDlls, "\n"),
defaultMessage,
fmt::join(descriptions, "\n"));
QMessageBox dialog(QMessageBox::Icon::Warning,
QObject::tr("Supercell Wx"),
QString::fromStdString(message));
QCheckBox* checkBox =
new QCheckBox(QObject::tr("Don't show this message again"), &dialog);
dialog.setCheckBox(checkBox);
dialog.exec();
// Stage the result of the checkbox. This value will be committed on
// shutdown.
processModuleWarningsEnabled.StageValue(!checkBox->isChecked());
}
#endif
}
} // namespace scwx::qt::main

View file

@ -1,8 +0,0 @@
#pragma once
namespace scwx::qt::main
{
void CheckProcessModules();
} // namespace scwx::qt::main

View file

@ -3,12 +3,17 @@
#include <cstdint> #include <cstdint>
#include <string> #include <string>
namespace scwx::qt::main namespace scwx
{
namespace qt
{
namespace main
{ {
const std::uint32_t kBuildNumber_ {${build_number}u};
const std::string kCommitString_ {"${commit_string}"}; const std::string kCommitString_ {"${commit_string}"};
const std::uint16_t kCopyrightYear_ {${copyright_year}u}; const std::uint16_t kCopyrightYear_ {${copyright_year}u};
const std::string kVersionString_ {"${version_string}"}; const std::string kVersionString_ {"${version_string}"};
} // namespace scwx::qt::main } // namespace main
} // namespace qt
} // namespace scwx

View file

@ -2,13 +2,12 @@
#include <scwx/qt/manager/media_manager.hpp> #include <scwx/qt/manager/media_manager.hpp>
#include <scwx/qt/manager/position_manager.hpp> #include <scwx/qt/manager/position_manager.hpp>
#include <scwx/qt/manager/text_event_manager.hpp> #include <scwx/qt/manager/text_event_manager.hpp>
#include <scwx/qt/config/radar_site.hpp>
#include <scwx/qt/settings/audio_settings.hpp> #include <scwx/qt/settings/audio_settings.hpp>
#include <scwx/qt/settings/general_settings.hpp>
#include <scwx/qt/types/location_types.hpp> #include <scwx/qt/types/location_types.hpp>
#include <scwx/qt/util/geographic_lib.hpp> #include <scwx/qt/util/geographic_lib.hpp>
#include <scwx/util/logger.hpp> #include <scwx/util/logger.hpp>
#include <scwx/util/time.hpp> #include <scwx/qt/config/radar_site.hpp>
#include <scwx/qt/settings/general_settings.hpp>
#include <boost/asio/post.hpp> #include <boost/asio/post.hpp>
#include <boost/asio/thread_pool.hpp> #include <boost/asio/thread_pool.hpp>
@ -139,10 +138,8 @@ common::Coordinate AlertManager::Impl::CurrentCoordinate(
void AlertManager::Impl::HandleAlert(const types::TextEventKey& key, void AlertManager::Impl::HandleAlert(const types::TextEventKey& key,
size_t messageIndex) const size_t messageIndex) const
{ {
auto messages = textEventManager_->message_list(key);
// Skip alert if there are more messages to be processed // Skip alert if there are more messages to be processed
if (messages.empty() || messageIndex + 1 < messages.size()) if (messageIndex + 1 < textEventManager_->message_count(key))
{ {
return; return;
} }
@ -156,7 +153,7 @@ void AlertManager::Impl::HandleAlert(const types::TextEventKey& key,
audioSettings.alert_radius().GetValue()); audioSettings.alert_radius().GetValue());
std::string alertWFO = audioSettings.alert_wfo().GetValue(); std::string alertWFO = audioSettings.alert_wfo().GetValue();
auto message = messages.at(messageIndex); auto message = textEventManager_->message_list(key).at(messageIndex);
for (auto& segment : message->segments()) for (auto& segment : message->segments())
{ {
@ -173,7 +170,7 @@ void AlertManager::Impl::HandleAlert(const types::TextEventKey& key,
// If the event has ended or is inactive, or if the alert is not enabled, // If the event has ended or is inactive, or if the alert is not enabled,
// skip it // skip it
if (eventEnd < scwx::util::time::now() || !alertActive || if (eventEnd < std::chrono::system_clock::now() || !alertActive ||
!audioSettings.alert_enabled(phenomenon).GetValue()) !audioSettings.alert_enabled(phenomenon).GetValue())
{ {
continue; continue;

View file

@ -155,7 +155,7 @@ void DownloadManager::Impl::DownloadSync(
return !request->IsCanceled(); return !request->IsCanceled();
}), }),
cpr::WriteCallback( cpr::WriteCallback(
[&](const std::string_view& data, std::intptr_t /* userdata */) [&](std::string data, std::intptr_t /* userdata */)
{ {
// Write file // Write file
ofs << data; ofs << data;

View file

@ -15,17 +15,19 @@
#include <boost/container_hash/hash.hpp> #include <boost/container_hash/hash.hpp>
#include <boost/unordered/unordered_flat_map.hpp> #include <boost/unordered/unordered_flat_map.hpp>
#include <boost/unordered/unordered_flat_set.hpp> #include <boost/unordered/unordered_flat_set.hpp>
#include <fmt/ranges.h>
#include <fontconfig/fontconfig.h> #include <fontconfig/fontconfig.h>
namespace scwx::qt::manager namespace scwx
{
namespace qt
{
namespace manager
{ {
static const std::string logPrefix_ = "scwx::qt::manager::font_manager"; static const std::string logPrefix_ = "scwx::qt::manager::font_manager";
static const auto logger_ = scwx::util::Logger::Create(logPrefix_); static const auto logger_ = scwx::util::Logger::Create(logPrefix_);
static const std::string kFcTrueType_ {"TrueType"}; static const std::string kFcTrueType_ {"TrueType"};
static const std::string kFcOpenType_ {"CFF"};
struct FontRecord struct FontRecord
{ {
@ -34,13 +36,15 @@ struct FontRecord
std::string filename_ {}; std::string filename_ {};
}; };
typedef std::pair<FontRecord, units::font_size::pixels<int>> FontRecordPair;
template<class Key> template<class Key>
struct FontRecordHash; struct FontRecordHash;
template<> template<>
struct FontRecordHash<FontRecord> struct FontRecordHash<FontRecordPair>
{ {
size_t operator()(const FontRecord& x) const; size_t operator()(const FontRecordPair& x) const;
}; };
class FontManager::Impl class FontManager::Impl
@ -65,7 +69,6 @@ public:
const std::vector<char>& GetRawFontData(const std::string& filename); const std::vector<char>& GetRawFontData(const std::string& filename);
static bool CheckFontFormat(const FcChar8* format);
static FontRecord MatchFontFile(const std::string& family, static FontRecord MatchFontFile(const std::string& family,
const std::vector<std::string>& styles); const std::vector<std::string>& styles);
@ -75,20 +78,20 @@ public:
std::shared_mutex imguiFontAtlasMutex_ {}; std::shared_mutex imguiFontAtlasMutex_ {};
boost::unordered_flat_map<FontRecord, std::uint64_t imguiFontsBuildCount_ {};
boost::unordered_flat_map<FontRecordPair,
std::shared_ptr<types::ImGuiFont>, std::shared_ptr<types::ImGuiFont>,
FontRecordHash<FontRecord>> FontRecordHash<FontRecordPair>>
imguiFonts_ {}; imguiFonts_ {};
std::shared_mutex imguiFontsMutex_ {}; std::shared_mutex imguiFontsMutex_ {};
boost::unordered_flat_map<std::string, std::vector<char>> rawFontData_ {}; boost::unordered_flat_map<std::string, std::vector<char>> rawFontData_ {};
std::mutex rawFontDataMutex_ {}; std::mutex rawFontDataMutex_ {};
std::pair<std::shared_ptr<types::ImGuiFont>, units::font_size::pixels<float>> std::shared_ptr<types::ImGuiFont> defaultFont_ {};
defaultFont_ {};
boost::unordered_flat_map<types::FontCategory, boost::unordered_flat_map<types::FontCategory,
std::pair<std::shared_ptr<types::ImGuiFont>, std::shared_ptr<types::ImGuiFont>>
units::font_size::pixels<float>>>
fontCategoryImguiFontMap_ {}; fontCategoryImguiFontMap_ {};
boost::unordered_flat_map<types::FontCategory, QFont> boost::unordered_flat_map<types::FontCategory, QFont>
fontCategoryQFontMap_ {}; fontCategoryQFontMap_ {};
@ -133,22 +136,22 @@ void FontManager::Impl::ConnectSignals()
}); });
} }
QObject::connect(&SettingsManager::Instance(), QObject::connect(
&SettingsManager::SettingsSaved, &SettingsManager::Instance(),
self_, &SettingsManager::SettingsSaved,
[this]() self_,
{ [this]()
const std::scoped_lock lock {dirtyFontsMutex_, {
fontCategoryMutex_}; std::scoped_lock lock {dirtyFontsMutex_, fontCategoryMutex_};
for (auto fontCategory : dirtyFonts_) for (auto fontCategory : dirtyFonts_)
{ {
UpdateImGuiFont(fontCategory); UpdateImGuiFont(fontCategory);
UpdateQFont(fontCategory); UpdateQFont(fontCategory);
} }
dirtyFonts_.clear(); dirtyFonts_.clear();
}); });
} }
void FontManager::InitializeFonts() void FontManager::InitializeFonts()
@ -160,22 +163,6 @@ void FontManager::InitializeFonts()
} }
} }
units::font_size::pixels<float>
FontManager::ImFontSize(units::font_size::pixels<double> size)
{
static constexpr units::font_size::pixels<int> kMinFontSize_ {8};
static constexpr units::font_size::pixels<int> kMaxFontSize_ {96};
// Only allow whole pixels, and clamp to 6-72 pt
const units::font_size::pixels<double> pixels {size};
const units::font_size::pixels<int> imFontSize {
std::clamp(static_cast<int>(pixels.value()),
kMinFontSize_.value(),
kMaxFontSize_.value())};
return imFontSize;
}
void FontManager::Impl::UpdateImGuiFont(types::FontCategory fontCategory) void FontManager::Impl::UpdateImGuiFont(types::FontCategory fontCategory)
{ {
auto& textSettings = settings::TextSettings::Instance(); auto& textSettings = settings::TextSettings::Instance();
@ -186,8 +173,7 @@ void FontManager::Impl::UpdateImGuiFont(types::FontCategory fontCategory)
textSettings.font_point_size(fontCategory).GetValue()}; textSettings.font_point_size(fontCategory).GetValue()};
fontCategoryImguiFontMap_.insert_or_assign( fontCategoryImguiFontMap_.insert_or_assign(
fontCategory, fontCategory, self_->LoadImGuiFont(family, {styles}, size));
std::make_pair(self_->LoadImGuiFont(family, {styles}), ImFontSize(size)));
} }
void FontManager::Impl::UpdateQFont(types::FontCategory fontCategory) void FontManager::Impl::UpdateQFont(types::FontCategory fontCategory)
@ -202,13 +188,7 @@ void FontManager::Impl::UpdateQFont(types::FontCategory fontCategory)
QFont font = QFontDatabase::font(QString::fromStdString(family), QFont font = QFontDatabase::font(QString::fromStdString(family),
QString::fromStdString(styles), QString::fromStdString(styles),
static_cast<int>(size.value())); static_cast<int>(size.value()));
#if !defined(__APPLE__)
font.setPointSizeF(size.value()); font.setPointSizeF(size.value());
#else
const units::font_size::pixels<double> pixelSize {size};
font.setPixelSize(static_cast<int>(pixelSize.value()));
#endif
fontCategoryQFontMap_.insert_or_assign(fontCategory, font); fontCategoryQFontMap_.insert_or_assign(fontCategory, font);
} }
@ -218,6 +198,11 @@ std::shared_mutex& FontManager::imgui_font_atlas_mutex()
return p->imguiFontAtlasMutex_; return p->imguiFontAtlasMutex_;
} }
std::uint64_t FontManager::imgui_fonts_build_count() const
{
return p->imguiFontsBuildCount_;
}
int FontManager::GetFontId(types::Font font) const int FontManager::GetFontId(types::Font font) const
{ {
auto it = p->fontIds_.find(font); auto it = p->fontIds_.find(font);
@ -228,7 +213,7 @@ int FontManager::GetFontId(types::Font font) const
return -1; return -1;
} }
std::pair<std::shared_ptr<types::ImGuiFont>, units::font_size::pixels<float>> std::shared_ptr<types::ImGuiFont>
FontManager::GetImGuiFont(types::FontCategory fontCategory) FontManager::GetImGuiFont(types::FontCategory fontCategory)
{ {
std::unique_lock lock {p->fontCategoryMutex_}; std::unique_lock lock {p->fontCategoryMutex_};
@ -256,23 +241,31 @@ QFont FontManager::GetQFont(types::FontCategory fontCategory)
} }
std::shared_ptr<types::ImGuiFont> std::shared_ptr<types::ImGuiFont>
FontManager::LoadImGuiFont(const std::string& family, FontManager::LoadImGuiFont(const std::string& family,
const std::vector<std::string>& styles, const std::vector<std::string>& styles,
bool loadIfNotFound) units::font_size::points<double> size,
bool loadIfNotFound)
{ {
const std::string styleString = fmt::format("{}", fmt::join(styles, " ")); const std::string styleString = fmt::format("{}", fmt::join(styles, " "));
const std::string fontString = fmt::format("{}:{}", family, styleString); const std::string fontString =
fmt::format("{}-{}:{}", family, size.value(), styleString);
logger_->debug("LoadFontResource: {}", fontString); logger_->debug("LoadFontResource: {}", fontString);
FontRecord fontRecord = Impl::MatchFontFile(family, styles); FontRecord fontRecord = Impl::MatchFontFile(family, styles);
// Only allow whole pixels, and clamp to 6-72 pt
units::font_size::pixels<double> pixels {size};
units::font_size::pixels<int> imFontSize {
std::clamp(static_cast<int>(pixels.value()), 8, 96)};
auto imguiFontKey = std::make_pair(fontRecord, imFontSize);
// Search for a loaded ImGui font // Search for a loaded ImGui font
{ {
std::shared_lock imguiFontLock {p->imguiFontsMutex_}; std::shared_lock imguiFontLock {p->imguiFontsMutex_};
// Search for the associated ImGui font // Search for the associated ImGui font
auto it = p->imguiFonts_.find(fontRecord); auto it = p->imguiFonts_.find(imguiFontKey);
if (it != p->imguiFonts_.end()) if (it != p->imguiFonts_.end())
{ {
return it->second; return it->second;
@ -297,7 +290,7 @@ FontManager::LoadImGuiFont(const std::string& family,
// Search for the associated ImGui font again, to prevent loading the same // Search for the associated ImGui font again, to prevent loading the same
// font twice // font twice
auto it = p->imguiFonts_.find(fontRecord); auto it = p->imguiFonts_.find(imguiFontKey);
if (it != p->imguiFonts_.end()) if (it != p->imguiFonts_.end())
{ {
return it->second; return it->second;
@ -308,20 +301,25 @@ FontManager::LoadImGuiFont(const std::string& family,
try try
{ {
fontName = fmt::format( fontName = fmt::format(
"{}", std::filesystem::path(fontRecord.filename_).filename().string()); "{}:{}",
std::filesystem::path(fontRecord.filename_).filename().string(),
imFontSize.value());
} }
catch (const std::exception& ex) catch (const std::exception& ex)
{ {
logger_->warn(ex.what()); logger_->warn(ex.what());
fontName = fmt::format("{}", fontRecord.filename_); fontName = fmt::format("{}:{}", fontRecord.filename_, imFontSize.value());
} }
// Create an ImGui font // Create an ImGui font
std::shared_ptr<types::ImGuiFont> imguiFont = std::shared_ptr<types::ImGuiFont> imguiFont =
std::make_shared<types::ImGuiFont>(fontName, rawFontData); std::make_shared<types::ImGuiFont>(fontName, rawFontData, imFontSize);
// Store the ImGui font // Store the ImGui font
p->imguiFonts_.insert_or_assign(fontRecord, imguiFont); p->imguiFonts_.insert_or_assign(imguiFontKey, imguiFont);
// Increment ImGui font build count
++p->imguiFontsBuildCount_;
// Return the ImGui font // Return the ImGui font
return imguiFont; return imguiFont;
@ -458,13 +456,6 @@ void FontManager::Impl::FinalizeFontconfig()
FcFini(); FcFini();
} }
bool FontManager::Impl::CheckFontFormat(const FcChar8* format)
{
const std::string stdFormat = reinterpret_cast<const char*>(format);
return stdFormat == kFcTrueType_ || stdFormat == kFcOpenType_;
}
FontRecord FontRecord
FontManager::Impl::MatchFontFile(const std::string& family, FontManager::Impl::MatchFontFile(const std::string& family,
const std::vector<std::string>& styles) const std::vector<std::string>& styles)
@ -477,7 +468,9 @@ FontManager::Impl::MatchFontFile(const std::string& family,
FcPatternAddString( FcPatternAddString(
pattern, FC_FAMILY, reinterpret_cast<const FcChar8*>(family.c_str())); pattern, FC_FAMILY, reinterpret_cast<const FcChar8*>(family.c_str()));
FcPatternAddBool(pattern, FC_SYMBOL, FcFalse); FcPatternAddString(pattern,
FC_FONTFORMAT,
reinterpret_cast<const FcChar8*>(kFcTrueType_.c_str()));
if (!styles.empty()) if (!styles.empty())
{ {
@ -491,55 +484,29 @@ FontManager::Impl::MatchFontFile(const std::string& family,
FcDefaultSubstitute(pattern); FcDefaultSubstitute(pattern);
// Find matching font // Find matching font
FcResult result {}; FcResult result;
FcFontSet* matches = FcFontSort(nullptr, pattern, FcFalse, nullptr, &result); FcPattern* match = FcFontMatch(nullptr, pattern, &result);
FontRecord record {}; FontRecord record {};
if (matches != nullptr) if (match != nullptr)
{ {
for (int i = 0; i < matches->nfont; i++) FcChar8* fcFamily;
FcChar8* fcStyle;
FcChar8* fcFile;
// Match was found, get properties
if (FcPatternGetString(match, FC_FAMILY, 0, &fcFamily) == FcResultMatch &&
FcPatternGetString(match, FC_STYLE, 0, &fcStyle) == FcResultMatch &&
FcPatternGetString(match, FC_FILE, 0, &fcFile) == FcResultMatch)
{ {
FcPattern* match = record.family_ = reinterpret_cast<char*>(fcFamily);
// Using C code requires pointer arithmetic record.style_ = reinterpret_cast<char*>(fcStyle);
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) record.filename_ = reinterpret_cast<char*>(fcFile);
FcFontRenderPrepare(nullptr, pattern, matches->fonts[i]);
if (match == nullptr)
{
continue;
}
FcChar8* fcFamily = nullptr;
FcChar8* fcStyle = nullptr;
FcChar8* fcFile = nullptr;
FcChar8* fcFormat = nullptr;
FcBool fcSymbol = FcFalse;
// Match was found, get properties logger_->debug("Found matching font: {}:{} ({})",
if (FcPatternGetString(match, FC_FAMILY, 0, &fcFamily) == record.family_,
FcResultMatch && record.style_,
FcPatternGetString(match, FC_STYLE, 0, &fcStyle) == record.filename_);
FcResultMatch &&
FcPatternGetString(match, FC_FILE, 0, &fcFile) == FcResultMatch &&
FcPatternGetBool(match, FC_SYMBOL, 0, &fcSymbol) ==
FcResultMatch &&
FcPatternGetString(match, FC_FONTFORMAT, 0, &fcFormat) ==
FcResultMatch &&
fcSymbol == FcFalse /*Must check fcSymbol manually*/ &&
CheckFontFormat(fcFormat))
{
record.family_ = reinterpret_cast<char*>(fcFamily);
record.style_ = reinterpret_cast<char*>(fcStyle);
record.filename_ = reinterpret_cast<char*>(fcFile);
logger_->debug("Found matching font: {}:{} ({}) {}",
record.family_,
record.style_,
record.filename_,
fcSymbol);
FcPatternDestroy(match);
break;
}
FcPatternDestroy(match);
} }
} }
@ -549,7 +516,7 @@ FontManager::Impl::MatchFontFile(const std::string& family,
} }
// Cleanup // Cleanup
FcFontSetDestroy(matches); FcPatternDestroy(match);
FcPatternDestroy(pattern); FcPatternDestroy(pattern);
return record; return record;
@ -561,12 +528,13 @@ FontManager& FontManager::Instance()
return instance_; return instance_;
} }
size_t FontRecordHash<FontRecord>::operator()(const FontRecord& x) const size_t FontRecordHash<FontRecordPair>::operator()(const FontRecordPair& x) const
{ {
size_t seed = 0; size_t seed = 0;
boost::hash_combine(seed, x.family_); boost::hash_combine(seed, x.first.family_);
boost::hash_combine(seed, x.style_); boost::hash_combine(seed, x.first.style_);
boost::hash_combine(seed, x.filename_); boost::hash_combine(seed, x.first.filename_);
boost::hash_combine(seed, x.second.value());
return seed; return seed;
} }
@ -577,4 +545,6 @@ bool operator==(const FontRecord& lhs, const FontRecord& rhs)
lhs.filename_ == rhs.filename_; lhs.filename_ == rhs.filename_;
} }
} // namespace scwx::qt::manager } // namespace manager
} // namespace qt
} // namespace scwx

View file

@ -26,22 +26,21 @@ public:
~FontManager(); ~FontManager();
std::shared_mutex& imgui_font_atlas_mutex(); std::shared_mutex& imgui_font_atlas_mutex();
std::uint64_t imgui_fonts_build_count() const;
int GetFontId(types::Font font) const; int GetFontId(types::Font font) const;
std::pair<std::shared_ptr<types::ImGuiFont>, units::font_size::pixels<float>> std::shared_ptr<types::ImGuiFont>
GetImGuiFont(types::FontCategory fontCategory); GetImGuiFont(types::FontCategory fontCategory);
QFont GetQFont(types::FontCategory fontCategory); QFont GetQFont(types::FontCategory fontCategory);
std::shared_ptr<types::ImGuiFont> std::shared_ptr<types::ImGuiFont>
LoadImGuiFont(const std::string& family, LoadImGuiFont(const std::string& family,
const std::vector<std::string>& styles, const std::vector<std::string>& styles,
bool loadIfNotFound = true); units::font_size::points<double> size,
bool loadIfNotFound = true);
void LoadApplicationFont(types::Font font, const std::string& filename); void LoadApplicationFont(types::Font font, const std::string& filename);
void InitializeFonts(); void InitializeFonts();
static units::font_size::pixels<float>
ImFontSize(units::font_size::pixels<double> size);
static FontManager& Instance(); static FontManager& Instance();
private: private:

View file

@ -1,14 +1,12 @@
#include <scwx/qt/manager/log_manager.hpp> #include <scwx/qt/manager/log_manager.hpp>
#include <scwx/util/logger.hpp> #include <scwx/util/logger.hpp>
#include <cstdlib>
#include <ctime>
#include <filesystem> #include <filesystem>
#include <map> #include <map>
#include <ranges> #include <ranges>
#include <unordered_map> #include <unordered_map>
#include <boost/process/v1/environment.hpp> #include <boost/process/environment.hpp>
#include <fmt/format.h> #include <fmt/format.h>
#include <spdlog/spdlog.h> #include <spdlog/spdlog.h>
#include <QStandardPaths> #include <QStandardPaths>
@ -59,14 +57,6 @@ void LogManager::InitializeLogFile()
QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation)
.toStdString(); .toStdString();
p->pid_ = boost::this_process::get_id(); p->pid_ = boost::this_process::get_id();
if (p->pid_ == 2)
{
// The pid == 2 means that this is likely a flatpak. We assign a random
// number in this case to avoid overlap, scince it is always 2 in a
// flatpak
std::srand(std::time({}));
p->pid_ = std::rand();
}
p->logFile_ = fmt::format("{}/supercell-wx.{}.log", p->logPath_, p->pid_); p->logFile_ = fmt::format("{}/supercell-wx.{}.log", p->logPath_, p->pid_);
// Create log directory if it doesn't exist // Create log directory if it doesn't exist

Some files were not shown because too many files have changed in this diff Show more