Compare commits

..
Author SHA1 Message Date
SirKnightly 30371fae64 Automated build commit 2026-01-04 01:53:12 +00:00
1662 changed files with 84471 additions and 195539 deletions

No files matched your search

+114 -149
View File
@@ -5,6 +5,9 @@ on:
tags:
- 'nightly_*'
env:
QT_VERSION: 5.12.12
jobs:
build_linux:
strategy:
@@ -18,25 +21,24 @@ jobs:
arch: arm64
name: Linux
runs-on: ${{ matrix.os }}
container: ghcr.io/scp-fs2open/linux_build:sha-ab87451
container: ghcr.io/scp-fs2open/linux_build:sha-71099c9
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@v1
name: Checkout
with:
submodules: true
- name: Set workspace as safe
# This appears to be broken in current actions, so do it manually
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
- name: Configure CMake
env:
CONFIGURATION: ${{ matrix.configuration }}
COMPILER: gcc-9
ENABLE_QTFRED: OFF
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
- name: Compile
working-directory: ./build
env:
CONFIGURATION: ${{ matrix.configuration }}
run: ninja -k 20 all
run: |
LD_LIBRARY_PATH=$Qt5_DIR/lib:$LD_LIBRARY_PATH ninja -k 20 all
- name: Run Tests
working-directory: ./build
env:
@@ -49,7 +51,7 @@ jobs:
CONFIGURATION: ${{ matrix.configuration }}
run: $GITHUB_WORKSPACE/ci/linux/generate_appimage.sh $GITHUB_WORKSPACE/build/install
- name: Upload build result
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v4
with:
name: linux-${{ matrix.configuration }}-${{ matrix.arch }}
path: ${{ github.workspace }}/build/install/*.AppImage
@@ -57,26 +59,23 @@ jobs:
name: Build Linux distribution zip
needs: build_linux
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/sftp_upload:sha-ab87451
container: ghcr.io/scp-fs2open/sftp_upload:sha-748b19d
strategy:
matrix:
arch: [x86_64, arm64]
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@v1
name: Checkout
with:
submodules: true
fetch-depth: '0'
- name: Set workspace as safe
# This appears to be broken in current actions, so do it manually
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
- name: Download Release builds
uses: actions/download-artifact@v8
uses: actions/download-artifact@v4
with:
name: linux-Release-${{ matrix.arch }}
path: builds
- name: Download FastDebug builds
uses: actions/download-artifact@v8
uses: actions/download-artifact@v4
with:
name: linux-FastDebug-${{ matrix.arch }}
path: builds
@@ -102,169 +101,119 @@ jobs:
strategy:
matrix:
configuration: [FastDebug, Release]
os: [windows-2025, windows-11-arm]
arch: [Win32, x64, ARM64]
simd: [SSE2, ""]
exclude:
- arch: Win32
os: windows-11-arm
- arch: x64
os: windows-11-arm
- arch: ARM64
os: windows-2025
- os: windows-2025
simd: ""
- os: windows-11-arm
simd: SSE2
arch: [Win32, x64]
simd: [SSE2]
name: Windows
runs-on: ${{ matrix.os }}
runs-on: windows-2022
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@v1
name: Checkout
with:
submodules: true
- name: Set workspace as safe
# This appears to be broken in current actions, so do it manually
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
- name: Install v143 ATL/MFC
shell: pwsh
run: ci/windows/install_v143_atlmfc.ps1
# Tree A: static CRT (/MT) for FSO + FRED2 (no Qt dependency needed)
- name: Configure CMake (static CRT /MT - FSO + FRED2)
# - name: Cache Qt
# id: cache-qt-win
# uses: actions/cache@v1
# with:
# path: ${{ github.workspace }}/../Qt
# key: ${{ runner.os }}-${{ matrix.arch }}-QtCache-${{ env.QT_VERSION }}
# - name: Install Qt (32 bit)
# uses: jurplel/install-qt-action@v2
# if: ${{ matrix.arch == 'Win32' }}
# with:
# version: ${{ env.QT_VERSION }}
# dir: ${{ github.workspace }}/..
# arch: win32_msvc2017
# cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
# aqtversion: ==0.8
# - name: Install Qt (64 bit)
# uses: jurplel/install-qt-action@v2
# if: ${{ matrix.arch == 'x64' }}
# with:
# version: ${{ env.QT_VERSION }}
# dir: ${{ github.workspace }}/..
# arch: win64_msvc2017_64
# cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
# aqtversion: ==0.8
- name: Prepare Vulkan SDK
uses: humbletim/[email protected]
with:
vulkan-query-version: 1.4.304.1
vulkan-components: Vulkan-Headers, Vulkan-Loader
vulkan-use-cache: true
- name: Configure CMake
env:
CONFIGURATION: ${{ matrix.configuration }}
ARCHITECTURE: ${{ matrix.arch }}
SIMD: ${{ matrix.simd }}
shell: bash
run: |
mkdir build-mt
cd build-mt
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH=ON \
-DFSO_USE_VOICEREC=ON -DFORCED_SIMD_INSTRUCTIONS="$SIMD" \
-DFSO_BUILD_TESTS=ON -DFSO_INSTALL_DEBUG_FILES=ON -A "$ARCHITECTURE" \
-DFSO_BUILD_QTFRED=OFF -G "Visual Studio 18 2026" -T "v143" \
-DCMAKE_BUILD_TYPE=$CONFIGURATION ..
- name: Compile (static CRT)
working-directory: ./build-mt
env:
CONFIGURATION: ${{ matrix.configuration }}
COMPILER: ${{ matrix.compiler }}
shell: bash
run: |
cmake --build . --config "$CONFIGURATION" -- /verbosity:minimal
cmake --install . --config "$CONFIGURATION"
ls -alR "$(pwd)/install"
# Tree B: dynamic CRT (/MD) for QtFRED only (matches Qt's prebuilt /MD runtime)
# Skipped on Win32: Qt6 has no 32-bit Windows support, so CMake force-disables
# FSO_BUILD_QTFRED there and the qtfred target would not exist
- name: Configure CMake (dynamic CRT /MD - QtFRED)
if: matrix.arch != 'Win32'
env:
CONFIGURATION: ${{ matrix.configuration }}
ARCHITECTURE: ${{ matrix.arch }}
SIMD: ${{ matrix.simd }}
shell: bash
run: |
mkdir build-md
cd build-md
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH=ON \
-DFSO_USE_VOICEREC=ON -DFORCED_SIMD_INSTRUCTIONS="$SIMD" \
-DFSO_BUILD_TESTS=OFF -DFSO_INSTALL_DEBUG_FILES=ON -A "$ARCHITECTURE" \
-DFSO_BUILD_QTFRED=ON -DFSO_BUILD_FRED2=OFF -DQT_USE_PRECOMPILED=ON \
-G "Visual Studio 18 2026" -T "v143" -DCMAKE_BUILD_TYPE=$CONFIGURATION ..
- name: Compile (dynamic CRT)
if: matrix.arch != 'Win32'
working-directory: ./build-md
env:
CONFIGURATION: ${{ matrix.configuration }}
COMPILER: ${{ matrix.compiler }}
shell: bash
run: |
cmake --build . --config "$CONFIGURATION" --target qtfred -- /verbosity:minimal
cmake --install . --config "$CONFIGURATION" --component qtFRED
ls -alR "$(pwd)/install"
# Merge both trees into the single install dir the zip job consumes
- name: Merge installs
shell: bash
run: |
mkdir -p build/install
# build-md does not exist on Win32 (no QtFRED there)
if [ -d build-md/install ]; then
cp -r build-md/install/. build/install/
mkdir build
cd build
if [ "$ARCHITECTURE" = "Win32" ]; then
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH="ON" \
-DFSO_USE_VOICEREC="ON" -DFORCED_SIMD_INSTRUCTIONS="$SIMD" \
-DFSO_BUILD_QTFRED=OFF -DFSO_BUILD_TESTS=ON \
-DFSO_INSTALL_DEBUG_FILES="ON" -DFSO_BUILD_WITH_VULKAN="OFF" -A "$ARCHITECTURE" \
-G "Visual Studio 17 2022" -T "v143" -DCMAKE_BUILD_TYPE=$CONFIGURATION ..
else
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH="ON" \
-DFSO_USE_VOICEREC="ON" -DFORCED_SIMD_INSTRUCTIONS="$SIMD" \
-DFSO_BUILD_QTFRED=OFF -DFSO_BUILD_TESTS=ON \
-DFSO_INSTALL_DEBUG_FILES="ON" -A "$ARCHITECTURE" \
-G "Visual Studio 17 2022" -T "v143" -DCMAKE_BUILD_TYPE=$CONFIGURATION ..
fi
cp -r build-mt/install/. build/install/
ls -alR build/install
- name: Compile
working-directory: ./build
env:
CONFIGURATION: ${{ matrix.configuration }}
COMPILER: ${{ matrix.compiler }}
shell: bash
run: |
cmake --build . --config "$CONFIGURATION" --target INSTALL -- /verbosity:minimal
ls -alR "$(pwd)/install"
- name: Run Tests
working-directory: ./build-mt
working-directory: ./build
env:
CONFIGURATION: ${{ matrix.configuration }}
shell: bash
run: ./bin/$CONFIGURATION/unittests --gtest_shuffle
- name: Set artifact id
shell: bash
run: |
id=
if [ -n "${{ matrix.simd }}" ]; then
id="${{ matrix.configuration }}-${{ matrix.arch }}-${{ matrix.simd }}"
else
id="${{ matrix.configuration }}-${{ matrix.arch }}"
fi
echo "artifact_id=${id}" >> $GITHUB_ENV
- name: Upload build result
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v4
with:
name: windows-${{ env.artifact_id }}
name: windows-${{ matrix.configuration }}-${{ matrix.arch }}-${{ matrix.simd }}
path: ${{ github.workspace }}/build/install/*
windows_zip:
name: Build Windows distribution zip
needs: build_windows
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/sftp_upload:sha-ab87451
container: ghcr.io/scp-fs2open/sftp_upload:sha-748b19d
strategy:
matrix:
arch: [Win32, x64, ARM64]
simd: [SSE2, ""]
exclude:
- arch: Win32
simd: ""
- arch: x64
simd: ""
- arch: ARM64
simd: SSE2
arch: [Win32, x64]
simd: [SSE2]
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@v1
name: Checkout
with:
submodules: true
fetch-depth: '0'
- name: Set workspace as safe
# This appears to be broken in current actions, so do it manually
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
- name: Set artifact id
shell: bash
run: |
id=
if [ -n "${{ matrix.simd }}" ]; then
id="${{ matrix.arch }}-${{ matrix.simd }}"
else
id="${{ matrix.arch }}"
fi
echo "artifact_id=${id}" >> $GITHUB_ENV
- name: Download Release builds
uses: actions/download-artifact@v8
uses: actions/download-artifact@v4
with:
name: windows-Release-${{ env.artifact_id }}
name: windows-Release-${{ matrix.arch }}-${{ matrix.simd }}
path: builds
- name: Download FastDebug builds
uses: actions/download-artifact@v8
uses: actions/download-artifact@v4
with:
name: windows-FastDebug-${{ env.artifact_id }}
name: windows-FastDebug-${{ matrix.arch }}-${{ matrix.simd }}
path: builds
- name: Create Distribution package
working-directory: ./builds
shell: bash
env:
ID: ${{ env.artifact_id }}
ARCH: ${{ matrix.arch }}
SIMD: ${{ matrix.simd }}
run: $GITHUB_WORKSPACE/ci/linux/create_dist_pack.sh Windows
- name: Upload result package
working-directory: ./builds
@@ -285,14 +234,32 @@ jobs:
name: Mac
runs-on: macos-latest
steps:
- uses: actions/checkout@v7
# - name: Cache Qt
# id: cache-qt-mac
# uses: actions/cache@v1
# with:
# path: ${{ github.workspace }}/../Qt
# key: ${{ runner.os }}-QtCache-${{ env.QT_VERSION }}
# - name: Install Qt
# uses: jurplel/install-qt-action@v2
# with:
# version: ${{ env.QT_VERSION }}
# dir: ${{ github.workspace }}/..
# cached: ${{ steps.cache-qt-mac.outputs.cache-hit }}
# setup-python: 'false'
# aqtversion: ==1.1.3
# py7zrversion: '==0.19.*'
- uses: actions/checkout@v1
name: Checkout
with:
submodules: true
fetch-depth: 0
- name: Set workspace as safe
# This appears to be broken in current actions, so do it manually
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
- name: Prepare Vulkan SDK
uses: humbletim/[email protected]
with:
vulkan-query-version: 1.4.304.1
vulkan-components: Vulkan-Headers, Vulkan-Loader
vulkan-use-cache: true
- name: Set up test version
shell: bash
run: |
@@ -305,10 +272,11 @@ jobs:
COMPILER: ${{ matrix.compiler }}
ARCHITECTURE: ${{ matrix.arch }}
JOB_CMAKE_OPTIONS: ${{ matrix.cmake_options }}
ENABLE_QTFRED: OFF
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
- name: Compile
working-directory: ./build
run: ninja all
run: LD_LIBRARY_PATH=$Qt5_DIR/lib:$LD_LIBRARY_PATH ninja all
- name: Run Tests
working-directory: ./build
env:
@@ -334,7 +302,7 @@ jobs:
# Ref: https://github.com/actions/runner-images/issues/2619
run: gtar -cvzf macos-build-${{ matrix.configuration }}-${{ matrix.arch }}.tgz *.app
- name: Upload build result
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v4
with:
name: mac-${{ matrix.configuration }}-${{ matrix.arch }}
path: ${{ github.workspace }}/build/bin/macos-build-${{ matrix.configuration }}-${{ matrix.arch }}.tgz
@@ -342,27 +310,24 @@ jobs:
name: Build Mac distribution zip
needs: build_mac
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/sftp_upload:sha-ab87451
container: ghcr.io/scp-fs2open/sftp_upload:sha-748b19d
strategy:
matrix:
arch: [x86_64, arm64]
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@v2
name: Checkout
with:
submodules: true
fetch-depth: '0'
ref: '${{ github.ref }}'
- name: Set workspace as safe
# This appears to be broken in current actions, so do it manually
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
- name: Download Release builds
uses: actions/download-artifact@v8
uses: actions/download-artifact@v4
with:
name: mac-Release-${{ matrix.arch }}
path: builds
- name: Download FastDebug builds
uses: actions/download-artifact@v8
uses: actions/download-artifact@v4
with:
name: mac-FastDebug-${{ matrix.arch }}
path: builds
+120 -157
View File
@@ -5,6 +5,9 @@ on:
tags:
- 'release_*'
env:
QT_VERSION: 5.12.12
jobs:
create_release:
name: Create GitHub release
@@ -47,27 +50,26 @@ jobs:
name: Linux
needs: create_release # Don't run this job until create_release is done and successful
runs-on: ${{ matrix.os }}
container: ghcr.io/scp-fs2open/linux_build:sha-ab87451
container: ghcr.io/scp-fs2open/linux_build:sha-71099c9
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@v1
# checks-out your repository under $GITHUB_WORKSPACE, so your workflow can access it.
name: Checkout
with:
submodules: true # `true` to checkout submodules, `recursive` to recursively checkout submodules
ref: '${{ github.ref }}'
- name: Set workspace as safe
# This appears to be broken in current actions, so do it manually
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
- name: Configure CMake
env:
CONFIGURATION: ${{ matrix.configuration }}
COMPILER: gcc-9
ENABLE_QTFRED: OFF
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
- name: Compile
working-directory: ./build
env:
CONFIGURATION: ${{ matrix.configuration }}
run: ninja -k 20 all
run: |
LD_LIBRARY_PATH=$Qt5_DIR/lib:$LD_LIBRARY_PATH ninja -k 20 all
- name: Run Tests
working-directory: ./build
env:
@@ -80,7 +82,7 @@ jobs:
CONFIGURATION: ${{ matrix.configuration }}
run: $GITHUB_WORKSPACE/ci/linux/generate_appimage.sh $GITHUB_WORKSPACE/build/install
- name: Upload build result
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v4
# Upload the url file for use with other runners
# upload-artifact.inputs:
# if-no-files-found=warn What to do if path fails to find any files.
@@ -97,29 +99,26 @@ jobs:
name: Build Linux distribution zip
needs: build_linux
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/sftp_upload:sha-ab87451
container: ghcr.io/scp-fs2open/sftp_upload:sha-748b19d
strategy:
matrix:
arch: [x86_64, arm64]
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@v1
name: Checkout
with:
submodules: true
fetch-depth: '0' # value 0 to fetch all history and tags for all branches
ref: '${{ github.ref }}'
- name: Set workspace as safe
# This appears to be broken in current actions, so do it manually
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
- name: Download Release builds
# Grab the release builds
uses: actions/download-artifact@v8
uses: actions/download-artifact@v4
with:
name: linux-Release-${{ matrix.arch }}
path: builds
- name: Download FastDebug builds
# Grab the debug builds
uses: actions/download-artifact@v8
uses: actions/download-artifact@v4
with:
name: linux-FastDebug-${{ matrix.arch }}
path: builds
@@ -136,7 +135,7 @@ jobs:
run: $GITHUB_WORKSPACE/ci/linux/create_dist_pack.sh Linux
- name: Upload result package
# Stash the result to artifact filespace
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v4
with:
name: ${{ steps.generate_package.outputs.package_name }}
path: ${{ steps.generate_package.outputs.package_path }}
@@ -152,175 +151,123 @@ jobs:
strategy:
matrix:
configuration: [FastDebug, Release]
os: [windows-2025, windows-11-arm]
arch: [Win32, x64, ARM64]
simd: [SSE2, AVX, ""]
exclude:
- arch: Win32
os: windows-11-arm
- arch: x64
os: windows-11-arm
- arch: ARM64
os: windows-2025
- os: windows-2025
simd: ""
- os: windows-11-arm
simd: SSE2
- os: windows-11-arm
simd: AVX
arch: [Win32, x64]
simd: [SSE2, AVX]
needs: create_release
name: Windows
runs-on: ${{ matrix.os }}
runs-on: windows-2022
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@v1
# Checkout repo
name: Checkout
with:
submodules: true
ref: '${{ github.ref }}'
- name: Set workspace as safe
# This appears to be broken in current actions, so do it manually
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
- name: Install v143 ATL/MFC
shell: pwsh
run: ci/windows/install_v143_atlmfc.ps1
# Tree A: static CRT (/MT) for FSO + FRED2 (no Qt dependency needed)
- name: Configure CMake (static CRT /MT - FSO + FRED2)
# - name: Cache Qt
# # Cache Qt
# id: cache-qt-win
# uses: actions/cache@v1
# with:
# path: ${{ github.workspace }}/../Qt
# key: ${{ runner.os }}-${{ matrix.arch }}-QtCache-${{ env.QT_VERSION }}
# - name: Install Qt (32 bit)
# # Install Qt 32bit if matrix.arch == Win32
# uses: jurplel/install-qt-action@v2
# if: ${{ matrix.arch == 'Win32' }}
# with:
# version: ${{ env.QT_VERSION }}
# dir: ${{ github.workspace }}/..
# arch: win32_msvc2017
# cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
# aqtversion: ==0.8
# - name: Install Qt (64 bit)
# # Install Qt 64bit if matrix.arch == x64
# uses: jurplel/install-qt-action@v2
# if: ${{ matrix.arch == 'x64' }}
# with:
# version: ${{ env.QT_VERSION }}
# dir: ${{ github.workspace }}/..
# arch: win64_msvc2017_64
# cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
# aqtversion: ==0.8
- name: Prepare Vulkan SDK
uses: humbletim/[email protected]
with:
vulkan-query-version: 1.4.304.1
vulkan-components: Vulkan-Headers, Vulkan-Loader
vulkan-use-cache: true
- name: Configure CMake
env:
CONFIGURATION: ${{ matrix.configuration }}
ARCHITECTURE: ${{ matrix.arch }}
SIMD: ${{ matrix.simd }}
shell: bash
run: |
mkdir build-mt
cd build-mt
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH=ON \
-DFSO_USE_VOICEREC=ON -DFORCED_SIMD_INSTRUCTIONS="$SIMD" \
-DFSO_BUILD_TESTS=ON -DFSO_INSTALL_DEBUG_FILES=ON -A "$ARCHITECTURE" \
-DFSO_BUILD_QTFRED=OFF -G "Visual Studio 18 2026" -T "v143" \
-DCMAKE_BUILD_TYPE=$CONFIGURATION ..
- name: Compile (static CRT)
working-directory: ./build-mt
env:
CONFIGURATION: ${{ matrix.configuration }}
COMPILER: ${{ matrix.compiler }}
shell: bash
run: |
cmake --build . --config "$CONFIGURATION" -- /verbosity:minimal
cmake --install . --config "$CONFIGURATION"
ls -alR "$(pwd)/install"
# Tree B: dynamic CRT (/MD) for QtFRED only (matches Qt's prebuilt /MD runtime)
# Skipped on Win32: Qt6 has no 32-bit Windows support, so CMake force-disables
# FSO_BUILD_QTFRED there and the qtfred target would not exist
- name: Configure CMake (dynamic CRT /MD - QtFRED)
if: matrix.arch != 'Win32'
env:
CONFIGURATION: ${{ matrix.configuration }}
ARCHITECTURE: ${{ matrix.arch }}
SIMD: ${{ matrix.simd }}
shell: bash
run: |
mkdir build-md
cd build-md
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH=ON \
-DFSO_USE_VOICEREC=ON -DFORCED_SIMD_INSTRUCTIONS="$SIMD" \
-DFSO_BUILD_TESTS=OFF -DFSO_INSTALL_DEBUG_FILES=ON -A "$ARCHITECTURE" \
-DFSO_BUILD_QTFRED=ON -DFSO_BUILD_FRED2=OFF -DQT_USE_PRECOMPILED=ON \
-G "Visual Studio 18 2026" -T "v143" -DCMAKE_BUILD_TYPE=$CONFIGURATION ..
- name: Compile (dynamic CRT)
if: matrix.arch != 'Win32'
working-directory: ./build-md
env:
CONFIGURATION: ${{ matrix.configuration }}
COMPILER: ${{ matrix.compiler }}
shell: bash
run: |
cmake --build . --config "$CONFIGURATION" --target qtfred -- /verbosity:minimal
cmake --install . --config "$CONFIGURATION" --component qtFRED
ls -alR "$(pwd)/install"
# Merge both trees into the single install dir the zip job consumes
- name: Merge installs
shell: bash
run: |
mkdir -p build/install
# build-md does not exist on Win32 (no QtFRED there)
if [ -d build-md/install ]; then
cp -r build-md/install/. build/install/
mkdir build
cd build
if [ "$ARCHITECTURE" = "Win32" ]; then
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH="ON" \
-DFSO_USE_VOICEREC="ON" -DFORCED_SIMD_INSTRUCTIONS="$SIMD" \
-DFSO_BUILD_QTFRED=OFF -DFSO_BUILD_TESTS=ON \
-DFSO_INSTALL_DEBUG_FILES="ON" -DFSO_BUILD_WITH_VULKAN="OFF" -A "$ARCHITECTURE" \
-G "Visual Studio 17 2022" -T "v143" -DCMAKE_BUILD_TYPE=$CONFIGURATION ..
else
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH="ON" \
-DFSO_USE_VOICEREC="ON" -DFORCED_SIMD_INSTRUCTIONS="$SIMD" \
-DFSO_BUILD_QTFRED=OFF -DFSO_BUILD_TESTS=ON \
-DFSO_INSTALL_DEBUG_FILES="ON" -A "$ARCHITECTURE" \
-G "Visual Studio 17 2022" -T "v143" -DCMAKE_BUILD_TYPE=$CONFIGURATION ..
fi
cp -r build-mt/install/. build/install/
ls -alR build/install
- name: Compile
working-directory: ./build
env:
CONFIGURATION: ${{ matrix.configuration }}
COMPILER: ${{ matrix.compiler }}
shell: bash
run: |
cmake --build . --config "$CONFIGURATION" --target INSTALL -- /verbosity:minimal
ls -alR "$(pwd)/install"
- name: Run Tests
working-directory: ./build-mt
working-directory: ./build
env:
CONFIGURATION: ${{ matrix.configuration }}
shell: bash
run: ./bin/$CONFIGURATION/unittests --gtest_shuffle
- name: Set artifact id
shell: bash
run: |
id=
if [ -n "${{ matrix.simd }}" ]; then
id="${{ matrix.configuration }}-${{ matrix.arch }}-${{ matrix.simd }}"
else
id="${{ matrix.configuration }}-${{ matrix.arch }}"
fi
echo "artifact_id=${id}" >> $GITHUB_ENV
- name: Upload build result
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v4
with:
name: windows-${{ env.artifact_id }}
name: windows-${{ matrix.configuration }}-${{ matrix.arch }}-${{ matrix.simd }}
path: ${{ github.workspace }}/build/install/*
windows_zip:
name: Build Windows distribution zip
needs: build_windows
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/sftp_upload:sha-ab87451
container: ghcr.io/scp-fs2open/sftp_upload:sha-748b19d
strategy:
fail-fast: false # Run the other jobs in the matrix instead of failing them
matrix:
arch: [Win32, x64, ARM64]
simd: [SSE2, AVX, ""]
exclude:
- arch: Win32
simd: ""
- arch: x64
simd: ""
- arch: ARM64
simd: SSE2
- arch: ARM64
simd: AVX
arch: [Win32, x64]
simd: [SSE2, AVX]
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@v1
name: Checkout
with:
submodules: true
fetch-depth: '0'
ref: '${{ github.ref }}'
- name: Set workspace as safe
# This appears to be broken in current actions, so do it manually
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
- name: Set artifact id
shell: bash
run: |
id=
if [ -n "${{ matrix.simd }}" ]; then
id="${{ matrix.arch }}-${{ matrix.simd }}"
else
id="${{ matrix.arch }}"
fi
echo "artifact_id=${id}" >> $GITHUB_ENV
- name: Download Release builds
uses: actions/download-artifact@v8
uses: actions/download-artifact@v4
with:
name: windows-Release-${{ env.artifact_id }}
name: windows-Release-${{ matrix.arch }}-${{ matrix.simd }}
path: builds
- name: Download FastDebug builds
uses: actions/download-artifact@v8
uses: actions/download-artifact@v4
with:
name: windows-FastDebug-${{ env.artifact_id }}
name: windows-FastDebug-${{ matrix.arch }}-${{ matrix.simd }}
path: builds
- name: Create Distribution package
@@ -328,17 +275,18 @@ jobs:
working-directory: ./builds
shell: bash
env:
ID: ${{ env.artifact_id }}
ARCH: ${{ matrix.arch }}
SIMD: ${{ matrix.simd }}
run: $GITHUB_WORKSPACE/ci/linux/create_dist_pack.sh Windows
- name: Upload result package
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v4
with:
name: ${{ steps.generate_package.outputs.package_name }}
path: ${{ steps.generate_package.outputs.package_path }}
- name: Upload debug package
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v4
with:
name: ${{ steps.generate_package.outputs.debug_name }}
path: ${{ steps.generate_package.outputs.debug_path }}
@@ -362,25 +310,43 @@ jobs:
needs: create_release
runs-on: macos-latest
steps:
- uses: actions/checkout@v7
# - name: Cache Qt
# id: cache-qt-mac
# uses: actions/cache@v1
# with:
# path: ${{ github.workspace }}/../Qt
# key: ${{ runner.os }}-QtCache-${{ env.QT_VERSION }}
# - name: Install Qt
# uses: jurplel/install-qt-action@v2
# with:
# version: ${{ env.QT_VERSION }}
# dir: ${{ github.workspace }}/..
# cached: ${{ steps.cache-qt-mac.outputs.cache-hit }}
# setup-python: 'false'
# aqtversion: ==1.1.3
- uses: actions/checkout@v1
name: Checkout
with:
submodules: true
fetch-depth: 0
ref: '${{ github.ref }}'
- name: Set workspace as safe
# This appears to be broken in current actions, so do it manually
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
- name: Prepare Vulkan SDK
uses: humbletim/[email protected]
with:
vulkan-query-version: 1.4.304.1
vulkan-components: Vulkan-Headers, Vulkan-Loader
vulkan-use-cache: true
- name: Configure CMake
env:
CONFIGURATION: ${{ matrix.configuration }}
COMPILER: ${{ matrix.compiler }}
ARCHITECTURE: ${{ matrix.arch }}
JOB_CMAKE_OPTIONS: ${{ matrix.cmake_options }}
ENABLE_QTFRED: OFF
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
- name: Compile
working-directory: ./build
run: ninja all
run: LD_LIBRARY_PATH=$Qt5_DIR/lib:$LD_LIBRARY_PATH ninja all
- name: Run Tests
working-directory: ./build
env:
@@ -406,7 +372,7 @@ jobs:
# Ref: https://github.com/actions/runner-images/issues/2619
run: gtar -cvzf macos-build-${{ matrix.configuration }}-${{ matrix.arch }}.tgz *.app
- name: Upload build result
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v4
with:
name: mac-${{ matrix.configuration }}-${{ matrix.arch }}
path: ${{ github.workspace }}/build/bin/macos-build-${{ matrix.configuration }}-${{ matrix.arch }}.tgz
@@ -414,27 +380,24 @@ jobs:
name: Build Mac distribution zip
needs: build_mac
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/sftp_upload:sha-ab87451
container: ghcr.io/scp-fs2open/sftp_upload:sha-748b19d
strategy:
matrix:
arch: [x86_64, arm64]
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@v2
name: Checkout
with:
submodules: true
fetch-depth: '0'
ref: '${{ github.ref }}'
- name: Set workspace as safe
# This appears to be broken in current actions, so do it manually
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
- name: Download Release builds
uses: actions/download-artifact@v8
uses: actions/download-artifact@v4
with:
name: mac-Release-${{ matrix.arch }}
path: builds
- name: Download FastDebug builds
uses: actions/download-artifact@v8
uses: actions/download-artifact@v4
with:
name: mac-FastDebug-${{ matrix.arch }}
path: builds
@@ -450,7 +413,7 @@ jobs:
ARCH: ${{ matrix.arch }}
run: $GITHUB_WORKSPACE/ci/linux/create_dist_pack.sh Mac
- name: Upload result package
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v4
with:
name: ${{ steps.generate_package.outputs.package_name }}
path: ${{ steps.generate_package.outputs.package_path }}
+106 -114
View File
@@ -5,28 +5,22 @@ on:
branches:
- 'test/*'
env:
QT_VERSION: 5.12.12
jobs:
build_linux:
strategy:
matrix:
configuration: [FastDebug, Release]
os: [ubuntu-latest, ubuntu-24.04-arm]
include:
- os: ubuntu-latest
arch: x86_64
- os: ubuntu-24.04-arm
arch: arm64
name: Linux
runs-on: ${{ matrix.os }}
container: ghcr.io/scp-fs2open/linux_build:sha-ab87451
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/linux_build:sha-71099c9
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@v1
name: Checkout
with:
submodules: true
- name: Set workspace as safe
# This appears to be broken in current actions, so do it manually
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
- name: Set up test version
shell: bash
run: |
@@ -37,12 +31,14 @@ jobs:
env:
CONFIGURATION: ${{ matrix.configuration }}
COMPILER: gcc-9
ENABLE_QTFRED: OFF
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
- name: Compile
working-directory: ./build
env:
CONFIGURATION: ${{ matrix.configuration }}
run: ninja -k 20 all
run: |
LD_LIBRARY_PATH=$Qt5_DIR/lib:$LD_LIBRARY_PATH ninja -k 20 all
- name: Run Tests
working-directory: ./build
env:
@@ -55,46 +51,34 @@ jobs:
CONFIGURATION: ${{ matrix.configuration }}
run: $GITHUB_WORKSPACE/ci/linux/generate_appimage.sh $GITHUB_WORKSPACE/build/install
- name: Upload build result
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v4
with:
name: linux-${{ matrix.configuration }}-${{ matrix.arch }}
name: linux-${{ matrix.configuration }}
path: ${{ github.workspace }}/build/install/*.AppImage
linux_zip:
name: Build Linux distribution zip
needs: build_linux
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/sftp_upload:sha-ab87451
strategy:
matrix:
arch: [x86_64, arm64]
container: ghcr.io/scp-fs2open/sftp_upload:sha-748b19d
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@v2
name: Checkout
with:
submodules: true
fetch-depth: '0'
ref: '${{ github.ref }}'
- name: Set workspace as safe
# This appears to be broken in current actions, so do it manually
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
- name: Download Release builds
uses: actions/download-artifact@v8
uses: actions/download-artifact@v4
with:
name: linux-Release-${{ matrix.arch }}
name: linux-Release
path: builds
- name: Download FastDebug builds
uses: actions/download-artifact@v8
uses: actions/download-artifact@v4
with:
name: linux-FastDebug-${{ matrix.arch }}
name: linux-FastDebug
path: builds
- name: Fix permissions
working-directory: ./builds
shell: bash
run: chmod 755 *.AppImage
- name: Create Distribution package
working-directory: ./builds
env:
ARCH: ${{ matrix.arch }}
run: $GITHUB_WORKSPACE/ci/linux/create_dist_pack.sh Linux
- name: Upload result package
working-directory: ./builds
@@ -109,39 +93,51 @@ jobs:
strategy:
matrix:
configuration: [FastDebug, Release]
os: [windows-2025, windows-11-arm]
arch: [Win32, x64, ARM64]
simd: [SSE2, ""]
exclude:
- arch: Win32
os: windows-11-arm
- arch: x64
os: windows-11-arm
- arch: ARM64
os: windows-2025
- os: windows-2025
simd: ""
- os: windows-11-arm
simd: SSE2
arch: [Win32, x64]
simd: [SSE2]
name: Windows
runs-on: ${{ matrix.os }}
runs-on: windows-2022
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@v1
name: Checkout
with:
submodules: true
- name: Set workspace as safe
# This appears to be broken in current actions, so do it manually
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
- name: Set up test version
shell: bash
run: |
[[ "${{ github.ref }}" =~ ^refs\/heads\/test\/(.*)$ ]]
# Override the revision string so that the builds are named correctly
echo "set(FSO_VERSION_REVISION_STR ${BASH_REMATCH[1]})" > "version_override.cmake"
- name: Install v143 ATL/MFC
shell: pwsh
run: ci/windows/install_v143_atlmfc.ps1
# - name: Cache Qt
# id: cache-qt-win
# uses: actions/cache@v1
# with:
# path: ${{ github.workspace }}/../Qt
# key: ${{ runner.os }}-${{ matrix.arch }}-QtCache-${{ env.QT_VERSION }}
# - name: Install Qt (32 bit)
# uses: jurplel/install-qt-action@v2
# if: ${{ matrix.arch == 'Win32' }}
# with:
# version: ${{ env.QT_VERSION }}
# dir: ${{ github.workspace }}/..
# arch: win32_msvc2017
# cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
# aqtversion: ==0.8
# - name: Install Qt (64 bit)
# uses: jurplel/install-qt-action@v2
# if: ${{ matrix.arch == 'x64' }}
# with:
# version: ${{ env.QT_VERSION }}
# dir: ${{ github.workspace }}/..
# arch: win64_msvc2017_64
# cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
# aqtversion: ==0.8
- name: Prepare Vulkan SDK
uses: humbletim/[email protected]
with:
vulkan-query-version: 1.4.304.1
vulkan-components: Vulkan-Headers, Vulkan-Loader
vulkan-use-cache: true
- name: Configure CMake
env:
CONFIGURATION: ${{ matrix.configuration }}
@@ -151,11 +147,20 @@ jobs:
run: |
mkdir build
cd build
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH=ON \
-DFSO_USE_VOICEREC=ON -DFORCED_SIMD_INSTRUCTIONS="$SIMD" \
-DFSO_BUILD_TESTS=ON -DFSO_INSTALL_DEBUG_FILES=ON -A "$ARCHITECTURE" \
-DQT_USE_PRECOMPILED=ON -G "Visual Studio 18 2026" -T "v143" \
-DCMAKE_BUILD_TYPE=$CONFIGURATION ..
if [ "$ARCHITECTURE" = "Win32" ]; then
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH="ON" \
-DFSO_USE_VOICEREC="ON" -DFORCED_SIMD_INSTRUCTIONS="$SIMD" \
-DFSO_BUILD_QTFRED=OFF -DFSO_BUILD_TESTS=ON \
-DFSO_INSTALL_DEBUG_FILES="ON" -DFSO_BUILD_WITH_VULKAN="OFF" -A "$ARCHITECTURE" \
-G "Visual Studio 17 2022" -T "v143" -DCMAKE_BUILD_TYPE=$CONFIGURATION ..
else
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH="ON" \
-DFSO_USE_VOICEREC="ON" -DFORCED_SIMD_INSTRUCTIONS="$SIMD" \
-DFSO_BUILD_QTFRED=OFF -DFSO_BUILD_TESTS=ON \
-DFSO_INSTALL_DEBUG_FILES="ON" -A "$ARCHITECTURE" \
-G "Visual Studio 17 2022" -T "v143" -DCMAKE_BUILD_TYPE=$CONFIGURATION ..
fi
- name: Compile
working-directory: ./build
env:
@@ -171,72 +176,43 @@ jobs:
CONFIGURATION: ${{ matrix.configuration }}
shell: bash
run: ./bin/$CONFIGURATION/unittests --gtest_shuffle
- name: Set artifact id
shell: bash
run: |
id=
if [ -n "${{ matrix.simd }}" ]; then
id="${{ matrix.configuration }}-${{ matrix.arch }}-${{ matrix.simd }}"
else
id="${{ matrix.configuration }}-${{ matrix.arch }}"
fi
echo "artifact_id=${id}" >> $GITHUB_ENV
- name: Upload build result
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v4
with:
name: windows-${{ env.artifact_id }}
name: windows-${{ matrix.configuration }}-${{ matrix.arch }}-${{ matrix.simd }}
path: ${{ github.workspace }}/build/install/*
windows_zip:
name: Build Windows distribution zip
needs: build_windows
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/sftp_upload:sha-ab87451
container: ghcr.io/scp-fs2open/sftp_upload:sha-748b19d
strategy:
matrix:
arch: [Win32, x64, ARM64]
simd: [SSE2, ""]
exclude:
- arch: Win32
simd: ""
- arch: x64
simd: ""
- arch: ARM64
simd: SSE2
arch: [Win32, x64]
simd: [SSE2]
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@v2
name: Checkout
with:
submodules: true
fetch-depth: '0'
ref: '${{ github.ref }}'
- name: Set workspace as safe
# This appears to be broken in current actions, so do it manually
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
- name: Set artifact id
shell: bash
run: |
id=
if [ -n "${{ matrix.simd }}" ]; then
id="${{ matrix.arch }}-${{ matrix.simd }}"
else
id="${{ matrix.arch }}"
fi
echo "artifact_id=${id}" >> $GITHUB_ENV
- name: Download Release builds
uses: actions/download-artifact@v8
uses: actions/download-artifact@v4
with:
name: windows-Release-${{ env.artifact_id }}
name: windows-Release-${{ matrix.arch }}-${{ matrix.simd }}
path: builds
- name: Download FastDebug builds
uses: actions/download-artifact@v8
uses: actions/download-artifact@v4
with:
name: windows-FastDebug-${{ env.artifact_id }}
name: windows-FastDebug-${{ matrix.arch }}-${{ matrix.simd }}
path: builds
- name: Create Distribution package
working-directory: ./builds
shell: bash
env:
ID: ${{ env.artifact_id }}
ARCH: ${{ matrix.arch }}
SIMD: ${{ matrix.simd }}
run: $GITHUB_WORKSPACE/ci/linux/create_dist_pack.sh Windows
- name: Upload result package
working-directory: ./builds
@@ -257,14 +233,32 @@ jobs:
name: Mac
runs-on: macos-latest
steps:
- uses: actions/checkout@v7
# - name: Cache Qt
# id: cache-qt-mac
# uses: actions/cache@v1
# with:
# path: ${{ github.workspace }}/../Qt
# key: ${{ runner.os }}-QtCache-${{ env.QT_VERSION }}
# - name: Install Qt
# uses: jurplel/install-qt-action@v2
# with:
# version: ${{ env.QT_VERSION }}
# dir: ${{ github.workspace }}/..
# cached: ${{ steps.cache-qt-mac.outputs.cache-hit }}
# setup-python: 'false'
# aqtversion: ==1.1.3
# py7zrversion: '==0.19.*'
- uses: actions/checkout@v1
name: Checkout
with:
submodules: true
fetch-depth: 0
- name: Set workspace as safe
# This appears to be broken in current actions, so do it manually
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
- name: Prepare Vulkan SDK
uses: humbletim/[email protected]
with:
vulkan-query-version: 1.4.304.1
vulkan-components: Vulkan-Headers, Vulkan-Loader
vulkan-use-cache: true
- name: Set up test version
shell: bash
run: |
@@ -276,10 +270,11 @@ jobs:
CONFIGURATION: ${{ matrix.configuration }}
COMPILER: ${{ matrix.compiler }}
ARCHITECTURE: ${{ matrix.arch }}
ENABLE_QTFRED: OFF
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
- name: Compile
working-directory: ./build
run: ninja all
run: LD_LIBRARY_PATH=$Qt5_DIR/lib:$LD_LIBRARY_PATH ninja all
- name: Run Tests
working-directory: ./build
env:
@@ -305,7 +300,7 @@ jobs:
# Ref: https://github.com/actions/runner-images/issues/2619
run: gtar -cvzf macos-build-${{ matrix.configuration }}-${{ matrix.arch }}.tgz *.app
- name: Upload build result
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v4
with:
name: mac-${{ matrix.configuration }}-${{ matrix.arch }}
path: ${{ github.workspace }}/build/bin/macos-build-${{ matrix.configuration }}-${{ matrix.arch }}.tgz
@@ -313,27 +308,24 @@ jobs:
name: Build Mac distribution zip
needs: build_mac
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/sftp_upload:sha-ab87451
container: ghcr.io/scp-fs2open/sftp_upload:sha-748b19d
strategy:
matrix:
arch: [x86_64, arm64]
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@v2
name: Checkout
with:
submodules: true
fetch-depth: '0'
ref: '${{ github.ref }}'
- name: Set workspace as safe
# This appears to be broken in current actions, so do it manually
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
- name: Download Release builds
uses: actions/download-artifact@v8
uses: actions/download-artifact@v4
with:
name: mac-Release-${{ matrix.arch }}
path: builds
- name: Download FastDebug builds
uses: actions/download-artifact@v8
uses: actions/download-artifact@v4
with:
name: mac-FastDebug-${{ matrix.arch }}
path: builds
+10 -52
View File
@@ -5,13 +5,15 @@ on:
branches:
- master
env:
QT_VERSION: 5.12.12
jobs:
build_linux:
strategy:
matrix:
configuration: [Debug, Release]
compiler: [gcc-9, gcc-13, clang-16]
arch: [x86_64]
cmake_options: [""]
include:
# Also include configurations that check if the code compiles without the graphics backends
@@ -23,20 +25,16 @@ jobs:
cmake_options: -DFSO_BUILD_WITH_OPENGL=OFF -DFSO_BUILD_WITH_VULKAN=OFF
name: Linux
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/linux_build:sha-ab87451
container: ghcr.io/scp-fs2open/linux_build:sha-71099c9
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@v1
name: Checkout
with:
submodules: true
- name: Set workspace as safe
# This appears to be broken in current actions, so do it manually
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
- name: ccache
uses: hendrikmuhs/ccache-action@v1.2.23
uses: hendrikmuhs/ccache-action@v1
with:
key: ${{ runner.os }}-${{ matrix.configuration }}-${{ matrix.compiler }}-${{ matrix.arch }}
max-size: 750MB
key: ${{ runner.os }}-${{ matrix.configuration }}-${{ matrix.compiler }}
- name: Configure ccache
run: |
ccache --set-config=sloppiness=pch_defines,time_macros
@@ -48,51 +46,11 @@ jobs:
COMPILER: ${{ matrix.compiler }}
JOB_CMAKE_OPTIONS: ${{ matrix.cmake_options }}
CCACHE_PATH: /usr/local/bin/ccache
ENABLE_QTFRED: ON
Qt5_DIR: /qt/${{ env.QT_VERSION }}/gcc_64/lib/cmake/Qt5
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
- name: Compile
working-directory: ./build
run: ninja -k 20 all
- name: Show CCache statistics
run: ccache --show-stats
build_mac:
strategy:
matrix:
configuration: [Debug, Release]
compiler: [clang]
arch: [x86_64, arm64]
cmake_options: [""]
name: Mac
runs-on: macos-latest
steps:
- uses: actions/checkout@v7
name: Checkout
with:
submodules: true
- name: Set workspace as safe
# This appears to be broken in current actions, so do it manually
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
- name: ccache
uses: hendrikmuhs/[email protected]
with:
key: ${{ runner.os }}-${{ matrix.configuration }}-${{ matrix.arch }}
max-size: 750MB
- name: Configure ccache
run: |
ccache --set-config=sloppiness=pch_defines,time_macros
ccache -p
- name: Configure CMake
env:
CONFIGURATION: ${{ matrix.configuration }}
COMPILER: ${{ matrix.compiler }}
ARCHITECTURE: ${{ matrix.arch }}
JOB_CMAKE_OPTIONS: ${{ matrix.cmake_options }}
CCACHE_PATH: /usr/local/bin/ccache
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
- name: Compile
working-directory: ./build
run: ninja -k 20 all
run: LD_LIBRARY_PATH=$Qt5_DIR/lib:$LD_LIBRARY_PATH ninja -k 20 all
- name: Show CCache statistics
run: ccache --show-stats
+2 -6
View File
@@ -33,7 +33,6 @@ env:
NEBULA_PASSWORD: ${{ secrets.NEBULA_PASSWORD }}
HLP_API: ${{ secrets.HLP_API }}
HLP_KEY: ${{ secrets.HLP_KEY }}
FORUM_SECRET: ${{ secrets.FORUM_SECRET }}
RELEASE_TAG: ${{ inputs.releaseTag }}
jobs:
@@ -46,13 +45,11 @@ jobs:
run: echo "github.event_name= ${{ github.event_name }}"
- name: Checkout
uses: actions/checkout@v7
uses: actions/checkout@v3
with:
fetch-depth: '0'
ref: ${{ env.RELEASE_TAG }}
- name: Set workspace as safe
# This appears to be broken in current actions, so do it manually
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
- name: Install Python dependencies
run: pip install -r ci/post/requirements.txt
@@ -70,7 +67,6 @@ jobs:
HLP_API: ${{ secrets.HLP_API }}
HLP_KEY: ${{ secrets.HLP_KEY }}
RELEASE_TAG: ${{ inputs.releaseTag }}
FORUM_SECRET: ${{ secrets.FORUM_SECRET }}
run: python ci/post/main.py release
- name: Post Builds (Manual trigger)
+90 -50
View File
@@ -2,6 +2,9 @@ name: Check a pull request
on: [pull_request]
env:
QT_VERSION: 5.12.12
jobs:
build_linux:
strategy:
@@ -17,26 +20,23 @@ jobs:
- configuration: Release
compiler: gcc-13
cmake_options: -DFSO_BUILD_WITH_OPENGL=OFF -DFSO_BUILD_WITH_VULKAN=OFF
# - configuration: Debug
# compiler: gcc-13
# cmake_options: -DFSO_BUILD_WITH_OPENGL=OFF -DFSO_BUILD_WITH_VULKAN=ON
# - configuration: Release
# compiler: gcc-13
# cmake_options: -DFSO_BUILD_WITH_OPENGL=OFF -DFSO_BUILD_WITH_VULKAN=ON
- configuration: Debug
compiler: gcc-13
cmake_options: -DFSO_BUILD_WITH_OPENGL=OFF -DFSO_BUILD_WITH_VULKAN=ON
- configuration: Release
compiler: gcc-13
cmake_options: -DFSO_BUILD_WITH_OPENGL=OFF -DFSO_BUILD_WITH_VULKAN=ON
name: Linux
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/linux_build:sha-ab87451
container: ghcr.io/scp-fs2open/linux_build:sha-71099c9
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@v1
name: Checkout
with:
submodules: true
fetch-depth: 0
- name: Set workspace as safe
# This appears to be broken in current actions, so do it manually
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
- name: ccache
uses: hendrikmuhs/ccache-action@v1.2.23
uses: hendrikmuhs/ccache-action@v1
with:
key: ${{ runner.os }}-${{ matrix.configuration }}-${{ matrix.compiler }}
save: false # Caches are created by a separate job and only restored for PRs
@@ -49,10 +49,12 @@ jobs:
COMPILER: ${{ matrix.compiler }}
JOB_CMAKE_OPTIONS: ${{ matrix.cmake_options }}
CCACHE_PATH: /usr/local/bin/ccache
ENABLE_QTFRED: ON
Qt5_DIR: /qt/${{ env.QT_VERSION }}/gcc_64/lib/cmake/Qt5
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
- name: Compile
working-directory: ./build
run: ninja -k 20 all
run: LD_LIBRARY_PATH=$Qt5_DIR/lib:$LD_LIBRARY_PATH ninja -k 20 all
- name: Run Tests
working-directory: ./build
env:
@@ -78,21 +80,44 @@ jobs:
compiler: [MSVC]
arch: [Win32, x64]
name: Windows
runs-on: windows-2025
runs-on: windows-2022
steps:
- name: Prepare Environment
run: choco install ninja
- uses: actions/checkout@v7
- uses: actions/checkout@v1
name: Checkout
with:
submodules: true
- name: Set workspace as safe
# This appears to be broken in current actions, so do it manually
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
- name: Install v143 ATL/MFC
if: matrix.compiler == 'MSVC'
shell: pwsh
run: ci/windows/install_v143_atlmfc.ps1
# - name: Cache Qt
# id: cache-qt-win
# uses: actions/cache@v1
# with:
# path: ${{ github.workspace }}/../Qt
# key: ${{ runner.os }}-${{ matrix.arch }}-QtCache-${{ env.QT_VERSION }}
# - name: Install Qt (32 bit)
# uses: jurplel/install-qt-action@v2
# if: ${{ matrix.compiler == 'MSVC' && matrix.arch == 'Win32' }}
# with:
# version: ${{ env.QT_VERSION }}
# dir: ${{ github.workspace }}/..
# arch: win32_msvc2017
# cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
# aqtversion: ==0.8
# - name: Install Qt (64 bit)
# uses: jurplel/install-qt-action@v2
# if: ${{ matrix.compiler == 'MSVC' && matrix.arch == 'x64' }}
# with:
# version: ${{ env.QT_VERSION }}
# dir: ${{ github.workspace }}/..
# arch: win64_msvc2017_64
# cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
# aqtversion: ==0.8
- name: Prepare Vulkan SDK
uses: humbletim/[email protected]
with:
vulkan-query-version: 1.4.304.1
vulkan-components: Vulkan-Headers, Vulkan-Loader
vulkan-use-cache: true
- name: Configure CMake
env:
CONFIGURATION: ${{ matrix.configuration }}
@@ -104,12 +129,23 @@ jobs:
cd build
if [ "$COMPILER" = "MinGW" ]; then
cmake -DFSO_USE_SPEECH=OFF -DFSO_FATAL_WARNINGS=ON -DFSO_USE_VOICEREC=OFF -DFSO_BUILD_TESTS=ON \
-DFSO_BUILD_FRED2=OFF -DQT_USE_PRECOMPILED=ON -DCMAKE_BUILD_TYPE=$CONFIGURATION -G "Ninja" ..
if [ "$ARCHITECTURE" = "Win32" ]; then
cmake -DFSO_USE_SPEECH="OFF" -DFSO_FATAL_WARNINGS="ON" -DFSO_USE_VOICEREC="OFF" -DFSO_BUILD_TESTS="ON" \
-DFSO_BUILD_FRED2="OFF" -DFSO_BUILD_WITH_VULKAN="OFF" -DCMAKE_BUILD_TYPE=$CONFIGURATION -G "Ninja" ..
else
cmake -DFSO_USE_SPEECH="OFF" -DFSO_FATAL_WARNINGS="ON" -DFSO_USE_VOICEREC="OFF" -DFSO_BUILD_TESTS="ON" \
-DFSO_BUILD_FRED2="OFF" -DCMAKE_BUILD_TYPE=$CONFIGURATION -G "Ninja" ..
fi
else
cmake -DFSO_USE_SPEECH=ON -DFSO_FATAL_WARNINGS=ON -DFSO_USE_VOICEREC=OFF -DFSO_BUILD_TESTS=ON \
-DFORCED_SIMD_INSTRUCTIONS=SSE2 -G "Visual Studio 18 2026" -T "v143" -A "$ARCHITECTURE" \
-DQT_USE_PRECOMPILED=ON -DCMAKE_BUILD_TYPE=$CONFIGURATION ..
if [ "$ARCHITECTURE" = "Win32" ]; then
cmake -DFSO_USE_SPEECH="ON" -DFSO_FATAL_WARNINGS="ON" -DFSO_USE_VOICEREC="OFF" -DFSO_BUILD_TESTS="ON" \
-DFORCED_SIMD_INSTRUCTIONS=SSE2 -DFSO_BUILD_FRED2="ON" -DFSO_BUILD_WITH_VULKAN="OFF" -G "Visual Studio 17 2022" \
-DFSO_BUILD_QTFRED=OFF -T "v143" -A "$ARCHITECTURE" -DCMAKE_BUILD_TYPE=$CONFIGURATION ..
else
cmake -DFSO_USE_SPEECH="ON" -DFSO_FATAL_WARNINGS="ON" -DFSO_USE_VOICEREC="OFF" -DFSO_BUILD_TESTS="ON" \
-DFORCED_SIMD_INSTRUCTIONS=SSE2 -DFSO_BUILD_FRED2="ON" -G "Visual Studio 17 2022" \
-DFSO_BUILD_QTFRED=OFF -T "v143" -A "$ARCHITECTURE" -DCMAKE_BUILD_TYPE=$CONFIGURATION ..
fi
fi
- name: Compile
working-directory: ./build
@@ -146,32 +182,48 @@ jobs:
name: Mac
runs-on: macos-latest
steps:
- uses: actions/checkout@v7
# - name: Cache Qt
# id: cache-qt-mac
# uses: actions/cache@v1
# with:
# path: ${{ github.workspace }}/../Qt
# key: ${{ runner.os }}-QtCache-${{ env.QT_VERSION }}
# - name: Install Qt
# uses: jurplel/install-qt-action@v2
# with:
# version: ${{ env.QT_VERSION }}
# dir: ${{ github.workspace }}/..
# cached: ${{ steps.cache-qt-mac.outputs.cache-hit }}
# setup-python: 'false'
# aqtversion: ==1.1.3
# py7zrversion: '==0.19.*'
- uses: actions/checkout@v1
name: Checkout
with:
submodules: true
fetch-depth: 0
- name: Set workspace as safe
# This appears to be broken in current actions, so do it manually
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
- name: ccache
uses: hendrikmuhs/ccache-action@v1.2.23
uses: hendrikmuhs/ccache-action@v1
with:
key: ${{ runner.os }}-${{ matrix.configuration }}-${{ matrix.compiler }}-${{ matrix.arch }}
save: false # Caches are created by a separate job and only restored for PRs
- name: Configure ccache
run: ccache --set-config=sloppiness=pch_defines,time_macros
- name: Prepare Vulkan SDK
uses: humbletim/[email protected]
with:
vulkan-query-version: 1.4.304.1
vulkan-components: Vulkan-Headers, Vulkan-Loader
vulkan-use-cache: true
- name: Configure CMake
env:
CONFIGURATION: ${{ matrix.configuration }}
COMPILER: ${{ matrix.compiler }}
ARCHITECTURE: ${{ matrix.arch }}
JOB_CMAKE_OPTIONS: ${{ matrix.cmake_options }}
CCACHE_PATH: /usr/local/bin/ccache
ENABLE_QTFRED: OFF
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
- name: Compile
working-directory: ./build
run: ninja all
run: LD_LIBRARY_PATH=$Qt5_DIR/lib:$LD_LIBRARY_PATH ninja all
- name: Run Tests
working-directory: ./build
env:
@@ -179,24 +231,12 @@ jobs:
ARCH: ${{ matrix.arch }}
XDG_RUNTIME_DIR: /root
run: $GITHUB_WORKSPACE/ci/linux/run_tests.sh
- name: Show CCache statistics
run: ccache --show-stats
- name: Install clang-tidy
# macOS runners don't ship clang-tidy; pin to the same version as the Linux
# container's clang-tidy-16 for consistent diagnostics. pyyaml is required
# too: clang-tidy-diff.py only accepts -export-fixes when it can import yaml.
# --break-system-packages is required since the runner's Homebrew Python
# is externally managed (PEP 668); the runner is ephemeral so this is safe.
if: startsWith(matrix.compiler, 'clang')
run: pip3 install --break-system-packages clang-tidy==16.0.4 pyyaml
- name: Run Clang Tidy
# Clang-tidy reuses the precompiled headers so this only makes sense for the clang compilers
if: startsWith(matrix.compiler, 'clang')
env:
CLANG_TIDY_BINARY: clang-tidy
if: startsWith(matrix.compiler, 'clang-')
run: $GITHUB_WORKSPACE/ci/linux/clang_tidy.sh ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }}
- name: Process clang-tidy warnings
if: startsWith(matrix.compiler, 'clang')
if: startsWith(matrix.compiler, 'clang-')
uses: asarium/clang-tidy-action@v1
with:
fixesFile: clang-fixes.yaml
+4 -5
View File
@@ -11,6 +11,7 @@ on:
- cron: "5 0 * * 5" # Run once per a week on Friday morning (midnight UTC, 4 AM EST), to avoid Coverity's submission limits
env:
QT_VERSION: 5.12.12
coverity_email: [email protected]
coverity_token: ${{ secrets.COVERITY_TOKEN }}
@@ -19,7 +20,7 @@ jobs:
name: Build FSO With Coverity Wrapper
if: github.repository == 'scp-fs2open/fs2open.github.com'
runs-on: ${{ matrix.config.os }}
container: ghcr.io/scp-fs2open/linux_build:sha-ab87451
container: ghcr.io/scp-fs2open/linux_build:sha-71099c9
strategy:
fail-fast: false
matrix:
@@ -28,12 +29,9 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v7
uses: actions/checkout@v1
with:
submodules: recursive # `true` to checkout submodules, `recursive` to recursively checkout submodules
- name: Set workspace as safe
# This appears to be broken in current actions, so do it manually
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
# pipe results of wget to a log file because it's very verbose and rarely fails
- name: Install Coverity
@@ -51,6 +49,7 @@ jobs:
env:
CONFIGURATION: Release
COMPILER: gcc-9
ENABLE_QTFRED: OFF
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
- name: Build FSO with Coverity Wrapper
-5
View File
@@ -262,8 +262,3 @@ CMakePresets.json
!/docker/build
CMakeFiles/cmake.check_cache
CMakeCache.txt
# Written by the unittests binary at runtime
test/test_data/**/*_settings.ini
test/test_data/data/players/presets/asdf.json
test/test_data/pilotfile/data/asdf.hdp
+3
View File
@@ -1,3 +1,6 @@
[submodule "cmake/external/rpavlik-cmake-modules"]
path = cmake/external/rpavlik-cmake-modules
url = https://github.com/rpavlik/cmake-modules.git
[submodule "lib/libRocket"]
path = lib/libRocket
url = https://github.com/scp-fs2open/libRocket.git
+29 -66
View File
@@ -29,57 +29,33 @@ ENDIF(NOT DEFINED CMAKE_INSTALL_PREFIX)
SET(TARGET_COPY_FILES "" CACHE INTERNAL "" FORCE)
SET(TARGET_COPY_DIRS "" CACHE INTERNAL "" FORCE)
get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
# Override standard CMake configurations
set(FSO_BUILD_TYPES Debug Release FastDebug)
if(is_multi_config)
set(CMAKE_CONFIGURATION_TYPES "${FSO_BUILD_TYPES}" CACHE STRING "Configuration types" FORCE)
elseif(NOT CMAKE_BUILD_TYPE)
### Define options and editable variables in the section below:
# This is only needed for single configuration generators so don't annoy others
if(NOT CMAKE_BUILD_TYPE AND NOT DEFINED CMAKE_CONFIGURATION_TYPES)
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Default build configuration used." FORCE)
message(WARNING "CMAKE_BUILD_TYPE was not specified, defaulting to Release configuration.")
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "${FSO_BUILD_TYPES}")
endif()
endif(NOT CMAKE_BUILD_TYPE AND NOT DEFINED CMAKE_CONFIGURATION_TYPES)
# Override standard CMake configurations
set(CMAKE_CONFIGURATION_TYPES Debug Release FastDebug CACHE STRING "Available configurations" FORCE)
set(FSO_LANGUAGES C CXX)
if(APPLE)
set(FSO_LANGUAGES ${FSO_LANGUAGES} OBJC OBJCXX)
# 10.15 for c++17 std::filesystem
# NOTE: this must be set *before* the project() call to work properly!!
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "macOS deployment target")
# fix all targets in scheme (so it's not just qtfred)
set(CMAKE_XCODE_GENERATE_SCHEME TRUE)
endif()
PROJECT(FS2_Open LANGUAGES ${FSO_LANGUAGES})
if (ANDROID)
message(STATUS "Building for Android (NDK)")
set(FSO_BUILD_INCLUDED_LIBS ON CACHE BOOL "" FORCE)
set(USING_PREBUILT_LIBS ON CACHE BOOL "" FORCE)
set(SDL3_USE_PRECOMPILED ON CACHE BOOL "" FORCE)
set(OPENAL_USE_PRECOMPILED ON CACHE BOOL "" FORCE)
set(USING_PREBUILT_VULKAN ON CACHE BOOL "" FORCE)
endif()
# Check if the external modules exists
IF(NOT IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/lib/libRocket/Build")
IF(NOT IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/cmake/external/rpavlik-cmake-modules/launcher-templates")
message(FATAL_ERROR "External submodules could not be found. Please make sure you have updated your submodules.")
endif()
LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/finder")
# this must be set before include(toolchain)
if(WIN32 AND CMAKE_SIZEOF_VOID_P EQUAL 4)
set(FSO_BUILD_QTFRED OFF CACHE INTERNAL "" FORCE)
else()
OPTION(FSO_BUILD_QTFRED "Build qtFRED2 binary" ON)
endif()
LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/external/rpavlik-cmake-modules")
LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/external/cotire")
INCLUDE(globals)
INCLUDE(toolchain)
@@ -98,11 +74,9 @@ IF(RESET_INSTALL_PREFIX)
ENDIF(NOT $ENV{FS2PATH} STREQUAL "")
ENDIF(RESET_INSTALL_PREFIX)
IF(WIN32 OR APPLE OR ANDROID OR CMAKE_SYSTEM_NAME STREQUAL "Linux")
IF(WIN32 OR APPLE)
OPTION(FSO_USE_SPEECH "Use text-to-speach libraries" ON)
ELSE()
OPTION(FSO_USE_SPEECH "Use text-to-speach libraries" OFF)
ENDIF()
ENDIF(WIN32 OR APPLE)
IF (WIN32)
OPTION(FSO_USE_VOICEREC "Enable voice recognition support" ON)
@@ -118,8 +92,10 @@ OPTION(FSO_BUILD_TESTS "Build unit tests" OFF)
OPTION(FSO_DEVELOPMENT_MODE "Generate binaries in development mode, only use if you know what you're doing!" OFF)
IF(WIN32 OR APPLE OR ANDROID)
# On windows, mac and android the default should be to always build the included libraries
OPTION(FSO_BUILD_QTFRED "Build qtFRED2 binary" OFF)
IF(WIN32 OR APPLE)
# On windows and mac the default should be to always build the included libraries
SET(FSO_BUILD_INCLUDED_LIBS_DEFAULT ON)
ELSE()
SET(FSO_BUILD_INCLUDED_LIBS_DEFAULT OFF)
@@ -139,6 +115,8 @@ SET(FSO_RUN_ARGUMENTS "" CACHE STRING "Additional arguments passed to a generate
option(FSO_INSTALL_DEBUG_FILES "Install some debug files (currently only PDB files on windows)" OFF)
option(ENABLE_COTIRE "Enable cotire for faster compilation. Enabled by default." ON)
option(FSO_RELEASE_LOGGING "Enable logging output for release builds" OFF)
OPTION(FSO_BUILD_WITH_FFMPEG "Enable the usage of FFmpeg for sound and custscenes" ON)
@@ -147,25 +125,10 @@ OPTION(FSO_BUILD_WITH_DISCORD "Build with Discord support" ON)
OPTION(FSO_BUILD_WITH_OPENGL "Enable compilation of the OpenGL renderer" ON)
OPTION(FSO_BUILD_WITH_OPENGL_DEBUG "Enables debug option for OpenGL" OFF)
OPTION(FSO_BUILD_WITH_OPENGL_ES "When building OpenGL, use OpenGL ES compatibility layer" OFF)
OPTION(FSO_BUILD_WITH_VULKAN "Enable compilation of the Vulkan renderer" ON)
OPTION(FSO_BUILD_WITH_VULKAN "Enable compilation of the Vulkan renderer" OFF)
if(NOT FSO_BUILD_WITH_OPENGL AND FSO_BUILD_WITH_OPENGL_ES)
# Disable GLES if not building with OpenGL
set(FSO_BUILD_WITH_OPENGL_ES OFF CACHE BOOL "" FORCE)
endif()
if(FSO_BUILD_WITH_OPENGL_ES)
add_definitions(-DUSE_OPENGL_ES)
IF(FSO_BUILD_WITH_OPENXR)
MESSAGE(WARNING "FSO_BUILD_WITH_OPENXR is ON. But not supported on OpenGL ES for now - setting to OFF.")
SET(FSO_BUILD_WITH_OPENXR OFF CACHE BOOL "" FORCE)
endif()
endif()
IF(NOT APPLE AND NOT FSO_BUILD_WITH_OPENGL_ES)
IF(NOT APPLE)
SET(OPENXR_BUILD_DEFAULT ON)
ELSE()
SET(OPENXR_BUILD_DEFAULT OFF)
@@ -187,12 +150,12 @@ MARK_AS_ADVANCED(FORCE FSO_USE_LUAJIT)
MARK_AS_ADVANCED(FORCE FSO_DEVELOPMENT_MODE)
MARK_AS_ADVANCED(FORCE FSO_FATAL_WARNINGS)
mark_as_advanced(FORCE FSO_INSTALL_DEBUG_FILES)
mark_as_advanced(FORCE ENABLE_COTIRE)
mark_as_advanced(FORCE FSO_RELEASE_LOGGING)
mark_as_advanced(FORCE FSO_BUILD_WITH_FFMPEG)
mark_as_advanced(FORCE FSO_BUILD_WITH_DISCORD)
mark_as_advanced(FORCE FSO_BUILD_WITH_OPENGL)
mark_as_advanced(FORCE FSO_BUILD_WITH_OPENGL_DEBUG)
mark_as_advanced(FORCE FSO_BUILD_WITH_OPENGL_ES)
mark_as_advanced(FORCE FSO_BUILD_WITH_VULKAN)
mark_as_advanced(FORCE FSO_BUILD_WITH_OPENXR)
mark_as_advanced(FORCE FSO_BUILD_WITH_OPENXR_DEBUG)
@@ -207,19 +170,18 @@ SET(GENERATED_SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/generated_source)
include(generateHeaders)
if(FSO_BUILD_APPIMAGE)
SET(BINARY_DESTINATION "bin")
SET(LIBRAY_DESTINATION "lib")
include(appimage)
endif()
include(clang-tidy)
include(CheckIPOSupported)
check_ipo_supported(RESULT LTO_AVAILABLE)
if (FSO_USE_LTO AND LTO_AVAILABLE)
if (CMAKE_BUILD_TYPE STREQUAL "Release" AND FSO_USE_LTO AND LTO_AVAILABLE)
set(CMAKE_POLICY_DEFAULT_CMP0069 NEW)
message("Enabled LTO for Release builds")
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE)
endif (FSO_USE_LTO AND LTO_AVAILABLE)
message("Enabled LTO")
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
endif (CMAKE_BUILD_TYPE STREQUAL "Release" AND FSO_USE_LTO AND LTO_AVAILABLE)
# This includes source code for some tools, either used in the build or also for something else
ADD_SUBDIRECTORY(tools)
@@ -264,7 +226,9 @@ include(package)
include(doxygen)
# Print used options to log
message(STATUS "Using text to speech: ${FSO_USE_SPEECH}")
IF(WIN32 OR APPLE)
message(STATUS "Using text to speech: ${FSO_USE_SPEECH}")
ENDIF()
IF (WIN32)
message(STATUS "Using voice recogition: ${FSO_USE_VOICEREC}")
message(STATUS "Building FRED2: ${FSO_BUILD_FRED2}")
@@ -278,6 +242,5 @@ message(STATUS "Release logging: ${FSO_RELEASE_LOGGING}")
message(STATUS "With FFmpeg: ${FSO_BUILD_WITH_FFMPEG}")
message(STATUS "With Discord: ${FSO_BUILD_WITH_DISCORD}")
message(STATUS "With OpenGL: ${FSO_BUILD_WITH_OPENGL}")
message(STATUS "With OpenGL ES: ${FSO_BUILD_WITH_OPENGL_ES}")
message(STATUS "With Vulkan: ${FSO_BUILD_WITH_VULKAN}")
message(STATUS "With OpenXR: ${FSO_BUILD_WITH_OPENXR}")
+4 -7
View File
@@ -18,16 +18,13 @@ fi
# branch
BASE_COMMIT=$(git merge-base $1 $2)
# Allow the caller to override the clang-tidy binary and job count, since neither
# /usr/bin/clang-tidy-16 nor nproc are available outside the Linux CI container
# (e.g. macOS runners install clang-tidy via pip and use sysctl for core count).
CLANG_TIDY_BINARY="${CLANG_TIDY_BINARY:-/usr/bin/clang-tidy-16}"
NUM_JOBS="${NUM_JOBS:-$( (command -v nproc >/dev/null 2>&1 && nproc) || sysctl -n hw.ncpu )}"
# Note: Manually passing in the Vulkan flags that are normally provided by cmake (but are not so, here), to ensure
# that the source files are checked with the actual configuration used.
echo "Running clang-tidy on changed files"
git diff -U0 --no-color "$BASE_COMMIT..$2" | \
$HERE/clang-tidy-diff.py -path "$(pwd)/build" -p1 \
-extra-arg="-DWITH_VULKAN" \
-extra-arg="-DVULKAN_HPP_DISPATCH_LOADER_DYNAMIC=1" \
-extra-arg="-DVK_NO_PROTOTYPES" \
-regex '(code(?!((\/graphics\/shaders\/compiled)|(\/globalincs\/windebug)|(\/def_files\/data)))|freespace2|qtfred|test\/src|build|tools)\/.*\.(cpp|h)' \
-clang-tidy-binary "$CLANG_TIDY_BINARY" -j"$NUM_JOBS" -export-fixes "$(pwd)/clang-fixes.yaml"
-clang-tidy-binary /usr/bin/clang-tidy-16 -j$(nproc) -export-fixes "$(pwd)/clang-fixes.yaml"
+9 -24
View File
@@ -13,32 +13,21 @@ if [ "$COMPILER" = "clang-16" ]; then
export CXX=clang++-16
fi
LD_LIBRARY_PATH=$Qt5_DIR/lib:$LD_LIBRARY_PATH
if [ "$RUNNER_OS" = "macOS" ]; then
CXXFLAGS="-mtune=generic -pipe -Wno-unknown-pragmas"
CFLAGS="-mtune=generic -pipe -Wno-unknown-pragmas"
# TODO: Vulkan support is disabled on MacOS due to issues with the test suite not linking correctly
PLATFORM_CMAKE_OPTIONS="-DFSO_BUILD_WITH_VULKAN=OFF"
export CMAKE_OSX_ARCHITECTURES="$ARCHITECTURE"
else
PLATFORM_CMAKE_OPTIONS="-DFSO_BUILD_APPIMAGE=ON -DFORCED_SIMD_INSTRUCTIONS=SSE2"
# Optionally use static libstdc++/libc++ on Linux, but default to off
# (Issue #5571 enabled it as a fix for 20.04 compatibility, but we've moved to 22.04)
PLATFORM_CMAKE_OPTIONS="$PLATFORM_CMAKE_OPTIONS -DUSE_STATIC_LIBCXX=${USE_STATIC_LIBCXX:-OFF}"
PLATFORM_CMAKE_OPTIONS="-DFSO_BUILD_APPIMAGE=ON -DFORCED_SIMD_INSTRUCTIONS=SSE2 -DUSE_STATIC_LIBCXX=ON"
fi
CMAKE_OPTIONS="$JOB_CMAKE_OPTIONS"
if [[ "$COMPILER" =~ ^clang.*$ ]]; then
# Default to allowing system standard c++ library be used. On Linux, which
# typically uses libstdc++ by default, using libc++ causes a conflict with
# Qt6 libs. So an error/warning is in place to catch that case when QtFRED
# is enabled.
CMAKE_OPTIONS="$CMAKE_OPTIONS -DCLANG_USE_LIBCXX=${CLANG_USE_LIBCXX:-OFF}"
fi
if [ ! "$CCACHE_PATH" = "" ] && [ ! -x "$CCACHE_PATH" ]; then
# The configured path doesn't exist on this runner (e.g. macOS runners on Apple
# Silicon hosts install Homebrew under /opt/homebrew instead of /usr/local),
# so fall back to whatever ccache is actually on PATH.
CCACHE_PATH="$(command -v ccache || true)"
CMAKE_OPTIONS="$CMAKE_OPTIONS -DCLANG_USE_LIBCXX=ON"
# force clang to silently allow -static-libstdc++ flag
fi
if [ ! "$CCACHE_PATH" = "" ]; then
@@ -46,10 +35,6 @@ if [ ! "$CCACHE_PATH" = "" ]; then
CMAKE_OPTIONS="$CMAKE_OPTIONS -DCMAKE_C_COMPILER_LAUNCHER=$CCACHE_PATH -DCMAKE_CXX_COMPILER_LAUNCHER=$CCACHE_PATH"
fi
if [ -n "${ENABLE_QTFRED:-}" ]; then
CMAKE_OPTIONS="$CMAKE_OPTIONS -DFSO_BUILD_QTFRED=${ENABLE_QTFRED}"
fi
mkdir build
cd build
@@ -65,6 +50,6 @@ fi
# we have some build rules that do not play nice with parallel invocation and that fixes these issues
cmake -G Ninja -DFSO_FATAL_WARNINGS=ON -DCMAKE_EXPORT_COMPILE_COMMANDS=ON $CMAKE_OPTIONS $PLATFORM_CMAKE_OPTIONS \
-DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DCMAKE_BUILD_TYPE=$CONFIGURATION -DQT_USE_PRECOMPILED=ON \
-DFFMPEG_USE_PRECOMPILED=ON -DFSO_BUILD_TESTS=ON -DFSO_BUILD_INCLUDED_LIBS=ON \
-DCMAKE_JOB_POOLS=link=1 -DCMAKE_JOB_POOL_LINK=link ..
-DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DCMAKE_BUILD_TYPE=$CONFIGURATION \
-DFFMPEG_USE_PRECOMPILED=ON -DFSO_BUILD_TESTS=ON -DFSO_BUILD_INCLUDED_LIBS=ON -DFSO_BUILD_QTFRED=${ENABLE_QTFRED:-OFF} \
-DSHADERS_ENABLE_COMPILATION=ON -DCMAKE_JOB_POOLS=link=1 -DCMAKE_JOB_POOL_LINK=link ..
+8 -8
View File
@@ -14,17 +14,17 @@ if [ "$OS" = "Linux" ]; then
echo "package_name=$(get_package_name)-builds-Linux-$ARCH.tar.gz" >> $GITHUB_OUTPUT
echo "package_mime=$(file -b --mime-type "$(pwd)/$(get_package_name)-builds-Linux-$ARCH.tar.gz")" >> $GITHUB_OUTPUT
elif [ "$OS" = "Windows" ]; then
7z a -xr'!*.pdb' "$(get_package_name)-builds-$ID.zip" "*"
7z a -xr'!*.pdb' "$(get_package_name)-builds-$ARCH-$SIMD.zip" "*"
echo "package_path=$(pwd)/$(get_package_name)-builds-$ID.zip" >> $GITHUB_OUTPUT
echo "package_name=$(get_package_name)-builds-$ID.zip" >> $GITHUB_OUTPUT
echo "package_mime=$(file -b --mime-type "$(pwd)/$(get_package_name)-builds-$ID.zip")" >> $GITHUB_OUTPUT
echo "package_path=$(pwd)/$(get_package_name)-builds-$ARCH-$SIMD.zip" >> $GITHUB_OUTPUT
echo "package_name=$(get_package_name)-builds-$ARCH-$SIMD.zip" >> $GITHUB_OUTPUT
echo "package_mime=$(file -b --mime-type "$(pwd)/$(get_package_name)-builds-$ARCH-$SIMD.zip")" >> $GITHUB_OUTPUT
7z a "$(get_package_name)-debug-$ID.7z" "*.pdb"
7z a "$(get_package_name)-debug-$ARCH-$SIMD.7z" "*.pdb"
echo "debug_path=$(pwd)/$(get_package_name)-debug-$ID.7z" >> $GITHUB_OUTPUT
echo "debug_name=$(get_package_name)-debug-$ID.7z" >> $GITHUB_OUTPUT
echo "debug_mime=$(file -b --mime-type "$(pwd)/$(get_package_name)-debug-$ID.7z")" >> $GITHUB_OUTPUT
echo "debug_path=$(pwd)/$(get_package_name)-debug-$ARCH-$SIMD.7z" >> $GITHUB_OUTPUT
echo "debug_name=$(get_package_name)-debug-$ARCH-$SIMD.7z" >> $GITHUB_OUTPUT
echo "debug_mime=$(file -b --mime-type "$(pwd)/$(get_package_name)-debug-$ARCH-$SIMD.7z")" >> $GITHUB_OUTPUT
elif [ "$OS" = "Mac" ]; then
tar -cvzf "$(get_package_name)-builds-Mac-$ARCH.tar.gz" *.app
+4 -39
View File
@@ -2,48 +2,13 @@
INSTALL_FOLDER=$1
# safety check
if [ ! -d bin -o ! -f cmake_install.cmake ]; then
echo "ERROR! This script must be run from within the build root!"
exit 1
fi
if [ ! -x "$(which wget)" ]; then
echo "ERROR! Required utility is not available: wget"
exit 1
fi
# install newest appimagetool if it's not already available
if [ ! -x ./bin/appimagetool ]; then
APPIMAGE_TOOL_URL="https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-$(uname -m).AppImage"
wget -O ./bin/appimagetool "$APPIMAGE_TOOL_URL" || { echo "ERROR! Failed to get appimagetool!" && exit 1; }
chmod +x ./bin/appimagetool
fi
# This shouldn't be needed with newer runtimes, but they still generate an
# error if fusermount is missing even though it works. So to skip error msg
# and have max compatibility with runtimes and containers we'll use it.
export APPIMAGE_EXTRACT_AND_RUN=1
# Install Freespace2 targets
cmake -DCMAKE_INSTALL_PREFIX=$INSTALL_FOLDER/Freespace2 -DCOMPONENT=Unspecified -P cmake_install.cmake
cmake -DCMAKE_INSTALL_PREFIX=$INSTALL_FOLDER/Freespace2 -DCOMPONENT=Freespace2 -P cmake_install.cmake
cmake -DCMAKE_INSTALL_PREFIX=$INSTALL_FOLDER -DCOMPONENT=Unspecified -P cmake_install.cmake
cmake -DCMAKE_INSTALL_PREFIX=$INSTALL_FOLDER -DCOMPONENT=Freespace2 -P cmake_install.cmake
# We need to be a bit creative for determining the AppImage name since we don't want to hard-code the name
FILENAME="$(find $INSTALL_FOLDER/Freespace2/bin -maxdepth 1 -name 'fs2_open_*' -type f -executable -printf "%f\n").AppImage"
./bin/appimagetool -n "$INSTALL_FOLDER/Freespace2" "$INSTALL_FOLDER/$FILENAME"
FILENAME="$(find $INSTALL_FOLDER/bin -name 'fs2_open_*' -type f -printf "%f\n").AppImage"
appimagetool -n $INSTALL_FOLDER "$INSTALL_FOLDER/$FILENAME"
chmod +x "$INSTALL_FOLDER/$FILENAME"
# Maybe install qtFRED targets
if [ -f qtfred/cmake_install.cmake ]; then
cmake -DCMAKE_INSTALL_PREFIX=$INSTALL_FOLDER/qtFRED -DCOMPONENT=Unspecified -P cmake_install.cmake
cmake -DCMAKE_INSTALL_PREFIX=$INSTALL_FOLDER/qtFRED -DCOMPONENT=qtFRED -P cmake_install.cmake
# We need to be a bit creative for determining the AppImage name since we don't want to hard-code the name
FILENAME="$(find $INSTALL_FOLDER/qtFRED/bin -maxdepth 1 -iname 'qtfred_*' -type f -executable -printf "%f\n").AppImage"
./bin/appimagetool -n "$INSTALL_FOLDER/qtFRED" "$INSTALL_FOLDER/$FILENAME"
chmod +x "$INSTALL_FOLDER/$FILENAME"
fi
ls -al $INSTALL_FOLDER
+1 -9
View File
@@ -5,14 +5,6 @@ HERE=$(dirname "$SCRIPT")
export LD_LIBRARY_PATH=$(pwd)/bin/lib:$LD_LIBRARY_PATH
# The unit tests never open a window, but a few of them reach code that brings SDL's video
# subsystem up (os_init() and resolution_default(), the latter via gr_init()). Left to itself SDL
# probes its real backends and dlopens libX11, which leaks a handful of blocks per init/quit cycle
# that SDL_QuitSubSystem() does not reclaim -- those are the "definitely lost" contexts memcheck
# fails the Debug legs on. Pinning the dummy driver skips the probing entirely, so the leaks never
# happen, and it makes the tests behave the same way whether or not the runner has a display.
export SDL_VIDEODRIVER=dummy
# if on mac and building for architecture that doesn't match host
# then unittests will fail so we just need to skip it (for now)
if [ "$RUNNER_OS" = "macOS" ] && [ "$ARCH" != "$(uname -m)" ]; then
@@ -20,7 +12,7 @@ if [ "$RUNNER_OS" = "macOS" ] && [ "$ARCH" != "$(uname -m)" ]; then
exit 0
fi
if [ "$CONFIGURATION" = "Debug" ] && [[ "$RUNNER_OS" != "macOS" ]] ; then
if [ "$CONFIGURATION" = "Debug"] && [[ "$RUNNER_OS" != "macOS" ]] ; then
valgrind --leak-check=full --error-exitcode=1 --gen-suppressions=all \
--suppressions="$HERE/valgrind.supp" ./bin/unittests --gtest_shuffle
else
+47 -23
View File
@@ -8,6 +8,24 @@
obj:*
obj:*
}
{
Travis memleak
Memcheck:Leak
match-leak-kinds: definite
fun:malloc
fun:_dl_signal_error
fun:_dl_open
fun:dlopen_doit
fun:_dl_catch_error
fun:_dlerror_run
fun:dlopen@@GLIBC_2.2.5
obj:/usr/lib/x86_64-linux-gnu/libmirclient.so.7
fun:call_init.part.0
fun:call_init
fun:_dl_init
fun:dl_open_worker
fun:_dl_catch_error
}
{
CLang Lua unitialized value error
Memcheck:Cond
@@ -109,31 +127,37 @@
fun:_ZN7testing8internal35HandleExceptionsInMethodIfSupportedINS_4TestEvEET0_PT_MS4_FS3_vEPKc
}
{
SDL_Init one-time internal allocation via os_init
<insert_a_suppression_name_here>
Memcheck:Leak
match-leak-kinds: definite
fun:malloc
obj:*
obj:*
obj:*
obj:*
fun:_Z7os_initPKcS0_S0_
fun:_ZN4test13FSTestFixture5SetUpEv
}
# Kept only as a backstop for running memcheck by hand. run_tests.sh pins SDL_VIDEODRIVER=dummy, so
# the X11 backend is never created there; this block also cannot match the prebuilt libSDL3 anymore,
# since that library is now stripped and X11_CreateDevice is a static symbol.
{
SDL3 X11 video backend internal allocations, not freed by SDL_VideoQuit
Memcheck:Leak
match-leak-kinds: definite,possible
...
fun:X11_CreateDevice
}
{
glibc loader bookkeeping and library constructor allocations retained across dlopen
Memcheck:Leak
match-leak-kinds: definite,possible
...
fun:_dl_signal_error
fun:_dl_open
fun:dlopen_doit
fun:_dl_catch_error
fun:_dlerror_run
fun:dlopen@@GLIBC_2.2.5
obj:*
obj:*
fun:call_init.part.0
fun:call_init
fun:_dl_init
fun:dl_open_worker
}
{
dlopen leak
Memcheck:Leak
match-leak-kinds: definite
fun:malloc
fun:_dl_exception_create
fun:_dl_signal_error
fun:_dl_map_object
fun:dl_open_worker
fun:_dl_catch_exception
fun:_dl_open
fun:dlopen_doit
fun:_dl_catch_exception
fun:_dl_catch_error
fun:_dlerror_run
fun:dlopen@@GLIBC_2.2.5
}
+1 -5
View File
@@ -149,8 +149,6 @@ def get_release_files(tag_name, config) -> Tuple[List[ReleaseFile], Dict[str, So
# x64 is the Visual Studio name but for consistency we need Win64
if platform == "x64":
platform = "Win64"
elif platform == "ARM64":
platform = "WinARM64"
binary_files.append(ReleaseFile(name, url, platform, group_match.group(3)))
else:
@@ -215,8 +213,6 @@ def get_ftp_files(build_type, tag_name, config) -> List[ReleaseFile] :
# x64 is the name Visual Studio uses but Win64 works better for us since that gets displayed in the nightly post
if "x64" in group_match:
group_match = group_match.replace("x64", "Win64")
elif "ARM64" in group_match:
group_match = group_match.replace("ARM64", "WinARM64")
# construct the download URL list for all mirrors. The first listed ftp location is taken as the Primary
for mirror in config["ftp"]["mirrors"]:
@@ -229,4 +225,4 @@ def get_ftp_files(build_type, tag_name, config) -> List[ReleaseFile] :
# Form the List[ReleaseFile] list with the download URL links
out_data.append(ReleaseFile(file, primary_url, group_match, None, mirrors))
return out_data
return out_data
+6 -9
View File
@@ -1,4 +1,3 @@
import os
from typing import List
import requests
@@ -34,14 +33,12 @@ class ForumAPI:
print("Post failed! No API or API_KEY given!")
return
resp = requests.post(self.config["hlp"]["api"],
headers={"X-HLP-Bot": os.environ["FORUM_SECRET"]},
data={
"api_key": self.config["hlp"]["key"],
"board": str(board),
"subject": title,
"body": content
})
resp = requests.post(self.config["hlp"]["api"], data={
"api_key": self.config["hlp"]["key"],
"board": str(board),
"subject": title,
"body": content
})
if resp.status_code != 200:
print("Post failed! Response: %s" %resp.text)
-5
View File
@@ -18,7 +18,6 @@
# Credentials into hard-light.net for forum post
# HLP_API:
# HLP_KEY:
# FORUM_SECRET:
# LINUX_RESULT: bool, if the linux builds were successfully uploaded
# WINDOWS_RESULT: bool, if the windows builds were successfully uploaded
@@ -125,10 +124,6 @@ def get_source_version(date_version: datetime, tag_name: str) -> semantic_versio
def main():
if "FORUM_SECRET" not in os.environ or not os.environ["FORUM_SECRET"]:
print(" ERROR: FORUM_SECRET environment variable not set")
sys.exit(1)
os.chdir(os.path.dirname(__file__)) # Change working directory to this file's directory
# Aggregate configuration data in a dictionary
+2 -6
View File
@@ -15,7 +15,6 @@ WIN32_SSE2_KEY = "Win32-SSE2"
WIN64_SSE2_KEY = "Win64-SSE2"
WIN32_AVX_KEY = "Win32-AVX"
WIN64_AVX_KEY = "Win64-AVX"
WINARM64_KEY = "WinARM64"
metadata = {
'type': 'engine',
@@ -43,8 +42,7 @@ platforms = {
WIN32_SSE2_KEY: 'windows',
WIN64_SSE2_KEY: 'windows',
WIN32_AVX_KEY: 'windows',
WIN64_AVX_KEY: 'windows',
WINARM64_KEY: 'windows',
WIN64_AVX_KEY: 'windows'
}
envs = {
@@ -55,8 +53,7 @@ envs = {
WIN32_SSE2_KEY: 'windows',
WIN64_SSE2_KEY: 'windows && x86_64',
WIN32_AVX_KEY: 'windows && avx',
WIN64_AVX_KEY: 'windows && avx && x86_64',
WINARM64_KEY: 'windows && arm64'
WIN64_AVX_KEY: 'windows && avx && x86_64'
}
subdirs = {
@@ -194,7 +191,6 @@ def render_nebula_release(version, stability, files, config):
"sse2": "SSE2" in fn or "AVX" in fn, # AVX implies SSE2
"avx": "AVX" in fn, # This conveniently also covers the AVX2 case since AVX2 implies AVX
"avx2": "AVX2" in fn,
"arm64": "arm64" in fn,
}
pkg['executables'].append({
+1 -3
View File
@@ -22,7 +22,7 @@ Windows: [url=http://scp.fsmods.net/builds/Launcher55g.zip]Launcher 5.5g[/url]
OS X: Soulstorm's [url=https://www.hard-light.net/forums/index.php/topic,51391.0.html]OS X Launcher 3.0[/url]
Linux: [url=https://www.hard-light.net/forums/index.php/topic,53206.0.html]YAL[/url] or [url=https://www.hard-light.net/wiki/index.php/Fs2_open_on_Linux/Graphics_Settings]by hand[/url] or whatever you can figure out.[/hidden]
[img]https://scp.indiegames.us/img/windows-icon.png[/img] [color=green][size=12pt]Windows (32/64-bit/ARM64)[/size][/color]
[img]https://scp.indiegames.us/img/windows-icon.png[/img] [color=green][size=12pt]Windows (32/64-bit)[/size][/color]
[size=8pt]Compiled using GitHub Actions on Windows Server 2019 (10.0.17763), Visual Studio Enterprise 2019[/size]
[b]64-bit:[/b] ${build(groups["Win64"].mainFile)}
@@ -30,8 +30,6 @@ Linux: [url=https://www.hard-light.net/forums/index.php/topic,53206.0.html]YAL[
[b]32-bit:[/b] ${build(groups["Win32"].mainFile)}
[size=8pt]This one is based on the SSE2 Optimizations from the MSVC Compiler.[/size]
[b]ARM64:[/b] ${build(groups["WinARM64"].mainFile)}
[hidden=Alternative builds]
[b]64-bit AVX:[/b] ${build(groups["Win64"].subFiles["AVX"])}
+2 -2
View File
@@ -1,3 +1,3 @@
Mako==1.4.2
requests==2.33.0
Mako==1.2.2
requests==2.32.4
semantic-version==2.8.5
-34
View File
@@ -1,34 +0,0 @@
# Installs ATL and MFC for the v143 toolset, which the Visual Studio 2026 runner images
# only ship for the latest toolset. ATL is needed by SAPI speech (sphelper.h) and MFC by FRED2.
$ErrorActionPreference = 'Stop'
$msvcVersion = '14.44'
$component = 'Microsoft.VisualStudio.Component.VC.14.44.17.14'
$suffix = if ($env:RUNNER_ARCH -eq 'ARM64') { '.ARM64' } else { '' }
$installerDir = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer"
$installPath = & "$installerDir\vswhere.exe" -version '[18.0,19.0)' -latest -property installationPath
if (-not $installPath) {
Write-Error 'Visual Studio 2026 was not found'
}
$arguments = @(
'/c', 'vs_installer.exe', 'modify',
'--installPath', "`"$installPath`"",
'--add', "$component.ATL$suffix",
'--add', "$component.MFC$suffix",
'--quiet', '--norestart', '--nocache'
)
$process = Start-Process -FilePath cmd.exe -ArgumentList $arguments -WorkingDirectory $installerDir -Wait -PassThru -NoNewWindow
# 3010 = success, reboot required
if ($process.ExitCode -notin 0, 3010) {
Write-Error "vs_installer exited with code $($process.ExitCode)"
}
# fail here rather than with a confusing compile error if the components didn't install
foreach ($header in 'atlbase.h', 'afxwin.h') {
if (-not (Test-Path "$installPath\VC\Tools\MSVC\$msvcVersion.*\atlmfc\include\$header")) {
Write-Error "$header for MSVC $msvcVersion is missing after install"
}
}
File renamed without changes.
File renamed without changes.
-48
View File
@@ -1,48 +0,0 @@
# - Removes duplicate entries and non-directories from a provided list
#
# clean_directory_list(<listvar> [<additional list items>...])
#
# Requires CMake 2.6 or newer (uses the 'function' command)
#
# Original Author:
# 2009-2010 Ryan Pavlik <[email protected]> <[email protected]>
# http://academic.cleardefinition.com
# Iowa State University HCI Graduate Program/VRAC
#
# Copyright Iowa State University 2009-2010.
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt)
if(__clean_directory_list)
return()
endif()
set(__clean_directory_list YES)
function(clean_directory_list _var)
# combine variable's current value with additional list items
set(_in ${${_var}} ${ARGN})
if(_in)
# Initial list cleaning
list(REMOVE_DUPLICATES _in)
# Grab the absolute path of each actual directory
set(_out)
foreach(_dir ${_in})
if(IS_DIRECTORY "${_dir}")
get_filename_component(_dir "${_dir}" ABSOLUTE)
file(TO_CMAKE_PATH "${_dir}" _dir)
list(APPEND _out "${_dir}")
endif()
endforeach()
if(_out)
# Clean up the output list now
list(REMOVE_DUPLICATES _out)
endif()
# return _out
set(${_var} "${_out}" PARENT_SCOPE)
endif()
endfunction()
-311
View File
@@ -1,311 +0,0 @@
# - Create launchers to set working directory, env. vars, etc.
#
# include(CreateLaunchers) - to make these available
# guess_runtime_library_dirs(<outputvarname> [<extralibrary> ...])
# create_default_target_launcher(<targetname>
# [ARGS <args...>]
# [FORWARD_ARGS]
# [RUNTIME_LIBRARY_DIRS <dir...>]
# [WORKING_DIRECTORY <dir>]
# [ENVIRONMENT <VAR=value> [<VAR=value>...]])
#
# create_target_launcher(<targetname>
# [ARGS <args...>]
# [FORWARD_ARGS]
# [RUNTIME_LIBRARY_DIRS <dir...>]
# [WORKING_DIRECTORY <dir>]
# [ENVIRONMENT <VAR=value> [<VAR=value>...]])
#
# create_generic_launcher(<launchername>
# [RUNTIME_LIBRARY_DIRS <dir...>]
# [WORKING_DIRECTORY <dir>]
# [ENVIRONMENT <VAR=value> [<VAR=value>...]])
# - sets GENERIC_LAUNCHER_COMMAND and GENERIC_LAUNCHER_FAIL_REGULAR_EXPRESSION
#
# Requires these CMake modules:
# ListFilter
# ProgramFilesGlob
# CleanDirectoryList
#
# Requires CMake 2.6 or newer (uses the 'function' command)
#
# Original Author:
# 2009-2010 Ryan Pavlik <[email protected]> <[email protected]>
# http://academic.cleardefinition.com
# Iowa State University HCI Graduate Program/VRAC
#
# Copyright Iowa State University 2009-2010.
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt)
if(__create_launchers)
return()
endif()
set(__create_launchers YES)
include(CleanDirectoryList)
# We must run the following at "include" time, not at function call time,
# to find the path to this module rather than the path to a calling list file
get_filename_component(_launchermoddir
${CMAKE_CURRENT_LIST_FILE}
PATH)
set(_launchermoddir "${_launchermoddir}/launcher-templates")
macro(_launcher_system_settings)
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(BITS 64)
else()
set(BITS 32)
endif()
if(WIN32)
# Find user and system name
set(SYSTEM_NAME $ENV{USERDOMAIN})
set(USER_NAME $ENV{USERNAME})
set(VCPROJ_TYPE vcproj)
set(USERFILE_EXTENSION ${SYSTEM_NAME}.${USER_NAME}.user)
set(LAUNCHER_LINESEP "&#x0A;")
if(MSVC90)
set(USERFILE_VC_VERSION 9.00)
elseif(MSVC80)
set(USERFILE_VC_VERSION 8.00)
elseif(MSVC71)
set(USERFILE_VC_VERSION 7.10)
elseif(MSVC10 OR (MSVC AND MSVC_VERSION GREATER 1600)) # 2010 or newer
set(LAUNCHER_LINESEP "\n")
set(USERFILE_VC_VERSION 10.00)
set(USERFILE_EXTENSION user)
set(VCPROJ_TYPE vcxproj)
endif()
if(BITS EQUAL 64)
set(USERFILE_PLATFORM x64)
else()
set(USERFILE_PLATFORM Win${BITS})
endif()
set(_pathdelim ";")
set(_suffix "cmd")
else()
set(_pathdelim ":")
set(USERFILE_PLATFORM ${CMAKE_SYSTEM_NAME}${BITS})
set(_suffix "sh")
find_package(GDB QUIET)
if(GDB_FOUND)
set(LAUNCHERS_GOT_GDB YES)
if(GDB_HAS_RETURN_CHILD_RESULT)
set(LAUNCHERS_GDB_ARG --return-child-result)
endif()
else()
set(LAUNCHERS_GOT_GDB)
endif()
endif()
if(WIN32 AND NOT USERFILE_REMOTE_MACHINE)
site_name(USERFILE_REMOTE_MACHINE)
mark_as_advanced(USERFILE_REMOTE_MACHINE)
endif()
endmacro()
macro(_launcher_process_args)
set(_nowhere)
set(_curdest _nowhere)
set(_val_args
ARGS
RUNTIME_LIBRARY_DIRS
WORKING_DIRECTORY
ENVIRONMENT)
set(_bool_args FORWARD_ARGS)
foreach(_arg ${_val_args} ${_bool_args})
set(${_arg})
endforeach()
foreach(_element ${ARGN})
list(FIND _val_args "${_element}" _val_arg_find)
list(FIND _bool_args "${_element}" _bool_arg_find)
if("${_val_arg_find}" GREATER "-1")
set(_curdest "${_element}")
elseif("${_bool_arg_find}" GREATER "-1")
set("${_element}" ON)
set(_curdest _nowhere)
else()
list(APPEND ${_curdest} "${_element}")
endif()
endforeach()
if(_nowhere)
message(FATAL_ERROR
"Syntax error in use of a function in CreateLaunchers!")
endif()
# Turn into a list of native paths
set(_runtime_lib_dirs)
foreach(_dlldir ${RUNTIME_LIBRARY_DIRS})
file(TO_NATIVE_PATH "${_dlldir}" _path)
set(_runtime_lib_dirs "${_runtime_lib_dirs}${_path}${_pathdelim}")
endforeach()
if(NOT WORKING_DIRECTORY)
set(WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}")
endif()
if(FORWARD_ARGS)
if(WIN32)
set(FWD_ARGS %*)
else()
set(FWD_ARGS $*)
endif()
else()
set(FWD_ARGS)
endif()
set(USERFILE_WORKING_DIRECTORY "${WORKING_DIRECTORY}")
set(USERFILE_COMMAND_ARGUMENTS "${ARGS}")
set(LAUNCHERSCRIPT_COMMAND_ARGUMENTS "${ARGS} ${FWD_ARGS}")
if(WIN32)
set(RUNTIME_LIBRARIES_ENVIRONMENT "PATH=${_runtime_lib_dirs};%PATH%")
file(READ
"${_launchermoddir}/launcher.env.cmd.in"
_cmdenv)
else()
if(APPLE)
set(RUNTIME_LIBRARIES_ENVIRONMENT
"DYLD_LIBRARY_PATH=${_runtime_lib_dirs}:$DYLD_LIBRARY_PATH")
else()
set(RUNTIME_LIBRARIES_ENVIRONMENT
"LD_LIBRARY_PATH=${_runtime_lib_dirs}:$LD_LIBRARY_PATH")
endif()
file(READ
"${_launchermoddir}/launcher.env.sh.in"
_cmdenv)
endif()
set(USERFILE_ENVIRONMENT "${RUNTIME_LIBRARIES_ENVIRONMENT}")
set(USERFILE_ENV_COMMANDS)
foreach(_arg "${RUNTIME_LIBRARIES_ENVIRONMENT}" ${ENVIRONMENT})
string(CONFIGURE
"@USERFILE_ENVIRONMENT@@LAUNCHER_LINESEP@@_arg@"
USERFILE_ENVIRONMENT
@ONLY)
string(CONFIGURE
"@USERFILE_ENV_COMMANDS@${_cmdenv}"
USERFILE_ENV_COMMANDS
@ONLY)
endforeach()
endmacro()
macro(_launcher_produce_vcproj_user)
if(MSVC)
file(READ
"${_launchermoddir}/perconfig.${VCPROJ_TYPE}.user.in"
_perconfig)
file(TO_NATIVE_PATH "${USERFILE_WORKING_DIRECTORY}" NATIVE_WORKING_DIRECTORY)
set(USERFILE_CONFIGSECTIONS)
foreach(USERFILE_CONFIGNAME ${CMAKE_CONFIGURATION_TYPES})
string(CONFIGURE "${_perconfig}" _temp @ONLY ESCAPE_QUOTES)
set(USERFILE_CONFIGSECTIONS "${USERFILE_CONFIGSECTIONS}${_temp}")
endforeach()
configure_file("${_launchermoddir}/${VCPROJ_TYPE}.user.in"
"${VCPROJNAME}.${VCPROJ_TYPE}.${USERFILE_EXTENSION}"
@ONLY)
endif()
endmacro()
macro(_launcher_configure_executable _src _tmp _target)
# get_filename_component(_targetname "${_target}" NAME)
get_filename_component(_targetpath "${_target}" PATH)
configure_file("${_src}"
"${_tmp}"
@ONLY)
file(COPY "${_tmp}"
DESTINATION "${_targetpath}"
FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_WRITE GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
endmacro()
macro(_launcher_create_target_launcher)
set(TARGET_NAME ${_targetname})
set(_fn "launch-${_targetname}-generator.${_suffix}")
configure_file("${_launchermoddir}/targetlauncher.${_suffix}.in"
"${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${_fn}"
@ONLY)
file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/launch-${_targetname}-$<CONFIGURATION>.${_suffix}"
INPUT "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${_fn}")
endmacro()
function(create_default_target_launcher _targetname)
_launcher_system_settings()
_launcher_process_args(${ARGN})
set(VCPROJNAME "${CMAKE_BINARY_DIR}/ALL_BUILD")
_launcher_produce_vcproj_user()
_launcher_create_target_launcher()
endfunction()
function(create_target_launcher _targetname)
_launcher_system_settings()
_launcher_process_args(${ARGN})
set(VCPROJNAME "${CMAKE_CURRENT_BINARY_DIR}/${_targetname}")
_launcher_produce_vcproj_user()
_launcher_create_target_launcher()
endfunction()
function(create_generic_launcher _launchername)
_launcher_system_settings()
_launcher_process_args(${ARGN})
if(NOT IS_ABSOLUTE _launchername)
set(_launchername
"${CMAKE_CURRENT_BINARY_DIR}/${_launchername}.${_suffix}")
else()
set(_launchername "${_launchername}.${_suffix}")
endif()
if(WIN32)
set(GENERIC_LAUNCHER_COMMAND "${_launchername}" PARENT_SCOPE)
set(GENERIC_LAUNCHER_FAIL_REGULAR_EXPRESSION)
else()
set(GENERIC_LAUNCHER_COMMAND sh "${_launchername}" PARENT_SCOPE)
set(GENERIC_LAUNCHER_FAIL_REGULAR_EXPRESSION
"Program terminated with signal")
endif()
_launcher_configure_executable("${_launchermoddir}/genericlauncher.${_suffix}.in"
"${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/genericlauncher.${_suffix}.in"
"${_launchername}")
endfunction()
function(guess_runtime_library_dirs _var)
# Start off with the link directories of the calling listfile's directory
get_directory_property(_libdirs LINK_DIRECTORIES)
# Add additional libraries passed to the function
foreach(_lib ${ARGN})
get_filename_component(_libdir "${_lib}" PATH)
list(APPEND _libdirs "${_libdir}")
endforeach()
# Now, build a list of potential dll directories
set(_dlldirs)
foreach(_libdir ${_libdirs})
# Add the libdir itself
list(APPEND _dlldirs "${_libdir}")
# Look also in libdir/../bin since the dll might not be with the lib
get_filename_component(_libdir "${_libdir}/../bin" ABSOLUTE)
list(APPEND _dlldirs "${_libdir}")
endforeach()
# Only keep the valid, unique directories
clean_directory_list(_dlldirs)
# Return _dlldirs
set(${_var} "${_dlldirs}" PARENT_SCOPE)
endfunction()
-88
View File
@@ -1,88 +0,0 @@
# - Add flags to compile with extra warnings
#
# enable_extra_compiler_warnings(<targetname>)
# globally_enable_extra_compiler_warnings() - to modify CMAKE_CXX_FLAGS, etc
# to change for all targets declared after the command, instead of per-command
#
#
# Original Author:
# 2010 Ryan Pavlik <[email protected]> <[email protected]>
# http://academic.cleardefinition.com
# Iowa State University HCI Graduate Program/VRAC
#
# Copyright Iowa State University 2009-2010.
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt)
if(__enable_extra_compiler_warnings)
return()
endif()
set(__enable_extra_compiler_warnings YES)
macro(_enable_extra_compiler_warnings_flags)
set(_flags)
if(MSVC)
option(COMPILER_WARNINGS_EXTREME
"Use compiler warnings that are probably overkill."
off)
mark_as_advanced(COMPILER_WARNINGS_EXTREME)
set(_flags "/W4")
if(COMPILER_WARNINGS_EXTREME)
set(_flags "${_flags} /Wall /wd4619 /wd4668 /wd4820 /wd4571 /wd4710")
endif()
else()
include(CheckCXXCompilerFlag)
set(_flags)
check_cxx_compiler_flag(-W SUPPORTS_W_FLAG)
if(SUPPORTS_W_FLAG)
set(_flags "${_flags} -W")
endif()
check_cxx_compiler_flag(-Wall SUPPORTS_WALL_FLAG)
if(SUPPORTS_WALL_FLAG)
set(_flags "${_flags} -Wall")
endif()
check_cxx_compiler_flag(-Wextra SUPPORTS_WEXTRA_FLAG)
if(SUPPORTS_WEXTRA_FLAG)
set(_flags "${_flags} -Wextra")
endif()
if(SUPPORTS_WALL_FLAG)
# At least GCC includes -Wmaybe-uninitialized in -Wall, which
# unneccesarily whines about boost::optional (by it's nature
# it's a "maybe" warning - prone to noisy false-positives)
check_cxx_compiler_flag(-Wno-maybe-uninitialized SUPPORTS_WNO_MAYBE_UNINITIALIZED_FLAG)
if(SUPPORTS_WNO_MAYBE_UNINITIALIZED_FLAG)
set(_flags "${_flags} -Wno-maybe-uninitialized")
endif()
endif()
endif()
endmacro()
function(enable_extra_compiler_warnings _target)
_enable_extra_compiler_warnings_flags()
get_target_property(_origflags ${_target} COMPILE_FLAGS)
if(_origflags)
set_property(TARGET
${_target}
PROPERTY
COMPILE_FLAGS
"${_flags} ${_origflags}")
else()
set_property(TARGET
${_target}
PROPERTY
COMPILE_FLAGS
"${_flags}")
endif()
endfunction()
function(globally_enable_extra_compiler_warnings)
_enable_extra_compiler_warnings_flags()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${_flags}" PARENT_SCOPE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${_flags}" PARENT_SCOPE)
endfunction()
-53
View File
@@ -1,53 +0,0 @@
# - Combine lists of prefixes and suffixes in all combinations
#
# list_combinations(var PREFIXES listitems... SUFFIXES listitems...) -
# where var is the name of your desired output variable and PREFIXES
# and SUFFIXES are special arguments that indicate the start of your
# list of prefixes or suffixes respectively.
#
# Original Author:
# 2009-2010 Ryan Pavlik <[email protected]> <[email protected]>
# http://academic.cleardefinition.com
# Iowa State University HCI Graduate Program/VRAC
#
# Copyright Iowa State University 2009-2010.
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt)
if(__list_combinations)
return()
endif()
set(__list_combinations YES)
function(list_combinations var)
# Parse arguments
set(_prefixes)
set(_suffixes)
set(_nowhere)
set(_curdest _nowhere)
foreach(_element ${ARGN})
if("${_element}" STREQUAL "PREFIXES")
set(_curdest _prefixes)
elseif("${_element}" STREQUAL "SUFFIXES")
set(_curdest _suffixes)
else()
list(APPEND ${_curdest} "${_element}")
endif()
endforeach()
if(_nowhere)
message(STATUS "_prefixes ${_prefixes}")
message(STATUS "_prefixes ${_suffixes}")
message(STATUS "_prefixes ${_nowhere}")
message(FATAL_ERROR
"Syntax error in use of ${CMAKE_CURRENT_LIST_FILE}")
endif()
foreach(_prefix ${_prefixes})
foreach(_suffix ${_suffixes})
list(APPEND _out "${_prefix}${_suffix}")
endforeach()
endforeach()
set(${var} "${_out}" PARENT_SCOPE)
endfunction()
-31
View File
@@ -1,31 +0,0 @@
# - Compile with multiple processes on MSVC
#
# include(MSVCMultipleProcessCompile)
#
# Requires these CMake modules:
# ListCombinations.cmake
#
# Original Author:
# 2009-2010 Ryan Pavlik <[email protected]> <[email protected]>
# http://academic.cleardefinition.com
# Iowa State University HCI Graduate Program/VRAC
#
# Copyright Iowa State University 2009-2010.
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt)
if(MSVC AND NOT "${MSVC_VERSION}" LESS 1400)
# Only available in VS 2005 and newer
string(TOUPPER "${CMAKE_CONFIGURATION_TYPES}" _conftypesUC)
include(ListCombinations)
list_combinations(_varnames
PREFIXES
CMAKE_C_FLAGS_
CMAKE_CXX_FLAGS_
SUFFIXES
${_conftypesUC})
foreach(_var ${_varnames})
set(${_var} "${${_var}} /MP")
endforeach()
endif()
+21
View File
@@ -0,0 +1,21 @@
SET(BINARY_DESTINATION "bin")
SET(LIBRAY_DESTINATION "lib")
configure_file("${CMAKE_CURRENT_LIST_DIR}/AppRun.in" "${CMAKE_CURRENT_BINARY_DIR}/AppRun.gen" @ONLY)
file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/AppRun-$<CONFIG>"
INPUT "${CMAKE_CURRENT_BINARY_DIR}/AppRun.gen")
install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/AppRun-$<CONFIG>" DESTINATION "." RENAME "AppRun"
COMPONENT "Freespace2")
configure_file("${CMAKE_CURRENT_LIST_DIR}/AppImage.desktop.in" "${CMAKE_CURRENT_BINARY_DIR}/AppImage.desktop.gen" @ONLY)
file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/AppImage-$<CONFIG>.desktop"
INPUT "${CMAKE_CURRENT_BINARY_DIR}/AppImage.desktop.gen")
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/AppImage-$<CONFIG>.desktop" DESTINATION "." RENAME "fso.desktop"
COMPONENT "Freespace2")
install(FILES "${CMAKE_SOURCE_DIR}/freespace2/resources/app_icon.png" DESTINATION "."
COMPONENT "Freespace2")
-4
View File
@@ -11,10 +11,6 @@ if (WIN32)
endif()
elseif(APPLE)
# it should just work
elseif(ANDROID)
# connects to a java TTS manager via SDL activity class
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
# uses speech-dispatcher with dlopen
else()
message(SEND_ERROR "Text to Speech is not supported on this platform!")
endif()
@@ -1,14 +0,0 @@
cd @USERFILE_WORKING_DIRECTORY@
@USERFILE_ENV_COMMANDS@
IF NOT [x%1]==[x--debugger] GOTO SkipDebuggingMess
ECHO Need to ditch the debugger!
SHIFT /1
%1 %2 %3 %4 %5 %6 %7 %8 %9
GOTO EOF
:SkipDebuggingMess
%*
:EOF
@@ -1,18 +0,0 @@
#!/bin/sh
bindir=$(pwd)
cd @USERFILE_WORKING_DIRECTORY@
@USERFILE_ENV_COMMANDS@
if test "x$1" = "x--debugger"; then
shift
cmd="$1"
shift
if test "x@LAUNCHERS_GOT_GDB@" = "xYES"; then
echo "r $@" > $bindir/gdbscript
echo "bt" >> $bindir/gdbscript
@GDB_COMMAND@ -batch -command=$bindir/gdbscript @LAUNCHERS_GDB_ARG@ $cmd
else
$cmd $@
fi
else
$@
fi
@@ -1 +0,0 @@
set @_arg@
@@ -1 +0,0 @@
export @_arg@
@@ -1,28 +0,0 @@
<Configuration
Name="@USERFILE_CONFIGNAME@|@USERFILE_PLATFORM@"
>
<DebugSettings
Command="${USERFILE_@USERFILE_CONFIGNAME@_COMMAND}"
WorkingDirectory="@USERFILE_WORKING_DIRECTORY@"
CommandArguments="@USERFILE_COMMAND_ARGUMENTS@"
Attach="false"
DebuggerType="3"
Remote="1"
RemoteMachine="@USERFILE_REMOTE_MACHINE@"
RemoteCommand=""
HttpUrl=""
PDBPath=""
SQLDebugging=""
Environment="@USERFILE_ENVIRONMENT@"
EnvironmentMerge="true"
DebuggerFlavor=""
MPIRunCommand=""
MPIRunArguments=""
MPIRunWorkingDirectory=""
ApplicationCommand=""
ApplicationArguments=""
ShimCommand=""
MPIAcceptMode=""
MPIAcceptFilter=""
/>
</Configuration>
@@ -1,7 +0,0 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='@USERFILE_CONFIGNAME@|@USERFILE_PLATFORM@'">
<LocalDebuggerEnvironment>@USERFILE_ENVIRONMENT@</LocalDebuggerEnvironment>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
<LocalDebuggerCommand>$(TargetPath)</LocalDebuggerCommand>
<LocalDebuggerCommandArguments>@USERFILE_COMMAND_ARGUMENTS@</LocalDebuggerCommandArguments>
<LocalDebuggerWorkingDirectory>@NATIVE_WORKING_DIRECTORY@</LocalDebuggerWorkingDirectory>
</PropertyGroup>
@@ -1,8 +0,0 @@
cd @USERFILE_WORKING_DIRECTORY@
@USERFILE_ENV_COMMANDS@
if [%1]==[--debugger] (
SHIFT
)
"@USERFILE_COMMAND@" @LAUNCHERSCRIPT_COMMAND_ARGUMENTS@
pause
@@ -1,16 +0,0 @@
#!/bin/sh
bindir=$(pwd)
cd @USERFILE_WORKING_DIRECTORY@
@USERFILE_ENV_COMMANDS@
if test "x$1" = "x--debugger"; then
shift
if test "x@LAUNCHERS_GOT_GDB@" = "xYES"; then
echo "r @LAUNCHERSCRIPT_COMMAND_ARGUMENTS@" > $bindir/gdbscript
echo "bt" >> $bindir/gdbscript
@GDB_COMMAND@ -batch -command=$bindir/gdbscript @LAUNCHERS_GDB_ARG@ @USERFILE_COMMAND@
else
"@USERFILE_COMMAND@" @LAUNCHERSCRIPT_COMMAND_ARGUMENTS@
fi
else
"@USERFILE_COMMAND@" @LAUNCHERSCRIPT_COMMAND_ARGUMENTS@
fi
-10
View File
@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioUserFile
ProjectType="Visual C++"
Version="@USERFILE_VC_VERSION@"
ShowAllFiles="false"
>
<Configurations>
@USERFILE_CONFIGSECTIONS@
</Configurations>
</VisualStudioUserFile>
-4
View File
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
@USERFILE_CONFIGSECTIONS@
</Project>
+3
View File
@@ -11,6 +11,9 @@ endif()
target_link_libraries(platform INTERFACE ${COCOA_LIBRARY})
# To support C++17 we need to target at least 10.13. maybe 10.14 for some rare features
SET(CMAKE_OSX_DEPLOYMENT_TARGET "10.13")
SET(CMAKE_SKIP_RPATH FALSE)
SET(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
SET(CMAKE_INSTALL_RPATH @loader_path/../Frameworks/)
+3 -4
View File
@@ -43,6 +43,7 @@ endif()
if (USE_STATIC_LIBCXX)
set(CXX_BASE_FLAGS "${CXX_BASE_FLAGS} -static-libstdc++ -Qunused-arguments")
set(CLANG_USE_LIBCXX ON)
endif()
# For C and C++, the values can be overwritten independently
@@ -134,10 +135,8 @@ endif()
set(CXX_FLAGS_RELEASE "${CXX_OPT_FLAG_RELEASE} -Wno-unused-variable -Wno-unused-parameter")
set(C_FLAGS_RELEASE "${C_OPT_FLAG_RELEASE} -Wno-unused-variable -Wno-unused-parameter")
# Valgrind (as used by CI) does not understand the DWARF5 debug info that clang
# emits by default, so force DWARF4 to keep memcheck able to symbolize the binary.
set(CXX_FLAGS_DEBUG "${CXX_OPT_FLAG_DEBUG} -g -gdwarf-4 -Wshadow")
set(C_FLAGS_DEBUG "${C_OPT_FLAG_DEBUG} -g -gdwarf-4 -Wshadow")
set(CXX_FLAGS_DEBUG "${CXX_OPT_FLAG_DEBUG} -g -Wshadow")
set(C_FLAGS_DEBUG "${C_OPT_FLAG_DEBUG} -g -Wshadow")
# Always use the base flags and add our compiler flags at the back
set(CMAKE_CXX_FLAGS "${CXX_BASE_FLAGS} ${COMPILER_FLAGS}")
+6 -13
View File
@@ -13,13 +13,6 @@ option(MSVC_RELEASE_DEBUGGING "Set options that allow to debug release builds" O
MARK_AS_ADVANCED(FORCE MSVC_USE_RUNTIME_DLL)
MARK_AS_ADVANCED(FORCE MSVC_RELEASE_DEBUGGING)
# Qt is only available as DLL-runtime builds, so qtFRED forces the DLL runtime for the whole tree
if(MSVC_USE_RUNTIME_DLL OR FSO_BUILD_QTFRED)
set(FSO_MSVC_RUNTIME_DLL ON)
else()
set(FSO_MSVC_RUNTIME_DLL OFF)
endif()
# These are the warnings we disable
set(WARNING_FLAGS
/wd4100 # unreferenced formal parameters
@@ -78,13 +71,12 @@ if (MSVC_RELEASE_DEBUGGING)
endif()
endif()
# The debug runtime is not redistributable (statically linked or not), so only Debug may use it
IF(FSO_MSVC_RUNTIME_DLL)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
IF(MSVC_USE_RUNTIME_DLL)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<NOT:$<CONFIG:Release>>:Debug>DLL")
add_compile_definitions(_AFXDLL)
ELSE()
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
ENDIF()
ELSE(MSVC_USE_RUNTIME_DLL)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<NOT:$<CONFIG:Release>>:Debug>")
ENDIF(MSVC_USE_RUNTIME_DLL)
# Debug
set(CMAKE_C_FLAGS_DEBUG "/W4 /Gy /Zi /Od /RTC1 /Gd /Oy-")
@@ -121,6 +113,7 @@ if(IS_X86)
endif()
add_compile_definitions("$<$<CONFIG:FastDebug>:_ITERATOR_DEBUG_LEVEL=0>")
target_compile_definitions(compiler INTERFACE _CRT_SECURE_NO_DEPRECATE _CRT_SECURE_NO_WARNINGS _SECURE_SCL=0 NOMINMAX _SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING)
if (FSO_FATAL_WARNINGS)
+10 -7
View File
@@ -3,13 +3,7 @@
add_library(compiler INTERFACE)
set(FSO_CONFIG_DEFINITIONS "$<$<CONFIG:Release>:NDEBUG>" "$<$<CONFIG:Debug>:_DEBUG>")
if(NOT MSVC)
# On MSVC the debug runtime flags (/MTd, /MDd) define _DEBUG themselves, and a FastDebug
# build on the release runtime must not have it
list(APPEND FSO_CONFIG_DEFINITIONS "$<$<CONFIG:FastDebug>:_DEBUG>")
endif()
target_compile_definitions(compiler INTERFACE ${FSO_CONFIG_DEFINITIONS})
target_compile_definitions(compiler INTERFACE "$<$<CONFIG:Release>:NDEBUG>;$<$<CONFIG:Debug>:_DEBUG>;$<$<CONFIG:FastDebug>:_DEBUG>")
set(FORCED_NATIVE_SIMD_INSTRUCTIONS ON CACHE BOOL "Override instruction set detection and compile with the maximum possible instructions for the current system.")
IF(IS_X86)
@@ -80,3 +74,12 @@ set(CMAKE_C_FLAGS_FASTDEBUG "${CMAKE_C_FLAGS_RELEASE}")
set(CMAKE_CXX_FLAGS_FASTDEBUG "${CMAKE_CXX_FLAGS_RELEASE}")
set(CMAKE_EXE_LINKER_FLAGS_FASTDEBUG "${CMAKE_EXE_LINKER_FLAGS_RELEASE}")
set(CMAKE_STATIC_LINKER_FLAGS_FASTDEBUG "${CMAKE_STATIC_LINKER_FLAGS_RELEASE}")
if (MSVC)
# Adjust runtime library
string(REPLACE "/MD" "/MDd" CMAKE_C_FLAGS_FASTDEBUG "${CMAKE_C_FLAGS_FASTDEBUG}")
string(REPLACE "/MT" "/MTd" CMAKE_C_FLAGS_FASTDEBUG "${CMAKE_C_FLAGS_FASTDEBUG}")
string(REPLACE "/MD" "/MDd" CMAKE_CXX_FLAGS_FASTDEBUG "${CMAKE_CXX_FLAGS_FASTDEBUG}")
string(REPLACE "/MT" "/MTd" CMAKE_CXX_FLAGS_FASTDEBUG "${CMAKE_CXX_FLAGS_FASTDEBUG}")
endif()
+14 -29
View File
@@ -66,37 +66,33 @@ ENDIF(EXISTS \"${CMAKE_CURRENT_BINARY_DIR}/${TARGET}/${FILE}\")
SET(${OUTVAR} "${CMAKE_COMMAND}" -P ${CMAKE_CURRENT_BINARY_DIR}/${TARGET}/${NAME} PARENT_SCOPE)
ENDFUNCTION(EP_CHECK_FILE_EXISTS)
# Use rsync if possible for COPY_FILE_TO_TARGET macro in order to preserve
# symlinks as copy_if_different follows them which results in multiple copies
if(PLATFORM_UNIX AND NOT DEFINED RSYNC_BIN)
find_program(RSYNC_BIN rsync)
endif()
MACRO(COPY_FILE_TO_TARGET _target _file)
if(RSYNC_BIN)
ADD_CUSTOM_COMMAND(
TARGET ${_target} POST_BUILD
COMMAND ${RSYNC_BIN} -rlq "${_file}" "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}"
COMMENT "copying '${_file}'..."
VERBATIM
)
else()
if (IS_DIRECTORY "${_file}")
get_filename_component(_dirName "${_file}" NAME)
if (IS_DIRECTORY "${_file}")
get_filename_component(_dirName "${_file}" NAME)
if (PLATFORM_MAC AND ("${_file}" MATCHES ".framework$"))
# This is stupid, but it preserves symlinks, unlike copy_directory_if_different.
# Otherwise we end up creating duplicate files in the copied framework.
ADD_CUSTOM_COMMAND(
TARGET ${_target} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different "${_file}" "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/${_dirName}"
COMMAND rsync -rlq "${_file}" "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}"
COMMENT "copying '${_file}'..."
VERBATIM
)
else()
ADD_CUSTOM_COMMAND(
TARGET ${_target} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${_file}" "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/"
COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different "${_file}" "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/${_dirName}"
COMMENT "copying '${_file}'..."
VERBATIM
)
endif()
else()
ADD_CUSTOM_COMMAND(
TARGET ${_target} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${_file}" "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/"
COMMENT "copying '${_file}'..."
VERBATIM
)
endif()
endmacro(COPY_FILE_TO_TARGET)
@@ -241,17 +237,6 @@ function(suppress_file_warnings)
endif()
endfunction(suppress_file_warnings)
# Suppress no symbols warnings in static libraries (on Xcode)
function(suppress_no_symbol_warnings _target)
if(XCODE)
get_target_property(target_type ${_target} TYPE)
if(target_type STREQUAL "STATIC_LIBRARY")
set_property(TARGET ${_target} APPEND PROPERTY
STATIC_LIBRARY_OPTIONS "-no_warning_for_no_symbols"
)
endif()
endif()
endfunction(suppress_no_symbol_warnings)
function(list_target_dependencies _target _out_var)
set(out_list)
+1 -1
View File
@@ -6,7 +6,7 @@ if (EXISTS "${PROJECT_SOURCE_DIR}/version_override.cmake")
include("${PROJECT_SOURCE_DIR}/version_override.cmake")
endif()
set_if_not_defined(FSO_VERSION_MAJOR 26)
set_if_not_defined(FSO_VERSION_MAJOR 24)
set_if_not_defined(FSO_VERSION_MINOR 3)
set_if_not_defined(FSO_VERSION_BUILD 0)
+13 -7
View File
@@ -39,7 +39,7 @@ TARGET_LINK_LIBRARIES(code PUBLIC ${PNG_LIBS})
TARGET_LINK_LIBRARIES(code PUBLIC ${JPEG_LIBS})
TARGET_LINK_LIBRARIES(code PUBLIC lz4)
TARGET_LINK_LIBRARIES(code PUBLIC sdl3)
TARGET_LINK_LIBRARIES(code PUBLIC sdl2)
if (FSO_BUILD_WITH_FFMPEG)
TARGET_LINK_LIBRARIES(code PUBLIC ffmpeg)
@@ -76,6 +76,8 @@ TARGET_LINK_LIBRARIES(code PUBLIC jansson)
target_link_libraries(code PUBLIC anl)
target_link_libraries(code PUBLIC hidapi::hidapi)
target_link_libraries(code PUBLIC imgui)
IF(FSO_BUILD_WITH_OPENXR)
@@ -111,9 +113,16 @@ if (FSO_BUILD_WITH_OPENGL)
target_compile_definitions(code PUBLIC WITH_OPENGL)
endif()
if (FSO_BUILD_WITH_VULKAN)
target_compile_definitions(code PUBLIC WITH_VULKAN VULKAN_HPP_DISPATCH_LOADER_DYNAMIC=1 VK_NO_PROTOTYPES)
target_include_directories(code PUBLIC Vulkan::Headers)
target_link_libraries(code PUBLIC VulkanMemoryAllocator)
find_package(Vulkan REQUIRED)
if (Vulkan_FOUND)
target_compile_definitions(code PUBLIC WITH_VULKAN)
target_link_libraries(code PRIVATE Vulkan::Vulkan)
target_compile_definitions(code PUBLIC WITH_VULKAN VULKAN_HPP_DISPATCH_LOADER_DYNAMIC=1 VK_NO_PROTOTYPES)
else()
message(WARNING "FSO_BUILD_WITH_VULKAN was set, but the package was unable to be found. Forcing OFF.")
set(FSO_BUILD_WITH_VULKAN OFF CACHE BOOL "Enable compilation of the Vulkan renderer" FORCE)
endif()
endif()
include(shaders.cmake)
@@ -130,8 +139,5 @@ set_target_properties(code PROPERTIES XCODE_ATTRIBUTE_COPY_PHASE_STRIP[variant=D
set_target_properties(code PROPERTIES XCODE_ATTRIBUTE_STRIP_INSTALLED_PRODUCT[variant=Debug] "NO")
set_target_properties(code PROPERTIES XCODE_ATTRIBUTE_GCC_SYMBOLS_PRIVATE_EXTERN[variant=Debug] "NO")
# Prevent warnings on files with no symbols on Mac
suppress_no_symbol_warnings(code)
# Prevent GCC warnings in third-party BitOp... see GitHub #4366
suppress_file_warnings(scripting/lua/bitop/bit.c)
+1 -1
View File
@@ -30,7 +30,7 @@ class BuiltinActionDefinition : public ActionDefinition {
// This should have been caught earlier
Assertion(paramIter != parameterExpressions.cend(), "Could not find built-in parameter!");
return std::make_unique<TAction>(paramIter->second.template asTyped<ActionValueType>());
return std::unique_ptr<Action>(new TAction(paramIter->second.template asTyped<ActionValueType>()));
}
};
+1 -1
View File
@@ -19,7 +19,7 @@ expression::ProgramVariables getDefaultTableVariables()
expression::ProgramVariables vars;
vars.setValue({"locals", "position"}, expression::Value(vmd_zero_vector));
vars.setValue({"locals", "direction"}, expression::Value(vmd_z_vector));
vars.setValue({"locals", "direction"}, expression::Value(vmd_zero_vector));
return vars;
}
+2 -2
View File
@@ -24,7 +24,7 @@ ActionExpression ActionExpression::parseFromTable(ValueType expectedReturnType,
stuff_string(expressionText, F_NAME);
ExpressionParser parser(std::move(expressionText));
ExpressionParser parser(expressionText);
auto expression = parser.parse(context);
@@ -45,7 +45,7 @@ ActionExpression ActionExpression::parseFromTable(ValueType expectedReturnType,
}
// Everything is valid
return ActionExpression(std::move(expression));
return ActionExpression(expression);
}
Value ActionExpression::execute(const ProgramVariables& variables) const
+1 -1
View File
@@ -6,7 +6,7 @@ namespace expression {
ProgramVariablesDefinition& ProgramVariablesDefinition::addScope(const SCP_string& name)
{
auto scope = std::make_unique<ProgramVariablesDefinition>();
auto scope = std::unique_ptr<ProgramVariablesDefinition>(new ProgramVariablesDefinition());
auto scopePtr = scope.get();
+1 -1
View File
@@ -38,7 +38,7 @@ const TypeDefinition& TypeDefinition::forValueType(ValueType type)
case ValueType::String:
return s_identifier;
default:
UNREACHABLE("Invalid value type %d!", static_cast<int>(type));
UNREACHABLE("Invalid value type!");
return s_integer; // Make compiler happy
}
}
+1 -1
View File
@@ -70,7 +70,7 @@ ActionResult MoveToSubmodel::execute(ProgramLocals& locals) const
std::unique_ptr<Action> MoveToSubmodel::clone() const
{
return std::make_unique<MoveToSubmodel>(*this);
return std::unique_ptr<Action>(new MoveToSubmodel(*this));
}
} // namespace types
+2 -2
View File
@@ -61,7 +61,7 @@ ActionResult ParticleEffectAction::execute(ProgramLocals& locals) const
matrix orientation;
vm_vector_2_matrix_norm(&orientation, &direction); // direction is normalized in SetDirectionAction::execute
source->setHost(std::make_unique<EffectHostObject>(locals.host.objp(), local_pos, orientation, true));
source->setHost(make_unique<EffectHostObject>(locals.host.objp(), local_pos, orientation, true));
source->finishCreation();
return ActionResult::Finished;
@@ -69,7 +69,7 @@ ActionResult ParticleEffectAction::execute(ProgramLocals& locals) const
std::unique_ptr<Action> ParticleEffectAction::clone() const
{
return std::make_unique<ParticleEffectAction>(*this);
return std::unique_ptr<Action>(new ParticleEffectAction(*this));
}
} // namespace types
+1 -1
View File
@@ -57,7 +57,7 @@ ActionResult PlaySoundAction::execute(ProgramLocals& locals) const
}
std::unique_ptr<Action> PlaySoundAction::clone() const
{
return std::make_unique<PlaySoundAction>(*this);
return std::unique_ptr<Action>(new PlaySoundAction(*this));
}
} // namespace types
} // namespace actions
+1 -1
View File
@@ -32,7 +32,7 @@ ActionResult SetDirectionAction::execute(ProgramLocals& locals) const
std::unique_ptr<Action> SetDirectionAction::clone() const
{
return std::make_unique<SetDirectionAction>(*this);
return std::unique_ptr<Action>(new SetDirectionAction(*this));
}
} // namespace types
+1 -1
View File
@@ -27,7 +27,7 @@ ActionResult SetPositionAction::execute(ProgramLocals& locals) const
std::unique_ptr<Action> SetPositionAction::clone() const
{
return std::make_unique<SetPositionAction>(*this);
return std::unique_ptr<Action>(new SetPositionAction(*this));
}
} // namespace types
+1 -1
View File
@@ -41,7 +41,7 @@ ActionResult WaitAction::execute(actions::ProgramLocals& locals) const
}
std::unique_ptr<Action> WaitAction::clone() const
{
return std::make_unique<WaitAction>(*this);
return std::unique_ptr<Action>(new WaitAction(*this));
}
} // namespace types
+12 -7
View File
@@ -16,11 +16,9 @@
#include "ai/ai.h"
#include "object/object.h"
#include "ship/ship.h"
#include "utils/string_utils.h"
// heap-allocated rather than SCP_string, so that the pointers held by ai goals stay valid when the vector grows
SCP_vector<SCP_vm_unique_ptr<char>> Goal_target_names;
SCP_vector<char *> Goal_target_names;
ai_info Ai_info[MAX_AI_INFO];
ai_info *Player_ai;
@@ -59,13 +57,20 @@ const char *ai_get_goal_target_name(const char *name, int *index)
Assertion(name != nullptr && index != nullptr, "Arguments cannot be null!");
for (int i = 0; i < static_cast<int>(Goal_target_names.size()); ++i) {
if (!stricmp(name, Goal_target_names[i].get())) {
if (!stricmp(name, Goal_target_names[i])) {
*index = i;
return Goal_target_names[i].get();
return Goal_target_names[i];
}
}
*index = static_cast<int>(Goal_target_names.size());
Goal_target_names.push_back(util::vm_unique_copy(name, false));
return Goal_target_names.back().get();
Goal_target_names.push_back(vm_strdup(name));
return Goal_target_names[*index];
}
void ai_clear_goal_target_names()
{
for (auto ptr : Goal_target_names)
vm_free(ptr);
Goal_target_names.clear();
}
+5 -9
View File
@@ -42,7 +42,6 @@ typedef struct ai_flag_description {
extern ai_flag_name Ai_flag_names[];
extern ai_flag_description Ai_flag_descriptions[];
extern const int Num_ai_flag_names;
extern const size_t Num_ai_flag_descriptions;
// dock_orient_and_approach() modes.
#define DOA_APPROACH 1 // Approach the current point on the path (aip->path_cur)
@@ -295,7 +294,6 @@ typedef struct ai_info {
vec3d path_create_pos; // Object's position at time of global path creation.
matrix path_create_orient; // Object's orientation at time of global path creation.
int mp_index; // Model path index. Index in polymodel:model_paths
int mp_randomized_vert; // Vertex of the model path that was given a random offset, or -1
fix path_next_check_time; // Last time checked to see if would collide with model.
int path_goal_dist; // minimum distance to first path point to consider path reached
int path_subsystem_next_check; // timestamp to next check if subsystem is still visible
@@ -495,8 +493,8 @@ extern int Mission_all_attack; // !0 means all teams attack all teams.
extern ai_info Ai_info[];
extern ai_info *Player_ai;
extern SCP_vector<ai_class> Ai_classes;
extern SCP_vector<const char*> Ai_class_names;
extern ai_class *Ai_classes;
extern char** Ai_class_names;
extern int Num_ai_classes;
extern int Ai_firing_enabled;
@@ -526,6 +524,7 @@ void ai_object_init(object * obj, int ai_index);
void ai_process( object * obj, int ai_index, float frametime );
const char *ai_get_goal_target_name(const char *name, int *index);
void ai_clear_goal_target_names();
extern void init_ai_system(void);
extern void ai_attack_object(object *attacker, object *attacked, int ship_info_index = -1, int class_type = -1);
@@ -535,7 +534,6 @@ extern void ai_ignore_wing(object *ignorer, int wingnum);
extern void ai_dock_with_object(object *docker, int docker_index, object *dockee, int dockee_index, int dock_type);
extern void ai_stay_still(object *still_objp, vec3d *view_pos);
extern void ai_do_default_behavior(object *obj);
extern void ai_reset_order_state(ai_info *aip);
extern void ai_start_waypoints(object *objp, int wl_index, int wp_flags, int start_index, bool force = false);
extern void ai_ship_hit(object *objp_ship, object *hit_objp, const vec3d *hit_normal);
extern void ai_ship_destroy(int shipnum);
@@ -598,9 +596,7 @@ extern int ai_maybe_fire_afterburner(object *objp, ai_info *aip);
extern void set_predicted_enemy_pos(vec3d *predicted_enemy_pos, object *pobjp, vec3d *enemy_pos, vec3d *enemy_vel, ai_info *aip);
extern int is_instructor(object *objp);
extern int find_enemy(int objnum, float range, int max_attackers, bool for_pursuit, int ship_info_index = -1, int class_type = -1);
extern bool ai_targets_for_pursuit(const ai_info *aip);
extern bool ai_declines_pursuit(const object *attacker_objp, const object *target_objp);
extern int find_enemy(int objnum, float range, int max_attackers, int ship_info_index = -1, int class_type = -1);
float ai_get_weapon_speed(const ship_weapon *swp);
void set_predicted_enemy_pos_turret(vec3d *predicted_enemy_pos, const vec3d *gun_pos, const object *pobjp, const vec3d *enemy_pos, const vec3d *enemy_vel, float weapon_speed, float time_enemy_in_range);
@@ -621,7 +617,7 @@ extern float dock_orient_and_approach(object *docker_objp, int docker_index, obj
void ai_set_mode_warp_out(object *objp, ai_info *aip);
// prototyped by Goober5000
int get_nearest_objnum(int objnum, int enemy_team_mask, int enemy_wing, float range, int max_attackers, bool for_pursuit, int ship_info_index, int class_type = -1);
int get_nearest_objnum(int objnum, int enemy_team_mask, int enemy_wing, float range, int max_attackers, int ship_info_index, int class_type = -1);
// moved to header file by Goober5000
void ai_announce_ship_dying(object *dying_objp);
-19
View File
@@ -132,7 +132,6 @@ namespace AI {
Smart_shield_management,
Smart_subsystem_targeting_for_turrets,
Strict_turret_tagged_only_targeting,
Ships_intercept_mines, // all AI-controlled ships autonomously engage hostile mines within mine_targetable_range of themselves
Support_dont_add_primaries, //Prevents support ship from equipping new primary as requested in https://scp.indiegames.us/mantis/view.php?id=3198
Turrets_ignore_target_radius,
Use_actual_primary_range,
@@ -176,12 +175,6 @@ namespace AI {
Dont_limit_change_in_speed_due_to_physics_whack,
Guards_ignore_protected_attackers,
Fix_standard_strafe,
Fix_ai_target_recovery, // a) strafing ships that lose their target re-process their orders, like chasing ships already do
// b) ships parked in AIM_NONE while holding a standing chase order (attack-any etc.) re-process their orders;
// c) target selection for pursuit (chasing, guard reactions, retaliation) skips ships outside the attacker's
// actively-pursues list; targets held while not chasing are unaffected, and explicitly ordered targets are
// still assigned but not chased or strafed;
// d) enemy_wing is reset when a new order takes over (shared with Fix_stale_ai_order_state)
Standard_strafe_used_more,
Unify_usage_ai_shield_manage_delay,
Fix_AI_shield_management_bug,
@@ -196,18 +189,6 @@ namespace AI {
Do_not_set_override_when_assigning_form_on_wing,
Purge_player_issued_form_on_wing_after_subsequent_order,
Cancel_future_waves_of_any_wing_launched_from_an_exited_ship,
Fix_ignore_if_dead_flag,
Kamikaze_no_collision_avoidance,
Fix_big_ship_waypoint_completion, // a) big ships complete a waypoint within their radius rather than sqrt(radius);
// b) completion no longer requires moving 0.1m in a single frame (framerate-dependent)
Fix_shockwave_expire_before_do_damage, // shockwaves whose lifetime is shorter than one frame apply their area damage at least once before expiring
Fix_small_ai_recover_after_engines_repaired, // ensure small ship AI can switch back to useful AI modes if engines get repaired
Fix_model_path_refresh_randomization, // a subsystem path keeps its randomized point when the path is refreshed because the target moved
Fix_bay_speed_ramp, // the fighterbay speed ramp covers only the bay path itself, not points that route a departing ship around the carrier, and never exceeds max speed
Fix_stale_ai_order_state, // a) enemy_wing, guard_*, previous_mode, resume_goal_time, and the targeted subsystem (with its path) are reset when a new order takes over (enemy_wing is also reset under Fix_ai_target_recovery);
// b) a dynamic chase saves previous_mode/previous_submode; it and strafe entry leave them alone during an ongoing dynamic goal (evading a weapon still overwrites them, which is harmless since the evade resume re-processes orders);
// c) resuming guard duty discards any subsystem target and path left over from the interruption;
// d) a ship ordered to guard itself, or to guard a wing it leads (including one that becomes leader mid-mission), treats that goal as unachievable instead of holding it forever
NUM_VALUES
};
+7 -51
View File
@@ -42,7 +42,6 @@ void set_flag(ai_profile_t *profile, const char *name, AI::Profile_Flags flag)
const char *AI_path_types[] = {
"normal",
"alt1",
"alt2",
};
int Num_ai_path_types = sizeof(AI_path_types)/sizeof(char*);
@@ -140,7 +139,7 @@ void parse_ai_profiles_tbl(const char *filename)
// don't create multiple profiles with the same name
if (previous_profile != NULL)
{
Warning(LOCATION, "An AI profile named '%s' already exists! The new one will not be created.\n", profile_name);
Warning(LOCATION, "An ai profile named '%s' already exists! The new one will not be created.\n", profile_name);
}
else
{
@@ -412,7 +411,7 @@ void parse_ai_profiles_tbl(const char *filename)
set_flag(profile, "$disable player secondary doublefire:", AI::Profile_Flags::Disable_player_secondary_doublefire);
set_flag(profile, "$disable AI secondary doublefire:", AI::Profile_Flags::Disable_ai_secondary_doublefire);
set_flag(profile, "$disable ai secondary doublefire:", AI::Profile_Flags::Disable_ai_secondary_doublefire);
set_flag(profile, "$disable weapon damage scaling:", AI::Profile_Flags::Disable_weapon_damage_scaling);
@@ -450,7 +449,7 @@ void parse_ai_profiles_tbl(const char *filename)
set_flag(profile, "$force beam turrets to use normal fov:", AI::Profile_Flags::Force_beam_turret_fov);
set_flag(profile, "$fix AI class bug:", AI::Profile_Flags::Fix_ai_class_bug);
set_flag(profile, "$fix ai class bug:", AI::Profile_Flags::Fix_ai_class_bug);
set_flag(profile, "$turrets ignore targets radius in range checks:", AI::Profile_Flags::Turrets_ignore_target_radius);
@@ -505,13 +504,13 @@ void parse_ai_profiles_tbl(const char *filename)
profile->ai_path_mode = j;
}
else {
Warning(LOCATION, "Invalid AI path mode '%s' specified", buf);
Warning(LOCATION, "Invalid ai path mode '%s' specified", buf);
}
}
set_flag(profile, "$no warp camera:", AI::Profile_Flags::No_warp_camera);
set_flag(profile, "$fix AI path order bug:", AI::Profile_Flags::Fix_ai_path_order_bug);
set_flag(profile, "$fix ai path order bug:", AI::Profile_Flags::Fix_ai_path_order_bug);
set_flag(profile, "$strict turret-tagged-only targeting:", AI::Profile_Flags::Strict_turret_tagged_only_targeting);
@@ -622,7 +621,7 @@ void parse_ai_profiles_tbl(const char *filename)
profile->ai_range_aware_secondary_select_mode = j;
}
else {
Warning(LOCATION, "Invalid AI secondary range awareness mode '%s' specified", buf);
Warning(LOCATION, "Invalid ai secondary range awareness mode '%s' specified", buf);
}
}
@@ -677,8 +676,6 @@ void parse_ai_profiles_tbl(const char *filename)
set_flag(profile, "$fix standard strafe:", AI::Profile_Flags::Fix_standard_strafe);
set_flag(profile, "$fix AI target recovery:", AI::Profile_Flags::Fix_ai_target_recovery);
set_flag(profile, "$standard strafe used more:", AI::Profile_Flags::Standard_strafe_used_more);
if (optional_string("$standard strafe triggers under this speed:")) {
@@ -693,14 +690,6 @@ void parse_ai_profiles_tbl(const char *filename)
stuff_float(&profile->strafe_max_unhit_time);
}
if (optional_string("$strafe retreat collide time:")) {
stuff_float(&profile->strafe_retreat_collide_time);
}
if (optional_string("$strafe retreat collide distance:")) {
stuff_float(&profile->strafe_retreat_collide_distance);
}
if (optional_string("$guard uses big-orbit for target radius above:")) {
stuff_float(&profile->guard_big_orbit_above_target_radius);
}
@@ -755,23 +744,6 @@ void parse_ai_profiles_tbl(const char *filename)
set_flag(profile, "$cancel future waves of any wing launched from an exited ship:", AI::Profile_Flags::Cancel_future_waves_of_any_wing_launched_from_an_exited_ship);
set_flag(profile, "$ships intercept mines:", AI::Profile_Flags::Ships_intercept_mines);
set_flag(profile, "$fix 'ignore if dead' flag:", AI::Profile_Flags::Fix_ignore_if_dead_flag);
set_flag(profile, "$no collision avoidance for kamikaze fighters:", AI::Profile_Flags::Kamikaze_no_collision_avoidance);
set_flag(profile, "$fix big ship waypoint completion:", AI::Profile_Flags::Fix_big_ship_waypoint_completion);
set_flag(profile, "$fix shockwave expiring before dealing damage:", AI::Profile_Flags::Fix_shockwave_expire_before_do_damage);
set_flag(profile, "$fix fighter/bomber AI recovers after engines repaired:", AI::Profile_Flags::Fix_small_ai_recover_after_engines_repaired);
set_flag(profile, "$fix subsystem path randomization on refresh:", AI::Profile_Flags::Fix_model_path_refresh_randomization);
set_flag(profile, "$fix fighterbay speed ramp:", AI::Profile_Flags::Fix_bay_speed_ramp);
set_flag(profile, "$fix stale AI order state:", AI::Profile_Flags::Fix_stale_ai_order_state);
// end of options ----------------------------------------
@@ -840,7 +812,7 @@ void ai_profiles_init()
Ai_profiles_initted = 1;
}
int ai_profile_lookup(const char *name)
int ai_profile_lookup(char *name)
{
for (int i = 0; i < Num_ai_profiles; i++)
if (!stricmp(name, Ai_profiles[i].profile_name))
@@ -872,8 +844,6 @@ void ai_profile_t::reset()
standard_strafe_when_below_speed = 3.0f;
strafe_retreat_box_dist = 300.0f;
strafe_max_unhit_time = 20.0f;
strafe_retreat_collide_time = 2.0f;
strafe_retreat_collide_distance = 100.0f;
guard_big_orbit_above_target_radius = 500.0f;
guard_big_orbit_max_speed_percent = 1.0f;
@@ -997,18 +967,4 @@ void ai_profile_t::reset()
flags.set(AI::Profile_Flags::Purge_player_issued_form_on_wing_after_subsequent_order);
flags.set(AI::Profile_Flags::Cancel_future_waves_of_any_wing_launched_from_an_exited_ship);
}
if (mod_supports_version(26, 0, 0)) {
flags.set(AI::Profile_Flags::Fix_ignore_if_dead_flag);
}
if (mod_supports_version(26, 2, 0)) {
flags.set(AI::Profile_Flags::Kamikaze_no_collision_avoidance);
flags.set(AI::Profile_Flags::Fix_big_ship_waypoint_completion);
flags.set(AI::Profile_Flags::Fix_shockwave_expire_before_do_damage);
flags.set(AI::Profile_Flags::Fix_small_ai_recover_after_engines_repaired);
flags.set(AI::Profile_Flags::Fix_standard_strafe);
flags.set(AI::Profile_Flags::Fix_ai_target_recovery);
flags.set(AI::Profile_Flags::Fix_model_path_refresh_randomization);
flags.set(AI::Profile_Flags::Fix_bay_speed_ramp);
flags.set(AI::Profile_Flags::Fix_stale_ai_order_state);
}
}
+2 -5
View File
@@ -17,7 +17,6 @@
// AI Path types
#define AI_PATH_MODE_NORMAL 0
#define AI_PATH_MODE_ALT1 1
#define AI_PATH_MODE_ALT2 2
#define AI_RANGE_AWARE_SEC_SEL_MODE_RETAIL 0
#define AI_RANGE_AWARE_SEC_SEL_MODE_AWARE 1
@@ -143,8 +142,6 @@ public:
float standard_strafe_when_below_speed; // Speed at which standard strafing large ships is possibly triggered
float strafe_retreat_box_dist; // Distance beyond the bounding box to retreat to strafing point
float strafe_max_unhit_time; // Maximum amount of time to stay in strafe mode if not hit
float strafe_retreat_collide_time; // When anticipated collision time is less than this, begin retreat from strafe
float strafe_retreat_collide_distance; // When perpendicular distance to *surface* is less than this, begin retreat from strafe
// AI guard options --wookieejedi
float guard_big_orbit_above_target_radius; // Radius of guardee that triggers ai_big_guard()
@@ -163,10 +160,10 @@ extern int Num_ai_profiles;
extern int Default_ai_profile;
extern ai_profile_t Ai_profiles[MAX_AI_PROFILES];
#define AI_PROFILES_INDEX(ai_p) (static_cast<int>((ai_p)-Ai_profiles))
#define AI_PROFILES_INDEX(ai_p) ((int)((ai_p) - Ai_profiles))
void ai_profiles_init();
int ai_profile_lookup(const char *name);
int ai_profile_lookup(char *name);
#endif
+82 -97
View File
@@ -40,6 +40,9 @@
// AI BIG MAGIC NUMBERS
// Select strafing options are now exposed to modders --wookieejedi
#define STRAFE_RETREAT_COLLIDE_TIME 2.0 // when anticipated collision time is less than this, begin retreat
#define STRAFE_RETREAT_COLLIDE_DIST 100 // when perpendicular distance to *surface* is less than this, begin retreat
#define EVADE_BOX_BASE_DISTANCE 300 // standard distance to end evade submode
#define EVADE_BOX_MIN_DISTANCE 200 // minimun distance to end evade submode, after long time
@@ -66,16 +69,6 @@ static bool ai_big_strafe_maybe_retreat(const vec3d *target_pos);
extern void compute_desired_rvec(vec3d *rvec, const vec3d *goal_pos, const vec3d *cur_pos);
extern void big_ship_collide_recover_start(const object *objp, const object *big_objp, const vec3d *collision_normal);
// Record the mode being left as the one to return to, unless a dynamic goal is already in progress
// (in which case previous_mode still refers to the mode that goal interrupted).
static void ai_big_save_previous_mode(ai_info *aip)
{
if (The_mission.ai_profile->flags[AI::Profile_Flags::Fix_stale_ai_order_state] && aip->active_goal == AI_ACTIVE_GOAL_DYNAMIC)
return;
aip->previous_mode = aip->mode;
}
// Called by ai_big_pick_attack_point.
// Generates a random attack point.
@@ -509,7 +502,7 @@ bool ai_big_maybe_follow_subsys_path(bool do_dot_check)
// for now, only follow the path to the first point
if ( aip->path_cur < (aip->path_start+aip->path_length-1) ) {
if ( aip->goal_objnum != aip->target_objnum ) {
ai_big_save_previous_mode(aip);
aip->previous_mode = aip->mode;
aip->mode = AIM_NONE;
aip->submode = -1;
aip->submode_start_time = Missiontime;
@@ -716,8 +709,7 @@ void ai_big_chase_attack(ai_info *aip, ship_info *sip, vec3d *enemy_pos, float d
if (vm_vec_dot(&in_vec, &objp->orient.vec.fvec) > 0.0f) {
dist = vm_vec_normalize(&in_vec);
if ((dist < 200.0f) && (vm_vec_dot(&in_vec, &objp->orient.vec.fvec) > 0.95f)) {
if ((Objects[objp->parent].signature == objp->parent_sig) && (vm_vec_dist_quick(&objp->pos, &Objects[objp->parent].pos) < 300.0f)
&& !ai_declines_pursuit(Pl_objp, &Objects[objp->parent])) {
if ((Objects[objp->parent].signature == objp->parent_sig) && (vm_vec_dist_quick(&objp->pos, &Objects[objp->parent].pos) < 300.0f)) {
set_target_objnum(aip, objp->parent);
aip->submode = SM_ATTACK;
aip->submode_start_time = Missiontime;
@@ -738,7 +730,7 @@ void ai_big_chase_attack(ai_info *aip, ship_info *sip, vec3d *enemy_pos, float d
// including ai_profile flag and if enemy fighters are near
if (Pl_objp->phys_info.speed < The_mission.ai_profile->standard_strafe_when_below_speed &&
(The_mission.ai_profile->flags[AI::Profile_Flags::Standard_strafe_used_more] || ai_big_maybe_start_strafe(aip, sip))) {
ai_big_save_previous_mode(aip);
aip->previous_mode = aip->mode;
aip->mode = AIM_STRAFE;
aip->submode_parm0 = Missiontime; // use parm0 as time strafe mode entered (i.e. MODE start time)
ai_big_strafe_position();
@@ -747,7 +739,7 @@ void ai_big_chase_attack(ai_info *aip, ship_info *sip, vec3d *enemy_pos, float d
//Maybe enter glide strafe (check every 8 seconds, on a different schedule for each ship)
if ((sip->can_glide == true) && !(aip->ai_flags[AI::AI_Flags::Kamikaze]) && static_randf((Missiontime + static_rand(aip->shipnum)) >> 19) < aip->ai_glide_strafe_percent) {
ai_big_save_previous_mode(aip);
aip->previous_mode = aip->mode;
aip->mode = AIM_STRAFE;
aip->submode_parm0 = Missiontime; // use parm0 as time strafe mode entered (i.e. MODE start time)
aip->submode = AIS_STRAFE_GLIDE_ATTACK;
@@ -1019,7 +1011,7 @@ static void ai_big_maybe_fire_weapons(float dist_to_enemy, float dot_to_enemy)
// switch ai ship into chase mode
void ai_big_switch_to_chase_mode(ai_info *aip)
{
ai_big_save_previous_mode(aip);
aip->previous_mode = aip->mode;
aip->mode = AIM_CHASE;
aip->submode = SM_ATTACK;
aip->submode_start_time = Missiontime;
@@ -1119,7 +1111,7 @@ void ai_big_chase()
} else if (En_objp->flags[Object::Object_Flags::Protected]) { // If protected and we're not attacking a subsystem, stop attacking!
update_aspect_lock_information(aip, &vec_to_enemy, dist_to_enemy - En_objp->radius, En_objp->radius);
aip->target_objnum = -1;
if (find_enemy(OBJ_INDEX(Pl_objp), MAX_ENEMY_DISTANCE, The_mission.ai_profile->max_attackers[Game_skill_level], ai_targets_for_pursuit(aip)) == -1) {
if (find_enemy(OBJ_INDEX(Pl_objp), MAX_ENEMY_DISTANCE, The_mission.ai_profile->max_attackers[Game_skill_level]) == -1) {
ai_do_default_behavior(Pl_objp);
return;
}
@@ -1206,78 +1198,70 @@ void ai_big_chase()
}
// If a collision is expected, pull out!
if (!(The_mission.ai_profile->flags[AI::Profile_Flags::Kamikaze_no_collision_avoidance] && aip->ai_flags[AI::AI_Flags::Kamikaze])) {
float dist_normal_to_enemy;
float dist_normal_to_enemy;
if (vm_vec_mag_squared(&aip->big_attack_surface_normal) > 0.9) {
if (aip->ai_profile_flags[AI::Profile_Flags::Improved_subsystem_attack_pathing])
dist_normal_to_enemy = fl_abs((dist_to_enemy / vm_vec_dot(&vec_to_enemy, &aip->big_attack_surface_normal)));
else // I'm fairly sure this retail code VVV meant to use / instead of *
dist_normal_to_enemy = fl_abs((dist_to_enemy * vm_vec_dot(&vec_to_enemy, &aip->big_attack_surface_normal)));
}
else {
// don;t have normal so use a conservative value here
dist_normal_to_enemy = 0.3f * dist_to_enemy;
}
// float time_to_enemy = dist_normal_to_enemy / Pl_objp->phys_info.speed * fl_abs(vm_vec_dot(&Pl_objp->phys_info.vel, &aip->big_attack_surface_normal));
// if (Framecount % 30 == 1) {
// mprintf(("normal dist; %.1f, time: %.1f\n", dist_normal_to_enemy, time_to_enemy));
// }
// since we're not in strafe and we may get a bad normal, cap dist_normal_to_enemy as MIN(0.3*dist_to_enemy, self)
// this will allow us to get closer on a bad normal
dist_normal_to_enemy = MAX(0.3f * dist_to_enemy, dist_normal_to_enemy);
if (dist_to_enemy < ATTACK_COLLIDE_BASE_DIST) {
// within 50m or 1sec
float time_to_enemy;
if (vm_vec_mag_squared(&aip->big_attack_surface_normal) > 0.9) {
if (Pl_objp->phys_info.speed > 0.1) {
time_to_enemy = dist_normal_to_enemy / fl_abs(vm_vec_dot(&Pl_objp->phys_info.vel, &aip->big_attack_surface_normal));
}
else {
// a big time
time_to_enemy = 100.0f;
}
}
else {
if (Pl_objp->phys_info.speed > 0.1) {
time_to_enemy = dist_normal_to_enemy / Pl_objp->phys_info.speed;
}
else {
// a big time
time_to_enemy = 100.0f;
}
}
float speed_dist = MAX(0.0f, (Pl_objp->phys_info.speed - 50) * 2);
if ((dist_normal_to_enemy < ATTACK_COLLIDE_AVOID_DIST + speed_dist) || (time_to_enemy < ATTACK_COLLIDE_AVOID_TIME)) {
// get away, simulate crsh recovery (don't use avoid)
// accelerate_ship(aip, -1.0f);
big_ship_collide_recover_start(Pl_objp, En_objp, nullptr);
// aip->submode = SM_AVOID;
// aip->submode_start_time = Missiontime;
}
else if ((dist_normal_to_enemy < ATTACK_COLLIDE_SLOW_DIST) || (time_to_enemy < ATTACK_COLLIDE_SLOW_TIME)) {
// slow down
accelerate_ship(aip, -1.0f);
}
}
/*
if ((dot_to_enemy > 1.0f - 0.1f * En_objp->radius/(dist_to_enemy + 1.0f)) && (Pl_objp->phys_info.speed > dist_to_enemy/5.0f)) {
if (might_collide_with_ship(Pl_objp, En_objp, dot_to_enemy, dist_to_enemy, (aip->targeted_subsys == NULL)*2.0f + 1.5f)) {
if ((Missiontime - aip->last_hit_time > F1_0*4) && (dist_to_enemy < Pl_objp->radius*2 + En_objp->radius*2)) {
accelerate_ship(aip, -1.0f);
} else {
aip->submode = SM_AVOID;
aip->submode_start_time = Missiontime;
}
}
} */
if (vm_vec_mag_squared(&aip->big_attack_surface_normal) > 0.9) {
if (aip->ai_profile_flags[AI::Profile_Flags::Improved_subsystem_attack_pathing])
dist_normal_to_enemy = fl_abs((dist_to_enemy / vm_vec_dot(&vec_to_enemy, &aip->big_attack_surface_normal)));
else // I'm fairly sure this retail code VVV meant to use / instead of *
dist_normal_to_enemy = fl_abs((dist_to_enemy * vm_vec_dot(&vec_to_enemy, &aip->big_attack_surface_normal)));
} else {
// don;t have normal so use a conservative value here
dist_normal_to_enemy = 0.3f * dist_to_enemy;
}
// float time_to_enemy = dist_normal_to_enemy / Pl_objp->phys_info.speed * fl_abs(vm_vec_dot(&Pl_objp->phys_info.vel, &aip->big_attack_surface_normal));
// if (Framecount % 30 == 1) {
// mprintf(("normal dist; %.1f, time: %.1f\n", dist_normal_to_enemy, time_to_enemy));
// }
// since we're not in strafe and we may get a bad normal, cap dist_normal_to_enemy as MIN(0.3*dist_to_enemy, self)
// this will allow us to get closer on a bad normal
dist_normal_to_enemy = MAX(0.3f*dist_to_enemy, dist_normal_to_enemy);
if (dist_to_enemy < ATTACK_COLLIDE_BASE_DIST) {
// within 50m or 1sec
float time_to_enemy;
if (vm_vec_mag_squared(&aip->big_attack_surface_normal) > 0.9) {
if (Pl_objp->phys_info.speed > 0.1) {
time_to_enemy = dist_normal_to_enemy / fl_abs(vm_vec_dot(&Pl_objp->phys_info.vel, &aip->big_attack_surface_normal));
} else {
// a big time
time_to_enemy = 100.0f;
}
} else {
if (Pl_objp->phys_info.speed > 0.1) {
time_to_enemy = dist_normal_to_enemy / Pl_objp->phys_info.speed;
} else {
// a big time
time_to_enemy = 100.0f;
}
}
float speed_dist = MAX(0.0f, (Pl_objp->phys_info.speed-50) * 2);
if ((dist_normal_to_enemy < ATTACK_COLLIDE_AVOID_DIST + speed_dist) || (time_to_enemy < ATTACK_COLLIDE_AVOID_TIME) ) {
// get away, simulate crsh recovery (don't use avoid)
// accelerate_ship(aip, -1.0f);
big_ship_collide_recover_start(Pl_objp, En_objp, nullptr);
// aip->submode = SM_AVOID;
// aip->submode_start_time = Missiontime;
} else if ((dist_normal_to_enemy < ATTACK_COLLIDE_SLOW_DIST) || (time_to_enemy < ATTACK_COLLIDE_SLOW_TIME) ) {
// slow down
accelerate_ship(aip, -1.0f);
}
}
/*
if ((dot_to_enemy > 1.0f - 0.1f * En_objp->radius/(dist_to_enemy + 1.0f)) && (Pl_objp->phys_info.speed > dist_to_enemy/5.0f)) {
if (might_collide_with_ship(Pl_objp, En_objp, dot_to_enemy, dist_to_enemy, (aip->targeted_subsys == NULL)*2.0f + 1.5f)) {
if ((Missiontime - aip->last_hit_time > F1_0*4) && (dist_to_enemy < Pl_objp->radius*2 + En_objp->radius*2)) {
accelerate_ship(aip, -1.0f);
} else {
aip->submode = SM_AVOID;
aip->submode_start_time = Missiontime;
}
}
} */
}
switch (aip->submode) {
@@ -1460,8 +1444,8 @@ static bool ai_big_strafe_maybe_retreat(const vec3d *target_pos)
collide_time = false;
collide_distance = false;
} else {
collide_time = (Pl_objp->phys_info.speed > 0.0f) && (dist_to_target / Pl_objp->phys_info.speed) < (The_mission.ai_profile->strafe_retreat_collide_time);
collide_distance = dist_to_target < ((The_mission.ai_profile->strafe_retreat_collide_distance) + speed_to_dist_penalty);
collide_time = (dist_to_target / Pl_objp->phys_info.speed) < STRAFE_RETREAT_COLLIDE_TIME;
collide_distance = dist_to_target < (STRAFE_RETREAT_COLLIDE_DIST + speed_to_dist_penalty);
}
} else {
float dist_normal_to_target;
@@ -1471,8 +1455,8 @@ static bool ai_big_strafe_maybe_retreat(const vec3d *target_pos)
} else {
dist_normal_to_target = 0.2f * dist_to_target;
}
collide_time = (Pl_objp->phys_info.speed > 0.0f) && (dist_normal_to_target / Pl_objp->phys_info.speed) < (The_mission.ai_profile->strafe_retreat_collide_time);
collide_distance = dist_normal_to_target < ((The_mission.ai_profile->strafe_retreat_collide_distance) + speed_to_dist_penalty);
collide_time = (dist_normal_to_target / Pl_objp->phys_info.speed) < STRAFE_RETREAT_COLLIDE_TIME;
collide_distance = dist_normal_to_target < (STRAFE_RETREAT_COLLIDE_DIST + speed_to_dist_penalty);
}
//if ((dot_to_enemy > 1.0f - 0.1f * En_objp->radius/(dist_to_enemy + 1.0f)) && (Pl_objp->phys_info.speed > dist_to_enemy/5.0f))
@@ -1878,7 +1862,7 @@ void ai_big_strafe()
/*
if ( aip->goal_objnum != aip->target_objnum ) {
Assertion(false, "The goal objnum does not match the target objnum in ai_big_strafe(), please report to the SCP!"); // what is going on here? - Get Alan
UNREACHABLE("The goal objnum does not match the target objnum in ai_big_strafe(), please report to the SCP!"); // what is going on here? - Get Alan
aip->mode = AIM_NONE;
return;
}
@@ -1979,25 +1963,26 @@ int ai_big_maybe_enter_strafe_mode(const object *pl_objp, int weapon_objnum)
return 0;
}
if (ai_declines_pursuit(pl_objp, parent_objp)) {
return 0;
}
// Maybe the ship which fired the weapon isn't the current target
if ( OBJ_INDEX(parent_objp) != aip->target_objnum ) {
//JAS IMPOSSIBLE if (1) { // consider_target_only ) {
//JAS IMPOSSIBLE return 0;
//JAS IMPOSSIBLE } else {
// switch targets
sip = &Ship_info[Ships[parent_objp->instance].ship_info_index];
if ( !(sip->is_big_or_huge()) || (sip->flags[Ship::Info_Flags::Transport]) ) {
return 0;
}
set_target_objnum(aip, OBJ_INDEX(parent_objp));
//JAS IMPOSSIBLE }
}
ai_big_strafe_maybe_attack_turret(pl_objp, weapon_objp);
// if we've got this far, the weapon must have come from the player's target, and it is a
// big/capital ship... so enter strafe mode
ai_big_save_previous_mode(aip);
aip->previous_mode = aip->mode;
aip->mode = AIM_STRAFE;
aip->submode_parm0 = Missiontime; // use parm0 as time strafe mode entered (i.e. MODE start time)
aip->submode = AIS_STRAFE_AVOID;
+179 -494
View File
File diff suppressed because it is too large. Load diff
View File
Whitespace-only changes.
+19 -72
View File
@@ -825,8 +825,7 @@ void ai_add_goal_sub_player(ai_goal_type type, ai_goal_mode mode, int submode, c
// friendlies want to rearm at the same time. The support ship forgets what it's doing and flies
// off to repair somebody while still docked. I reproduced this with retail, so it's not a bug in
// my new docking code. :)
// Note that this function is now where Purge_when_new_goal_added is checked to set the Purge flag.
int ai_goal_allocate_slot( ai_goal *goals, int active_goal )
int ai_goal_find_empty_slot( ai_goal *goals, int active_goal )
{
int oldest_index = -1, first_empty_index = -1;
@@ -911,29 +910,12 @@ void ai_add_goal_sub_scripting(ai_goal_type type, ai_goal_mode mode, int submode
}
}
// find a dockpoint on the given ship that is compatible with the specified dock-type flags (c.f. ai_goal_fixup_dockpoints)
static int ai_goal_find_compatible_dockpoint(int shipnum, int type_flags)
{
for (int i = 0; i < Num_dock_type_names; i++)
{
if (type_flags & Dock_type_names[i].def)
{
int dock_index = ai_goal_find_dockpoint(shipnum, Dock_type_names[i].def);
if (dock_index >= 0)
return dock_index;
}
}
// no compatible type-specific point found; fall back to a generic one
return ai_goal_find_dockpoint(shipnum, DOCK_TYPE_GENERIC);
}
void ai_add_ship_goal_scripting(ai_goal_mode mode, int submode, int priority, const char *shipname, ai_info *aip, int int_data, float float_data, int docker_index, int dockee_index)
void ai_add_ship_goal_scripting(ai_goal_mode mode, int submode, int priority, const char *shipname, ai_info *aip, int int_data, float float_data)
{
int empty_index;
ai_goal *aigp;
empty_index = ai_goal_allocate_slot(aip->goals, aip->active_goal);
empty_index = ai_goal_find_empty_slot(aip->goals, aip->active_goal);
aigp = &aip->goals[empty_index];
ai_add_goal_sub_scripting(ai_goal_type::PLAYER_SHIP, mode, submode, priority, shipname, aigp, int_data, float_data);
@@ -944,27 +926,7 @@ void ai_add_ship_goal_scripting(ai_goal_mode mode, int submode, int priority, co
}
if ( (mode == AI_GOAL_REARM_REPAIR) || (mode == AI_GOAL_DOCK) ) {
// if the caller specified one or both dockpoints, honor them and choose the other side to match
if ( mode == AI_GOAL_DOCK && (docker_index >= 0 || dockee_index >= 0) ) {
int dockee_shipnum = ship_name_lookup(shipname);
Assertion(dockee_shipnum >= 0, "Couldn't find dock target '%s'; get a coder!", shipname);
// if only one point was given, choose the other to match its dock type
if ( docker_index < 0 ) {
polymodel *dockee_pm = model_get(Ship_info[Ships[dockee_shipnum].ship_info_index].model_num);
docker_index = ai_goal_find_compatible_dockpoint(aip->shipnum, dockee_pm->docking_bays[dockee_index].type_flags);
} else if ( dockee_index < 0 ) {
polymodel *docker_pm = model_get(Ship_info[Ships[aip->shipnum].ship_info_index].model_num);
dockee_index = ai_goal_find_compatible_dockpoint(dockee_shipnum, docker_pm->docking_bays[docker_index].type_flags);
}
aigp->docker.index = docker_index;
aigp->dockee.index = dockee_index;
aigp->flags.set(AI::Goal_Flags::Docker_index_valid);
aigp->flags.set(AI::Goal_Flags::Dockee_index_valid);
} else {
ai_goal_fixup_dockpoints( aip, aigp );
}
ai_goal_fixup_dockpoints( aip, aigp );
}
}
@@ -977,7 +939,7 @@ void ai_add_ship_goal_player(ai_goal_type type, ai_goal_mode mode, int submode,
int empty_index;
ai_goal *aigp;
empty_index = ai_goal_allocate_slot( aip->goals, aip->active_goal );
empty_index = ai_goal_find_empty_slot( aip->goals, aip->active_goal );
aigp = &aip->goals[empty_index];
ai_add_goal_sub_player( type, mode, submode, shipname, aigp, int_data, float_data, lua_target );
@@ -1011,7 +973,7 @@ void ai_add_wing_goal_player(ai_goal_type type, ai_goal_mode mode, int submode,
// add the sexpression index into the wing's list of goal sexpressions if
// there are more waves to come. We use the same method here as when adding a goal to
// a ship -- find the first empty entry. If none exists, take the oldest entry and replace it.
empty_index = ai_goal_allocate_slot( wingp->ai_goals, -1 );
empty_index = ai_goal_find_empty_slot( wingp->ai_goals, -1 );
ai_add_goal_sub_player( type, mode, submode, shipname, &wingp->ai_goals[empty_index], int_data, float_data, lua_target );
}
@@ -1290,7 +1252,7 @@ void ai_add_goal_sub_sexp( int sexp, ai_goal_type type, ai_info *aip, ai_goal *a
} else if ( op == OP_AI_IGNORE_NEW ) {
aigp->ai_mode = AI_GOAL_IGNORE_NEW;
} else
UNREACHABLE("Coding error: unhandled AI goal %d in ai_add_goal_sub_sexp!", op);
UNREACHABLE("Coding error: unhandled AI goal in ai_add_goal_sub_sexp!");
break;
@@ -1651,7 +1613,7 @@ void ai_add_ship_goal_sexp( int sexp, ai_goal_type type, ai_info *aip )
{
int gindex;
gindex = ai_goal_allocate_slot( aip->goals, aip->active_goal );
gindex = ai_goal_find_empty_slot( aip->goals, aip->active_goal );
ai_add_goal_sub_sexp( sexp, type, aip, &aip->goals[gindex], Ships[aip->shipnum].ship_name );
}
@@ -1675,7 +1637,7 @@ void ai_add_wing_goal_sexp(int sexp, ai_goal_type type, wing *wingp)
if ((wingp->num_waves - wingp->current_wave > 0) || Fred_running) {
int gindex;
gindex = ai_goal_allocate_slot( wingp->ai_goals, -1 );
gindex = ai_goal_find_empty_slot( wingp->ai_goals, -1 );
ai_add_goal_sub_sexp( sexp, type, nullptr, &wingp->ai_goals[gindex], wingp->name );
}
}
@@ -1698,7 +1660,7 @@ void ai_add_goal_ship_internal( ai_info *aip, int goal_type, char *name, int /*
Assertion(strcmp(name, Ships[aip->shipnum].ship_name) != 0, "The goals apply to the actor in ai_add_goal_ship_internal for ship %s, please report to the SCP!", name);
// find an empty slot to put this goal in.
gindex = ai_goal_allocate_slot( aip->goals, aip->active_goal );
gindex = ai_goal_find_empty_slot( aip->goals, aip->active_goal );
aigp = &(aip->goals[gindex]);
ai_goal_reset(aigp, true);
@@ -1803,20 +1765,6 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
auto target_ship_entry = aigp->target_name == nullptr ? nullptr : ship_registry_get(aigp->target_name);
// a ship can't guard itself, and the leader of a wing is the ship the rest of the wing guards
if (The_mission.ai_profile->flags[AI::Profile_Flags::Fix_stale_ai_order_state])
{
if (aigp->ai_mode == AI_GOAL_GUARD && target_ship_entry && target_ship_entry->has_shipp() && target_ship_entry->shipp() == shipp)
return ai_achievability::NOT_ACHIEVABLE;
if (aigp->ai_mode == AI_GOAL_GUARD_WING)
{
int wingnum = wing_name_lookup(aigp->target_name);
if (wingnum >= 0 && Wings[wingnum].ship_index[0] == objp->instance)
return ai_achievability::NOT_ACHIEVABLE;
}
}
// warp (depart) only achievable if there's somewhere to depart to
if (aigp->ai_mode == AI_GOAL_WARP)
{
@@ -1841,7 +1789,7 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
if (!target_ship_entry || !target_ship_entry->has_shipp())
return ai_achievability::NOT_ACHIEVABLE;
// the override flag is now set in the calling function, validate_mission_goals
// the override flag is now set in the calling function, ai_mission_goal_achievable
return ai_achievability::ACHIEVABLE;
}
@@ -2107,7 +2055,7 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
if (target_ship_entry->shipp()->subsys_info[SUBSYSTEM_TURRET].type_count == 0)
return ai_achievability::NOT_ACHIEVABLE;
} else {
Assertion(false, "Target name %s is not an arrived ship!", aigp->target_name);
UNREACHABLE("Target name %s is not an arrived ship!", aigp->target_name);
return ai_achievability::NOT_ACHIEVABLE; // force this goal to be invalid
}
}
@@ -2156,8 +2104,8 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
return ai_achievability::NOT_KNOWN;
// we must also determine if we're prevented from docking for any reason
Assertion(target_ship_entry && target_ship_entry->has_shipp(), "Target name %s is not an arrived ship!", aigp->target_name);
if (!target_ship_entry || !target_ship_entry->has_shipp()) {
UNREACHABLE("Target name %s is not an arrived ship!", aigp->target_name);
return ai_achievability::NOT_ACHIEVABLE; // force this goal to be invalid
}
auto goal_objp = target_ship_entry->objp();
@@ -2214,7 +2162,7 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
if (aip->goal_objnum != target_ship_entry->objnum)
return ai_achievability::NOT_KNOWN;
} else {
Assertion(false, "Target name %s is not an arrived ship!", aigp->target_name);
UNREACHABLE("Target name %s is not an arrived ship!", aigp->target_name);
return ai_achievability::NOT_ACHIEVABLE; // force this goal to be invalid
}
}
@@ -2228,14 +2176,14 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
aigp->ai_submode = ship_find_subsys( target_ship_entry->shipp(), aigp->docker.name );
aigp->flags.remove(AI::Goal_Flags::Subsys_needs_fixup);
} else {
Assertion(false, "Target name %s is not an arrived ship!", aigp->target_name);
UNREACHABLE("Target name %s is not an arrived ship!", aigp->target_name);
return ai_achievability::NOT_ACHIEVABLE; // force this goal to be invalid
}
}
} else if ( ((aigp->ai_mode == AI_GOAL_IGNORE) || (aigp->ai_mode == AI_GOAL_IGNORE_NEW)) && (status == SHIP_STATUS_ARRIVED) ) {
// for ignoring a ship, call the ai_ignore object function, then declare the goal satisfied
Assertion(target_ship_entry && target_ship_entry->has_objp(), "Target name %s is not an arrived ship!", aigp->target_name);
if (!target_ship_entry || !target_ship_entry->has_objp()) {
UNREACHABLE("Target name %s is not an arrived ship!", aigp->target_name);
return ai_achievability::NOT_ACHIEVABLE; // force this goal to be invalid
}
auto ignored = target_ship_entry->objp();
@@ -2284,16 +2232,16 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
{
// short circuit a couple of cases. Ship not arrived shouldn't happen. Ship gone means
// we mark the goal as not achievable.
Assertion(status != SHIP_STATUS_NOT_ARRIVED, "Ship %s cannot rearm a target %s that hasn't arrived; get Allender or a SCP member", shipp->ship_name, aigp->target_name); // get Allender. this shouldn't happen!!!
if ( status == SHIP_STATUS_NOT_ARRIVED ) {
UNREACHABLE("Ship %s cannot rearm a target %s that hasn't arrived; get Allender or a SCP member", shipp->ship_name, aigp->target_name); // get Allender. this shouldn't happen!!!
return ai_achievability::NOT_ACHIEVABLE;
}
if ( status == SHIP_STATUS_GONE )
return ai_achievability::NOT_ACHIEVABLE;
Assertion(target_ship_entry && target_ship_entry->has_shipp(), "Target name %s is not an arrived ship!", aigp->target_name);
if ( !target_ship_entry || !target_ship_entry->has_shipp() ) {
UNREACHABLE("Target name %s is not an arrived ship!", aigp->target_name);
return ai_achievability::NOT_ACHIEVABLE;
}
@@ -2549,9 +2497,8 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
if ( !(Player_use_ai) && (objp->flags[Object::Object_Flags::Player_ship]) && (current_goal->ai_mode != AI_GOAL_FORM_ON_WING) )
{
return;
}
}
ai_reset_order_state(aip);
std::unique_ptr<ai_goal> current_goal_backup;
auto current_goal_target_ship = current_goal->target_name ? ship_registry_get(current_goal->target_name) : nullptr;
+1 -5
View File
@@ -106,10 +106,6 @@ inline bool ai_goal_is_specific_chase(ai_goal_mode ai_mode)
{
return ai_mode == AI_GOAL_CHASE || ai_mode == AI_GOAL_CHASE_WING || ai_mode == AI_GOAL_CHASE_SHIP_CLASS || ai_mode == AI_GOAL_CHASE_SHIP_TYPE;
}
inline bool ai_goal_is_standing_chase(ai_goal_mode ai_mode)
{
return ai_mode == AI_GOAL_CHASE_ANY;
}
enum class ai_achievability { ACHIEVABLE, NOT_ACHIEVABLE, NOT_KNOWN, SATISFIED };
@@ -183,7 +179,7 @@ extern void ai_process_mission_orders( int objnum, ai_info *aip );
extern int ai_goal_num(ai_goal *goals);
// adds goals to ships/wing through sexpressions
extern void ai_add_ship_goal_scripting(ai_goal_mode mode, int submode, int priority, const char *shipname, ai_info *aip, int int_data, float float_data, int docker_index = -1, int dockee_index = -1);
extern void ai_add_ship_goal_scripting(ai_goal_mode mode, int submode, int priority, const char *shipname, ai_info *aip, int int_data, float float_data);
extern void ai_add_ship_goal_sexp(int sexp, ai_goal_type type, ai_info *aip);
extern void ai_add_wing_goal_sexp(int sexp, ai_goal_type type, wing *wingp);
extern void ai_add_goal_sub_sexp(int sexp, ai_goal_type type, ai_info *aip, ai_goal *aigp, const char *actor_name);
+96 -60
View File
@@ -350,18 +350,6 @@ const weapon_info *get_turret_weapon_wip(const ship_weapon *swp, int weapon_num)
return &Weapon_info[wi_index];
}
// similar to the above, since "weapon_num" is a bank index over multiple banks
static std::pair<int, int> get_turret_weapon_bank(int weapon_num)
{
int pbank = -1;
int sbank = -1;
if (weapon_num >= MAX_SHIP_PRIMARY_BANKS)
sbank = weapon_num - MAX_SHIP_PRIMARY_BANKS;
else
pbank = weapon_num;
return { pbank, sbank };
}
int get_turret_weapon_next_fire_stamp(const ship_weapon *swp, int weapon_num)
{
Assert(weapon_num < MAX_SHIP_WEAPONS);
@@ -491,12 +479,6 @@ int valid_turret_enemy(object *objp, object *turret_parent)
return 0;
}
// Mines are only targetable within their configured detection range
if (wip->is_mine()) {
if (vm_vec_dist(&objp->pos, &turret_parent->pos) > wip->mine_targetable_range)
return 0;
}
return 1;
}
@@ -1107,8 +1089,7 @@ int find_turret_enemy(const ship_subsys *turret_subsys, int objnum, const vec3d
int target_objnum = aip->target_objnum;
if (Objects[target_objnum].signature == aip->target_signature) {
// The parent's target can be a weapon or an asteroid, so make sure it's a ship before indexing Ships[]
ship* target_shipp = (Objects[target_objnum].type == OBJ_SHIP) ? &Ships[Objects[target_objnum].instance] : nullptr;
ship* target_shipp = &Ships[Objects[target_objnum].instance];
if (target_shipp && iff_matches_mask(target_shipp->team, enemy_team_mask)) {
if (!(Objects[target_objnum].flags[Object::Object_Flags::Protected])) { // check this flag as well
// nprintf(("AI", "Frame %i: Object %i resuming goal of object %i\n", AI_FrameCount, objnum,
@@ -1741,7 +1722,6 @@ bool turret_fire_weapon(int weapon_num,
auto wip = get_turret_weapon_wip(&turret->weapons, weapon_num);
if (!wip)
return false;
auto [turret_pbank, turret_sbank] = get_turret_weapon_bank(weapon_num);
bool in_lab = (gameseq_get_state() == GS_STATE_LAB);
@@ -1768,7 +1748,7 @@ bool turret_fire_weapon(int weapon_num,
parent_aip = &Ai_info[Ships[Objects[parent_objnum].instance].ai_index];
parent_ship = &Ships[Objects[parent_objnum].instance];
int turret_weapon_class = WEAPON_INFO_INDEX(wip);
int turret_weapon_class = weapon_info_get_index(wip);
#ifndef NDEBUG
// moved here from check_ok_to_fire
@@ -1852,7 +1832,6 @@ bool turret_fire_weapon(int weapon_num,
else
fire_info.target_subsys = nullptr;
fire_info.turret = turret;
fire_info.bank = turret_pbank;
fire_info.burst_seed = old_burst_seed;
fire_info.fire_method = BFM_TURRET_FIRED;
fire_info.per_burst_rotation = swp->per_burst_rot;
@@ -1865,6 +1844,7 @@ bool turret_fire_weapon(int weapon_num,
fire_info.target_pos1 = turret->last_aim_enemy_pos;
}
// fire a beam weapon
weapon_objnum = beam_fire(&fire_info);
@@ -1890,53 +1870,113 @@ bool turret_fire_weapon(int weapon_num,
}
// don't fire swam, but set up swarm info instead
else if ((wip->wi_flags[Weapon::Info_Flags::Swarm]) || (wip->wi_flags[Weapon::Info_Flags::Corkscrew])) {
// swarm and corkscrew are not restricted to missiles, so check whichever bank is actually firing
if (!in_lab && (turret->system_info->flags[Model::Subsystem_Flags::Turret_use_ammo])) {
bool has_ammo = (turret_pbank >= 0)
? swp->primary_bank_ammo[turret_pbank] > 0
: ship_secondary_has_ammo(swp, turret_sbank);
if (!has_ammo)
return false;
if (swp->current_secondary_bank < 0) {
swp->current_secondary_bank = 0;
}
int bank_to_fire = swp->current_secondary_bank;
if (!in_lab && (turret->system_info->flags[Model::Subsystem_Flags::Turret_use_ammo]) && !ship_secondary_has_ammo(swp, bank_to_fire)) {
if (!(turret->system_info->flags[Model::Subsystem_Flags::Use_multiple_guns])) {
swp->current_secondary_bank++;
if (swp->current_secondary_bank >= swp->num_secondary_banks) {
swp->current_secondary_bank = 0;
}
return false;
} else {
return false;
}
} else {
turret_swarm_set_up_info(parent_objnum, turret, wip, turret->turret_next_fire_pos, in_lab);
turret_swarm_set_up_info(parent_objnum, turret, wip, turret->turret_next_fire_pos, turret_pbank, turret_sbank, in_lab);
turret->flags.set(Ship::Subsystem_Flags::Has_fired); //set fired flag for scripting -nike
return true;
turret->flags.set(Ship::Subsystem_Flags::Has_fired); //set fired flag for scripting -nike
return true;
}
}
// now do anything else
else {
float shots_mult = wip->weapon_launch_curves.get_output(weapon_info::WeaponLaunchCurveOutputs::SHOTS_MULT, launch_curve_data);
int shots = fl2i(i2fl(wip->shots) * shots_mult);
// note that wip is reassigned to the created weapon's class inside the loop, so any
// property of the bank's own weapon must be read before we get there
bool no_ammo_needed = (turret_sbank >= 0) && Weapon_info[swp->secondary_bank_weapons[turret_sbank]].wi_flags[Weapon::Info_Flags::SecondaryNoAmmo];
for (int i = 0; i < shots; i++) {
if (!in_lab && turret->system_info->flags[Model::Subsystem_Flags::Turret_use_ammo]) {
if (turret_pbank >= 0) {
int bank_to_fire, num_slots = turret->system_info->turret_num_firing_points;
if (wip->subtype == WP_LASER) {
int points;
if (swp->num_primary_banks <= 0) {
return false;
}
if (swp->current_primary_bank < 0){
swp->current_primary_bank = 0;
return false;
}
int num_primary_banks = swp->num_primary_banks;
Assert(num_primary_banks > 0);
if (num_primary_banks < 1){
return false;
}
bank_to_fire = swp->current_primary_bank;
if (turret->system_info->flags[Model::Subsystem_Flags::Turret_salvo]) {
points = turret->system_info->turret_num_firing_points;
points = num_slots;
} else {
points = 1;
}
if (swp->primary_bank_ammo[turret_pbank] >= points) {
swp->primary_bank_ammo[turret_pbank] -= points;
} else if ((swp->primary_bank_ammo[turret_pbank] >= 0) && !(The_mission.ai_profile->flags[AI::Profile_Flags::Prevent_negative_turret_ammo])) {
if (swp->primary_bank_ammo[bank_to_fire] >= points) {
swp->primary_bank_ammo[bank_to_fire] -= points;
} else if ((swp->primary_bank_ammo[bank_to_fire] >= 0) && !(The_mission.ai_profile->flags[AI::Profile_Flags::Prevent_negative_turret_ammo])) {
// default behavior allowed ammo to be negative
swp->primary_bank_ammo[turret_pbank] -= points;
swp->primary_bank_ammo[bank_to_fire] -= points;
} else if (!(turret->system_info->flags[Model::Subsystem_Flags::Use_multiple_guns]) && (swp->primary_bank_ammo[bank_to_fire] < 0)) {
swp->current_primary_bank++;
if (swp->current_primary_bank >= swp->num_primary_banks) {
swp->current_primary_bank = 0;
}
return false;
} else {
return false;
}
}
else if (turret_sbank >= 0) {
if (!no_ammo_needed) {
if (swp->secondary_bank_ammo[turret_sbank] > 0) {
swp->secondary_bank_ammo[turret_sbank]--;
} else if ((swp->secondary_bank_ammo[turret_sbank] == 0) && !(The_mission.ai_profile->flags[AI::Profile_Flags::Prevent_negative_turret_ammo])) {
else if (wip->subtype == WP_MISSILE) {
if (swp->num_secondary_banks <= 0) {
return false;
}
if (swp->current_secondary_bank < 0){
swp->current_secondary_bank = 0;
return false;
}
bank_to_fire = swp->current_secondary_bank;
int start_slot, end_slot;
start_slot = swp->secondary_next_slot[bank_to_fire];
end_slot = start_slot;
for (int j = start_slot; j <= end_slot; j++) {
swp->secondary_next_slot[bank_to_fire]++;
if (Weapon_info[swp->secondary_bank_weapons[bank_to_fire]].wi_flags[Weapon::Info_Flags::SecondaryNoAmmo])
continue;
if (swp->secondary_next_slot[bank_to_fire] > (num_slots - 1)){
swp->secondary_next_slot[bank_to_fire] = 0;
}
if (swp->secondary_bank_ammo[bank_to_fire] > 0) {
swp->secondary_bank_ammo[bank_to_fire]--;
} else if ((swp->secondary_bank_ammo[bank_to_fire] == 0) && !(The_mission.ai_profile->flags[AI::Profile_Flags::Prevent_negative_turret_ammo])) {
// default behavior allowed ammo to be negative
swp->secondary_bank_ammo[turret_sbank]--;
swp->secondary_bank_ammo[bank_to_fire]--;
} else if (!(turret->system_info->flags[Model::Subsystem_Flags::Use_multiple_guns]) && (swp->secondary_bank_ammo[bank_to_fire] < 0)) {
swp->current_secondary_bank++;
if (swp->current_secondary_bank >= swp->num_secondary_banks) {
swp->current_secondary_bank = 0;
}
return false;
} else {
return false;
}
@@ -1951,7 +1991,7 @@ bool turret_fire_weapon(int weapon_num,
// so we need to get the position info separately for each shot
ship_get_global_turret_gun_info(&Objects[parent_objnum], turret, &firing_pos_buf, false, nullptr, true, nullptr);
weapon_objnum = weapon_create(firing_pos, &firing_orient, turret_weapon_class, parent_objnum, -1, true, false, swp, turret_pbank, turret_sbank, launch_curve_data);
weapon_objnum = weapon_create(firing_pos, &firing_orient, turret_weapon_class, parent_objnum, -1, true, false, 0.0f, turret, launch_curve_data);
weapon_set_tracking_info(weapon_objnum, parent_objnum, turret->turret_enemy_objnum, 1, turret->targeted_subsys);
//nprintf(("AI", "Turret_time_enemy_in_range = %7.3f\n", ss->turret_time_enemy_in_range));
@@ -2002,7 +2042,7 @@ bool turret_fire_weapon(int weapon_num,
}
//spawn particle effect
auto particleSource = particle::ParticleManager::get()->createSource(wip->muzzle_effect);
particleSource->setHost(std::make_unique<EffectHostTurret>(&Objects[parent_ship->objnum], turret->system_info->turret_gun_sobj, turret->turret_next_fire_pos, false));
particleSource->setHost(make_unique<EffectHostTurret>(&Objects[parent_ship->objnum], turret->system_info->turret_gun_sobj, turret->turret_next_fire_pos));
particleSource->setTriggerRadius(objp->radius * radius_mult);
particleSource->setTriggerVelocity(vm_vec_mag_quick(&objp->phys_info.vel));
particleSource->finishCreation();
@@ -2015,9 +2055,9 @@ bool turret_fire_weapon(int weapon_num,
subsys_index = ship_get_subsys_index(turret);
Assert( subsys_index != -1 );
if(wip->wi_flags[Weapon::Info_Flags::Flak]){
send_flak_fired_packet( parent_objnum, subsys_index, weapon_objnum, flak_range, launch_curve_data.distance_to_target, launch_curve_data.target_radius, launch_curve_data.target_forward_speed );
send_flak_fired_packet( parent_objnum, subsys_index, weapon_objnum, flak_range, launch_curve_data.distance_to_target, launch_curve_data.target_radius );
} else {
send_turret_fired_packet( parent_objnum, subsys_index, weapon_objnum, launch_curve_data.distance_to_target, launch_curve_data.target_radius, launch_curve_data.target_forward_speed );
send_turret_fired_packet( parent_objnum, subsys_index, weapon_objnum, launch_curve_data.distance_to_target, launch_curve_data.target_radius );
}
}
@@ -2091,11 +2131,10 @@ void turret_swarm_fire_from_turret(turret_swarm_info *tsi)
tsi->turret->system_info->turret_num_firing_points,
0.f,
0.f,
0.f,
};
// create weapon and homing info
weapon_objnum = weapon_create(&turret_pos, &firing_orient, tsi->weapon_class, tsi->parent_objnum, -1, true, false, &tsi->turret->weapons, tsi->swp_pbank, tsi->swp_sbank, launch_curve_data);
weapon_objnum = weapon_create(&turret_pos, &firing_orient, tsi->weapon_class, tsi->parent_objnum, -1, true, false, 0.0f, tsi->turret, launch_curve_data);
weapon_set_tracking_info(weapon_objnum, tsi->parent_objnum, tsi->target_objnum, 1, tsi->target_subsys);
// do other cool stuff if weapon is created.
@@ -2124,7 +2163,7 @@ void turret_swarm_fire_from_turret(turret_swarm_info *tsi)
if (Weapon_info[tsi->weapon_class].muzzle_effect.isValid()) {
//spawn particle effect
auto particleSource = particle::ParticleManager::get()->createSource(Weapon_info[tsi->weapon_class].muzzle_effect);
particleSource->setHost(std::make_unique<EffectHostTurret>(&Objects[tsi->parent_objnum], tsi->turret->system_info->turret_gun_sobj, tsi->turret->turret_next_fire_pos - 1, false));
particleSource->setHost(make_unique<EffectHostTurret>(&Objects[tsi->parent_objnum], tsi->turret->system_info->turret_gun_sobj, tsi->turret->turret_next_fire_pos - 1));
particleSource->setTriggerRadius(Objects[weapon_objnum].radius);
particleSource->finishCreation();
}
@@ -2143,7 +2182,7 @@ void turret_swarm_fire_from_turret(turret_swarm_info *tsi)
subsys_index = ship_get_subsys_index(tsi->turret);
Assert( subsys_index != -1 );
send_turret_fired_packet( tsi->parent_objnum, subsys_index, weapon_objnum, 0.f, 0.f, 0.f);
send_turret_fired_packet( tsi->parent_objnum, subsys_index, weapon_objnum, 0.f, 0.f);
}
}
}
@@ -2316,11 +2355,9 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
float turret_barrel_length = -1.0f;
float target_radius = 0.f;
float target_forward_speed = 0.f;
if (lep != nullptr) {
target_radius = lep->radius;
target_forward_speed = lep->phys_info.fspeed;
}
// grab the data for the launch curve inputs
@@ -2328,7 +2365,6 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
ss->system_info->turret_num_firing_points,
base_dist_to_enemy,
target_radius,
target_forward_speed,
};
//WMC - go through all valid weapons. Fire spawns if there are any.
+10 -18
View File
@@ -142,15 +142,11 @@ int unpack_pixel(anim_instance *ai, ubyte *data, ubyte pix, int aabitmap, int bp
bit_16 = (ushort)pix;
break;
case 8:
// 8-bit-per-pixel HUD gauge ANI aabitmaps use the palette index directly as an alpha value —
// the actual RGB colors stored in the palette are completely ignored. The valid range is [0, 15]:
// [0]: fully transparent (alpha 0)
// [1-14]: black-to-white gradient (alpha = index * 18)
// [15]: special HUD background (alpha 18, matching index 1, for a dark transparent tint)
// [>15]: clamped to fully opaque (alpha 255)
// Because only the index value matters, the palette in the source file must be ordered so that
// index 0 is the transparent end and index 14 is the opaque end. A reversed palette causes the
// gauge to render as a solid white square (see GitHub issue #4148).
// 8 bit-per-pixel aa bitmaps are a bit special since they only use a palette index value in the range [0, 15]. These
// palette indexes must be remapped to alpha values between [0, 255] which is what graphics code expects. Palette
// range [0, 14] is a gradient from black to white, and palette index 15 is a special color which indicates the background
// area of a HUD gauge. Retail code uses the final alpha value for index 1 for this special index to give gauges a dark
// transparent background.
if (pix > 15) {
bit_8 = 255;
}
@@ -244,15 +240,11 @@ int unpack_pixel_count(anim_instance *ai, ubyte *data, ubyte pix, int count = 0,
bit_16 = (ushort)pix;
break;
case 8 :
// 8-bit-per-pixel HUD gauge ANI aabitmaps use the palette index directly as an alpha value —
// the actual RGB colors stored in the palette are completely ignored. The valid range is [0, 15]:
// [0]: fully transparent (alpha 0)
// [1-14]: black-to-white gradient (alpha = index * 18)
// [15]: special HUD background (alpha 18, matching index 1, for a dark transparent tint)
// [>15]: clamped to fully opaque (alpha 255)
// Because only the index value matters, the palette in the source file must be ordered so that
// index 0 is the transparent end and index 14 is the opaque end. A reversed palette causes the
// gauge to render as a solid white square (see GitHub issue #4148).
// 8 bit-per-pixel aa bitmaps are a bit special since they only use a palette index value in the range [0, 15]. These
// palette indexes must be remapped to alpha values between [0, 255] which is what graphics code expects. Palette
// range [0, 14] is a gradient from black to white, and palette index 15 is a special color which indicates the background
// area of a HUD gauge. Retail code uses the final alpha value for index 1 for this special index to give gauges a dark
// transparent background.
if (pix > 15) {
bit_8 = 255;
}
+20 -41
View File
@@ -648,30 +648,24 @@ void asteroid_create_all()
int max_asteroids = Asteroid_field.num_initial_asteroids; // * (1.0f - 0.1f*(MAX_DETAIL_VALUE-Detail.asteroid_density)));
int num_debris_types = 0;
int num_valid = 0; // count of valid (non-(-1)) entries written into shipDebrisOddsTable
// get number of debris types
if (Asteroid_field.debris_genre == DG_DEBRIS) {
num_debris_types = static_cast<int>(Asteroid_field.field_debris_type.size());
// Calculate the odds table; skip invalid entries (field_debris_type[idx] == -1 means
// missionparse invalidated the entry because the type no longer exists in Asteroid_info)
// Calculate the odds table
for (idx=0; idx<num_debris_types; idx++) {
if (Asteroid_field.field_debris_type[idx] == -1)
continue;
float debris_weight = Asteroid_info[Asteroid_field.field_debris_type[idx]].spawn_weight;
shipDebrisOddsTable[num_valid].random_threshold = max_weighted_range + debris_weight;
shipDebrisOddsTable[num_valid].debris_type = Asteroid_field.field_debris_type[idx];
shipDebrisOddsTable[idx].random_threshold = max_weighted_range + debris_weight;
shipDebrisOddsTable[idx].debris_type = Asteroid_field.field_debris_type[idx];
max_weighted_range += debris_weight;
num_valid++;
}
}
// Load Asteroid/debris models
if (Asteroid_field.debris_genre == DG_DEBRIS) {
for (idx=0; idx<num_debris_types; idx++) {
if (Asteroid_field.field_debris_type[idx] != -1)
asteroid_load(Asteroid_field.field_debris_type[idx], 0);
asteroid_load(Asteroid_field.field_debris_type[idx], 0);
}
} else {
for (const auto& subtype : Asteroid_field.field_asteroid_type) {
@@ -696,7 +690,7 @@ void asteroid_create_all()
float rand_choice = frand() * max_weighted_range;
for (idx = 0; idx < num_valid; idx++) {
for (idx = 0; idx < static_cast<int>(Asteroid_field.field_debris_type.size()); idx++) {
// for ship debris, choose type according to odds table
if (rand_choice < shipDebrisOddsTable[idx].random_threshold) {
asteroid_create(&Asteroid_field, shipDebrisOddsTable[idx].debris_type, 0);
@@ -1083,10 +1077,8 @@ void asteroid_delete( object * obj )
asp = &Asteroids[num];
if (asp->model_instance_num >= 0) {
if (asp->model_instance_num >= 0)
model_delete_instance(asp->model_instance_num);
asp->model_instance_num = -1;
}
if (asp->target_objnum >= 0) {
for (asteroid_target& target : Asteroid_targets) {
@@ -1323,9 +1315,9 @@ int asteroid_check_collision(object *pasteroid, object *other_obj, vec3d *hitpos
model_get_moving_submodel_list(submodel_vector, heavy_obj);
// turn off all moving submodels, collide against only 1 at a time.
mc.collision_checked.assign(pm->n_models, 0);
// turn off collision detection for all moving submodels
for (auto submodel: submodel_vector) {
mc.collision_checked[submodel] = true;
pmi->submodel[submodel].collision_checked = true;
}
// Only check single submodel now, since children of moving submodels are handled as moving as well
@@ -1333,8 +1325,10 @@ int asteroid_check_collision(object *pasteroid, object *other_obj, vec3d *hitpos
// check each submodel in turn
for (auto submodel: submodel_vector) {
auto smi = &pmi->submodel[submodel];
// turn on just one submodel for collision test
mc.collision_checked[submodel] = false;
smi->collision_checked = false;
// find the start and end positions of the sphere in submodel RF
model_instance_global_to_local_point(&p0, &light_obj->last_pos, pm, pmi, submodel, &heavy_obj->last_orient, &heavy_obj->last_pos, true);
@@ -1366,12 +1360,9 @@ int asteroid_check_collision(object *pasteroid, object *other_obj, vec3d *hitpos
}
}
// Don't look at this submodel again
mc.collision_checked[submodel] = true;
smi->collision_checked = true;
}
// Clear collision_checked before base model pass so it auto-inits fresh
mc.collision_checked.clear();
}
// Now complete base model collision checks that do not take into account rotating submodels.
@@ -1439,9 +1430,9 @@ int asteroid_check_collision(object *pasteroid, object *other_obj, vec3d *hitpos
// everything above was calculated relative to the heavy's position
vec3d actual_world_hit_pos = mc.hit_point_world + heavy_obj->pos;
if ((shipp->is_arriving()) && (shipp->warpin_effect != nullptr))
warp_effect = shipp->warpin_effect.get();
warp_effect = shipp->warpin_effect;
else if ((shipp->flags[Ship::Ship_Flags::Depart_warp]) && (shipp->warpout_effect != nullptr))
warp_effect = shipp->warpout_effect.get();
warp_effect = shipp->warpout_effect;
if (warp_effect != nullptr && point_is_clipped_by_warp(&actual_world_hit_pos, warp_effect))
mc_ret_val = 0;
@@ -1616,13 +1607,8 @@ static float asteroid_create_explosion(object *objp)
}
fireball_scale_multiplier = asteroid_get_fireball_scale_multiplier(objp->instance);
auto fireball_radius = objp->radius * fireball_scale_multiplier;
if (Zero_radius_explosions_skip_fireballs && fl_near_zero(fireball_radius))
fireball_objnum = -1;
else
fireball_objnum = fireball_create( &objp->pos, fireball_type, FIREBALL_LARGE_EXPLOSION, OBJ_INDEX(objp), fireball_radius, false, &objp->phys_info.vel );
fireball_objnum = fireball_create( &objp->pos, fireball_type, FIREBALL_LARGE_EXPLOSION, OBJ_INDEX(objp), objp->radius*fireball_scale_multiplier, false, &objp->phys_info.vel );
if ( fireball_objnum > -1 ) {
explosion_life = fireball_lifeleft(&Objects[fireball_objnum]);
} else {
@@ -1693,7 +1679,7 @@ static void asteroid_do_area_effect(object *asteroid_objp)
if ( weapon_area_calc_damage(ship_objp, &asteroid_objp->pos, asip->inner_rad, asip->outer_rad, asip->blast, asip->damage, &blast, &damage, asip->outer_rad) == -1 )
continue;
ship_apply_global_damage(ship_objp, asteroid_objp, &asteroid_objp->pos, damage, asip->damage_type_idx, DamageSource::Explosion);
ship_apply_global_damage(ship_objp, asteroid_objp, &asteroid_objp->pos, damage, asip->damage_type_idx);
weapon_area_apply_blast(nullptr, ship_objp, &asteroid_objp->pos, blast, false);
} // end for
}
@@ -2234,7 +2220,7 @@ static void asteroid_parse_section()
}
return;
}
asteroid_list.push_back(std::move(asteroid_t));
asteroid_list.push_back(asteroid_t);
asteroid_p = &asteroid_list[asteroid_list.size() - 1];
}
@@ -2332,7 +2318,7 @@ static void asteroid_parse_section()
thisType.type_name.c_str(),
asteroid_p->name);
} else {
asteroid_p->subtypes.push_back(std::move(thisType));
asteroid_p->subtypes.push_back(thisType);
}
}
}
@@ -2621,7 +2607,7 @@ static void verify_asteroid_splits()
}
// Replace splits with only valid splits
Asteroid_info[i].split_info = std::move(splits_t);
Asteroid_info[i].split_info = splits_t;
}
}
@@ -2649,11 +2635,6 @@ static void verify_asteroid_list()
if (found)
continue;
if (asteroid_list.empty()) {
mprintf(("%s asteroid not found and no fallback available in asteroid_list.\n", asteroid_size[i].c_str()));
continue;
}
//Left this as a log print instead of a Warning because of retail-Mjn
mprintf(("%s asteroid not found. Using asteroid %s\n", asteroid_size[i].c_str(), asteroid_list[0].name));
asteroid_list[0].type = i;
@@ -2708,10 +2689,8 @@ void asteroid_init()
parse_modular_table("*-ast.tbm", asteroid_parse_tbl);
//No asteroids defined. Bail!
if (asteroid_list.empty()) {
mprintf(("No asteroids defined in asteroid.tbl or any modular tables. Asteroid fields will not function.\n"));
if (asteroid_list.empty())
return;
}
// now verify the asteroids were found and put them in the correct order
verify_asteroid_list();
+9 -10
View File
@@ -70,7 +70,7 @@ struct bitmap_entry {
// Stuff to keep track of usage
ubyte preloaded; //!< If set, then this was loaded from the lst file
int preload_count; //!< how many times this gets used in game, for unlocking
uint used_flags; //!< What flags it was accessed thru
ushort used_flags; //!< What flags it was accessed thru
int load_count;
bitmap bm; //!< Bitmap info
@@ -93,15 +93,14 @@ struct bitmap_slot {
};
// image specific lock functions
void bm_lock_ani( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, uint flags );
void bm_lock_dds( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, uint flags );
void bm_lock_png( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, uint flags );
void bm_lock_apng( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, uint flags );
void bm_lock_jpg( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, uint flags );
void bm_lock_pcx( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, uint flags );
void bm_lock_tga( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, uint flags );
void bm_lock_user( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, uint flags, bool convert = true );
void bm_lock_ktx1(int handle, bitmap_slot* bs, bitmap* bmp, int bpp, uint flags);
void bm_lock_ani( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags );
void bm_lock_dds( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags );
void bm_lock_png( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags );
void bm_lock_apng( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags );
void bm_lock_jpg( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags );
void bm_lock_pcx( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags );
void bm_lock_tga( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags );
void bm_lock_user( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags, bool convert = true );
const size_t BM_BLOCK_SIZE = 4096;
+57 -170
View File
@@ -13,7 +13,6 @@
#define WIN32_LEAN_AND_MEAN
#define BMPMAN_INTERNAL
#include "globalincs/pstypes.h"
#include "anim/animplay.h"
#include "anim/packunpack.h"
#include "bmpman/bm_internal.h"
@@ -33,7 +32,6 @@
#include "tgautils/tgautils.h"
#include "tracing/Monitor.h"
#include "tracing/tracing.h"
#include "ktxutils/ktxutils.h"
#include <cctype>
#include <climits>
@@ -61,8 +59,8 @@ size_t bm_texture_ram = 0;
int Bm_paging = 0;
// Extension type lists
const BM_TYPE bm_type_list[] = { BM_TYPE_DDS, BM_TYPE_TGA, BM_TYPE_PNG, BM_TYPE_JPG, BM_TYPE_PCX, BM_TYPE_KTX };
const char* bm_ext_list[] = { ".dds", ".tga", ".png", ".jpg", ".pcx", ".ktx" };
const BM_TYPE bm_type_list[] = { BM_TYPE_DDS, BM_TYPE_TGA, BM_TYPE_PNG, BM_TYPE_JPG, BM_TYPE_PCX };
const char *bm_ext_list[] = { ".dds", ".tga", ".png", ".jpg", ".pcx" };
const int BM_NUM_TYPES = sizeof(bm_type_list) / sizeof(bm_type_list[0]);
const BM_TYPE bm_ani_type_list[] = { BM_TYPE_EFF, BM_TYPE_ANI, BM_TYPE_PNG };
@@ -84,12 +82,7 @@ static bool bm_inited = false;
static uint Bm_next_signature = 0x1234;
static int Bm_low_mem = 0;
struct bm_lookup_cache_entry {
ubyte* data;
int width;
int height;
};
SCP_map<int, bm_lookup_cache_entry> bm_lookup_cache;
SCP_map<int,ubyte*> bm_lookup_cache;
/**
* How much RAM bmpman can use for textures.
@@ -150,31 +143,30 @@ bitmap_slot* bm_get_slot(int handle, bool separate_ani_frames) {
// Declaration of private functions and templates(declared as static type func(type param);)
bitmap_lookup::bitmap_lookup(int bitmap_num):
Bitmap_data(nullptr),
Width(0),
Height(0),
Num_channels(3)
Bitmap_data(NULL)
{
if ( !bm_is_valid(bitmap_num) ) return;
Num_channels = 3;
if ( bm_has_alpha_channel(bitmap_num) ) {
Num_channels = 4;
}
bitmap_entry *be = bm_get_entry(bitmap_num);
Width = be->bm.w;
Height = be->bm.h;
auto cache_search = bm_lookup_cache.find(bitmap_num);
if (cache_search == bm_lookup_cache.end()) {
// The texture in graphics memory may be smaller than the bitmap itself, e.g. when mipmap levels
// are culled at lower texture detail settings, so the readback reports the dimensions of the
// data it actually returns.
Bitmap_data = gr_get_bitmap_from_texture(bitmap_num, &Width, &Height);
Bitmap_data = (ubyte*)vm_malloc(Width * Height * Num_channels * sizeof(ubyte));
if (Bitmap_data != nullptr) {
bm_lookup_cache.insert({bitmap_num, {Bitmap_data, Width, Height}});
}
gr_get_bitmap_from_texture((void*)Bitmap_data, bitmap_num);
bm_lookup_cache.insert({bitmap_num, Bitmap_data});
} else {
Bitmap_data = cache_search->second.data;
Width = cache_search->second.width;
Height = cache_search->second.height;
Bitmap_data = cache_search->second;
}
}
@@ -197,11 +189,6 @@ float bitmap_lookup::get_channel_alpha(float u, float v)
{
Assert( Bitmap_data != NULL );
// without an alpha channel there is nothing to look up, and indexing channel 3 would read out of bounds
if ( Num_channels < 4 ) {
return 1.0f;
}
int x = fl2i(map_texture_address(u) * (Width-1));
int y = fl2i(map_texture_address(v) * (Height-1));
@@ -210,7 +197,7 @@ float bitmap_lookup::get_channel_alpha(float u, float v)
void clear_bm_lookup_cache() {
for(auto &iter: bm_lookup_cache) {
vm_free(iter.second.data);
free(iter.second);
}
bm_lookup_cache.clear();
}
@@ -218,7 +205,7 @@ void clear_bm_lookup_cache() {
/**
* Converts the bitmap referenced by bmp to the type specified by flags
*/
static void bm_convert_format(bitmap *bmp, uint flags);
static void bm_convert_format(bitmap *bmp, ushort flags);
/**
* Frees a bitmap's data if it can
@@ -611,8 +598,8 @@ int bm_create_3d(int bpp, int w, int h, int d, void* data) {
return -1;
// make sure that we have valid data
Assertion(data != nullptr, "No valid data received for 3D Bitmap creation!");
if (data == nullptr) {
UNREACHABLE("No valid data received for 3D Bitmap creation!");
return -1;
}
@@ -652,7 +639,7 @@ int bm_create_3d(int bpp, int w, int h, int d, void* data) {
return n;
}
void bm_convert_format(bitmap *bmp, uint flags) {
void bm_convert_format(bitmap *bmp, ushort flags) {
int idx;
// no transparency for 24 bpp images
@@ -914,7 +901,7 @@ void bm_get_frame_usage(int *ntotal, int *nnew) {
#endif
}
int bm_get_info(int handle, int *w, int * h, uint* flags, int *nframes, int *fps) {
int bm_get_info(int handle, int *w, int * h, ushort* flags, int *nframes, int *fps) {
bitmap * bmp;
if (!bm_inited) return -1;
@@ -1036,13 +1023,6 @@ void bm_init() {
bm_inited = true;
}
bool bm_is_cubemap(int handle)
{
const BM_TYPE type = bm_get_entry(handle)->comp_type;
return type == BM_TYPE_CUBEMAP_DDS || type == BM_TYPE_CUBEMAP_DXT1 || type == BM_TYPE_CUBEMAP_DXT3 ||
type == BM_TYPE_CUBEMAP_DXT5;
}
int bm_is_compressed(int num) {
auto entry = bm_get_entry(num);
BM_TYPE type = BM_TYPE_NONE;
@@ -1075,24 +1055,6 @@ int bm_is_compressed(int num) {
case BM_TYPE_CUBEMAP_DXT5:
return DDS_CUBEMAP_DXT5;
case BM_TYPE_ETC2_RGB:
return KTX_ETC2_RGB;
case BM_TYPE_ETC2_SRGB:
return KTX_ETC2_SRGB;
case BM_TYPE_ETC2_RGBA_EAC:
return KTX_ETC2_RGBA_EAC;
case BM_TYPE_ETC2_SRGBA_EAC:
return KTX_ETC2_SRGBA_EAC;
case BM_TYPE_ETC2_RGBA1:
return KTX_ETC2_RGB_A1;
case BM_TYPE_ETC2_SRGBA1:
return KTX_ETC2_SRGB_A1;
default:
return 0;
}
@@ -1186,16 +1148,6 @@ static int bm_load_info(BM_TYPE type, const char *filename, CFILE *img_cfp, int
return -1;
}
}
// its a KTX file
else if (type == BM_TYPE_KTX) {
int ktx_ct;
int ktx_error = ktx1_read_header(filename, img_cfp, w, h, bpp, &ktx_ct, mm_lvl, size);
if (ktx_error != KTX1_ERROR_NONE) {
mprintf(("ktx: could not open '%s'\n", filename));
return -1;
}
*c_type = (BM_TYPE)ktx_ct;
}
// if its a tga file
else if (type == BM_TYPE_TGA) {
int tga_error = targa_read_header(filename, img_cfp, w, h, bpp, NULL);
@@ -1229,7 +1181,7 @@ static int bm_load_info(BM_TYPE type, const char *filename, CFILE *img_cfp, int
}
}
else {
UNREACHABLE("Unknown file type %d specified! This is probably a coding error.", type);
UNREACHABLE("Unknown file type specified! This is probably a coding error.");
return -1;
}
@@ -1409,8 +1361,6 @@ bool bm_load_and_parse_eff(const char *filename, int dir_type, int *nframes, int
c_type = BM_TYPE_JPG;
} else if (!stricmp(NOX("pcx"), ext)) {
c_type = BM_TYPE_PCX;
} else if (!stricmp(NOX("ktx"), ext)) {
c_type = BM_TYPE_KTX;
} else {
mprintf(("BMPMAN: Unknown file type in EFF parse!\n"));
return false;
@@ -1440,7 +1390,7 @@ bool bm_load_and_parse_eff(const char *filename, int dir_type, int *nframes, int
/**
* Lock an image files data into memory
*/
static int bm_load_image_data(int handle, int bpp, uint flags, bool nodebug)
static int bm_load_image_data(int handle, int bpp, ushort flags, bool nodebug)
{
BM_TYPE c_type = BM_TYPE_NONE;
int true_bpp;
@@ -1532,10 +1482,6 @@ static int bm_load_image_data(int handle, int bpp, uint flags, bool nodebug)
bm_lock_user(handle, bs, bmp, true_bpp, flags, false);
break;
case BM_TYPE_KTX:
bm_lock_ktx1(handle, bs, bmp, true_bpp, flags);
break;
default:
Warning(LOCATION, "Unsupported type in bm_lock -- %d\n", c_type);
return -1;
@@ -1995,7 +1941,7 @@ int bm_load_sub_slow(const char *real_filename, const int num_ext, const char **
return -1;
}
bitmap * bm_lock(int handle, int bpp, uint flags, bool nodebug) {
bitmap * bm_lock(int handle, int bpp, ushort flags, bool nodebug) {
bitmap *bmp;
Assertion(bm_inited, "bmpman must be initialized before this function can be called!");
@@ -2092,7 +2038,7 @@ bitmap * bm_lock(int handle, int bpp, uint flags, bool nodebug) {
return bmp;
}
void bm_lock_ani(int /*handle*/, bitmap_slot *bs, bitmap* /*bmp*/, int bpp, uint flags) {
void bm_lock_ani(int /*handle*/, bitmap_slot *bs, bitmap* /*bmp*/, int bpp, ushort flags) {
anim *the_anim;
anim_instance *the_anim_instance;
bitmap *bm;
@@ -2218,7 +2164,7 @@ void bm_lock_ani(int /*handle*/, bitmap_slot *bs, bitmap* /*bmp*/, int bpp, uint
}
void bm_lock_apng(int /*handle*/, bitmap_slot *bs, bitmap *bmp, int bpp, uint /*flags*/) {
void bm_lock_apng(int /*handle*/, bitmap_slot *bs, bitmap *bmp, int bpp, ushort /*flags*/) {
auto be = &bs->entry;
int first_frame = be->info.ani.first_frame;
auto first_entry = bm_get_entry(first_frame);
@@ -2268,7 +2214,7 @@ void bm_lock_apng(int /*handle*/, bitmap_slot *bs, bitmap *bmp, int bpp, uint /*
}
void bm_lock_dds(int handle, bitmap_slot *bs, bitmap *bmp, int /*bpp*/, uint /*flags*/) {
void bm_lock_dds(int handle, bitmap_slot *bs, bitmap *bmp, int /*bpp*/, ushort /*flags*/) {
ubyte *data = NULL;
int error;
ubyte dds_bpp = 0;
@@ -2332,7 +2278,7 @@ void bm_lock_dds(int handle, bitmap_slot *bs, bitmap *bmp, int /*bpp*/, uint /*f
#endif
}
void bm_lock_jpg(int handle, bitmap_slot *bs, bitmap *bmp, int bpp, uint /*flags*/) {
void bm_lock_jpg(int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort /*flags*/) {
ubyte *data = NULL;
int d_size = 0;
int jpg_error = JPEG_ERROR_INVALID;
@@ -2379,7 +2325,7 @@ void bm_lock_jpg(int handle, bitmap_slot *bs, bitmap *bmp, int bpp, uint /*flags
#endif
}
void bm_lock_pcx(int handle, bitmap_slot *bs, bitmap *bmp, int bpp, uint flags) {
void bm_lock_pcx(int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags) {
ubyte *data;
int pcx_error;
char filename[MAX_FILENAME_LEN];
@@ -2424,7 +2370,7 @@ void bm_lock_pcx(int handle, bitmap_slot *bs, bitmap *bmp, int bpp, uint flags)
bm_convert_format(bmp, flags);
}
void bm_lock_png(int handle, bitmap_slot *bs, bitmap *bmp, int /*bpp*/, uint /*flags*/) {
void bm_lock_png(int handle, bitmap_slot *bs, bitmap *bmp, int /*bpp*/, ushort /*flags*/) {
ubyte *data = NULL;
//assume 32 bit - libpng should expand everything
int d_size;
@@ -2469,7 +2415,7 @@ void bm_lock_png(int handle, bitmap_slot *bs, bitmap *bmp, int /*bpp*/, uint /*f
#endif
}
void bm_lock_tga(int handle, bitmap_slot *bs, bitmap *bmp, int bpp, uint flags) {
void bm_lock_tga(int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags) {
ubyte *data = NULL;
int byte_size;
char filename[MAX_FILENAME_LEN];
@@ -2528,7 +2474,7 @@ void bm_lock_tga(int handle, bitmap_slot *bs, bitmap *bmp, int bpp, uint flags)
bm_convert_format(bmp, flags);
}
void bm_lock_user(int /*handle*/, bitmap_slot *bs, bitmap *bmp, int bpp, uint flags, bool convert) {
void bm_lock_user(int /*handle*/, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags, bool convert) {
auto be = &bs->entry;
// Unload any existing data
@@ -2821,21 +2767,6 @@ void bm_page_in_texture(int bitmapnum, int nframes) {
frame_entry->used_flags = BMP_TEX_CUBEMAP;
continue;
case BM_TYPE_ETC2_RGB:
case BM_TYPE_ETC2_SRGB:
frame_entry->used_flags = BMP_TEX_ETC2_RGB8;
continue;
case BM_TYPE_ETC2_RGBA1:
case BM_TYPE_ETC2_SRGBA1:
frame_entry->used_flags = BMP_TEX_ETC2_RGBA1;
continue;
case BM_TYPE_ETC2_RGBA_EAC:
case BM_TYPE_ETC2_SRGBA_EAC:
frame_entry->used_flags = BMP_TEX_ETC2_RGBA8;
continue;
default:
continue;
}
@@ -2881,21 +2812,6 @@ void bm_page_in_xparent_texture(int bitmapnum, int nframes) {
entry->used_flags = BMP_TEX_CUBEMAP;
continue;
case BM_TYPE_ETC2_RGB:
case BM_TYPE_ETC2_SRGB:
entry->used_flags = BMP_TEX_ETC2_RGB8;
continue;
case BM_TYPE_ETC2_RGBA1:
case BM_TYPE_ETC2_SRGBA1:
entry->used_flags = BMP_TEX_ETC2_RGBA1;
continue;
case BM_TYPE_ETC2_RGBA_EAC:
case BM_TYPE_ETC2_SRGBA_EAC:
entry->used_flags = BMP_TEX_ETC2_RGBA8;
continue;
default:
continue;
}
@@ -3481,67 +3397,38 @@ bool bm_validate_filename(const SCP_string& file, bool single_frame, bool animat
}
return false;
}
SDL_Surface* bm_to_sdl_surface(int handle)
{
SDL_Surface* bm_to_sdl_surface(int handle) {
Assertion(bm_is_valid(handle), "%d is no valid bitmap handle!", handle);
int w;
int h;
bm_get_info(handle, &w, &h, nullptr, nullptr);
Uint32 rmask, gmask, bmask, amask;
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
rmask = 0x0000ff00;
gmask = 0x00ff0000;
bmask = 0xff000000;
amask = 0x000000ff;
#else
rmask = 0x00ff0000;
gmask = 0x0000ff00;
bmask = 0x000000ff;
amask = 0xff000000;
#endif
SDL_Surface* bitmapSurface = SDL_CreateRGBSurface(0, w, h, 32, rmask, gmask, bmask, amask);
if (SDL_LockSurface(bitmapSurface) < 0) {
return nullptr;
}
bitmap* bmp = bm_lock(handle, 32, BMP_TEX_XPARENT);
auto bitmapSurface = SDL_CreateSurface(bmp->w, bmp->h, SDL_PIXELFORMAT_BGRA32);
if (bitmapSurface) {
memcpy(bitmapSurface->pixels, reinterpret_cast<void *>(bmp->data),
bmp->w * bmp->h * (bmp->bpp >> 3));
}
memcpy(bitmapSurface->pixels, reinterpret_cast<void*>(bmp->data), static_cast<size_t>(w * h * 4));
bm_unlock(handle);
bm_unload(handle);
SDL_UnlockSurface(bitmapSurface);
return bitmapSurface;
}
// copied bm_lock_dds and adjusted for ktx. missing BIG_ENDIAN
void bm_lock_ktx1(int handle, bitmap_slot* bs, bitmap* bmp, int bpp, uint flags)
{
(void)bpp;
(void)flags;
ubyte* data = nullptr;
ubyte ktx_bpp = 0;
int ktx_error = KTX1_ERROR_NONE;
char filename[MAX_FILENAME_LEN];
auto be = &bs->entry;
bm_free_data(bs);
Assert(be->mem_taken > 0);
Assert(&be->bm == bmp);
data = (ubyte*)bm_malloc(handle, be->mem_taken);
if (!data)
return;
memset(data, 0, be->mem_taken);
// make sure we are using the correct filename in the case of an EFF.
// this will populate filename[] whether it's EFF or not
EFF_FILENAME_CHECK;
ktx_error = ktx1_read_bitmap(filename, data, &ktx_bpp);
if (ktx_error != KTX1_ERROR_NONE)
{
mprintf(("KTX: read_bitmap error=%d file='%s'\n", ktx_error, filename));
bm_free_data(bs);
return;
}
bmp->bpp = ktx_bpp;
bmp->data = (ptr_u)data;
bmp->flags = 0;
#ifdef BMPMAN_NDEBUG
Assert(be->data_size > 0);
#endif
}
+5 -28
View File
@@ -34,7 +34,6 @@
// Flag positions for bitmap.flags
// ***** NOTE: bitmap.flags is an 8-bit value, no more BMP_TEX_* flags can be added unless the type is changed!! ******
// Update: bitmap.flags type changed to 16-bit
#define BMP_AABITMAP (1<<0) //!< antialiased bitmap
#define BMP_TEX_XPARENT (1<<1) //!< transparent texture
#define BMP_TEX_OTHER (1<<2) //!< so we can identify all "normal" textures
@@ -44,14 +43,9 @@
#define BMP_TEX_BC7 (1<<6) //!< BC7 compressed 8r8g8b8a (32bit)
#define BMP_TEX_CUBEMAP (1<<7) //!< a texture made for cubic environment map
#define BMP_MASK_BITMAP (1<<8) //!< a bitmap that will be used for masking mouse interaction. Typically not used in render operations
#define BMP_TEX_ETC2_RGB8 (1 << 9) //!< ETC2 RGB compressed (24bit, no alpha)
#define BMP_TEX_ETC2_RGBA1 (1 << 10) //!< ETC2 RGBA1 compressed (24bit, 1 alpha)
#define BMP_TEX_ETC2_RGBA8 (1 << 11) //!< ETC2 RGBA8 compressed (32bit, 8 alpha)
// Combined flags
#define BMP_TEX_COMP ( BMP_TEX_DXT1 | BMP_TEX_DXT3 | BMP_TEX_DXT5 | BMP_TEX_BC7 | BMP_TEX_ETC2_RGB8 |\
BMP_TEX_ETC2_RGBA1 | BMP_TEX_ETC2_RGBA8 ) //!< Compressed textures
#define BMP_TEX_COMP ( BMP_TEX_DXT1 | BMP_TEX_DXT3 | BMP_TEX_DXT5 | BMP_TEX_BC7 ) //!< Compressed textures
#define BMP_TEX_NONCOMP ( BMP_TEX_XPARENT | BMP_TEX_OTHER ) //!< Non-compressed textures
#define BMP_TEX_ANY ( BMP_TEX_COMP | BMP_TEX_NONCOMP ) //!< Any texture
@@ -87,15 +81,7 @@ enum BM_TYPE
BM_TYPE_CUBEMAP_DXT3, //!< 32-bit cubemap (compressed cubemap surface)
BM_TYPE_CUBEMAP_DXT5, //!< 32-bit cubemap (compressed cubemap surface)
BM_TYPE_3D, //!< 3D in-memory
BM_TYPE_KTX, //!< generic identifier for KTX1
BM_TYPE_ETC2_RGB, //!< 24 bit, no alpha
BM_TYPE_ETC2_SRGB, //!< 24 bit, no alpha, signed
BM_TYPE_ETC2_RGBA1, //!< 24 bit, 1 bit alpha
BM_TYPE_ETC2_SRGBA1, //!< 24 bit, 1 bit alpha, signed
BM_TYPE_ETC2_RGBA_EAC, //!< 32 bit, 8 bit alpha
BM_TYPE_ETC2_SRGBA_EAC //!< 32 bit, 8 bit alpha, signed
BM_TYPE_3D //!< 3D in-memory
};
/**
@@ -110,7 +96,7 @@ struct bitmap
short rowsize; //!< What you need to add to go to next row
int bpp; //!< Requested bitdepth of each pixel. ( 7, 8, 15, 16, 24, 32)
int true_bpp; //!< The image's actual bitdepth
uint flags; //!< Various texture type flags. @see BMPMAN_CONSTANTS
ushort flags; //!< Various texture type flags. @see BMPMAN_CONSTANTS
ptr_u data; //!< Pointer to data, or maybe offset into VRAM.
ubyte *palette; /**< @brief Pointer to this bitmap's palette (if it has one).
* @details If BMP_NO_PALETTE_MAP flag is cleared, this palette just points to the screen palette. (gr_palette)
@@ -149,7 +135,6 @@ void bm_close();
#define BMP_FLAG_RENDER_TARGET_DYNAMIC (1<<1)
#define BMP_FLAG_CUBEMAP (1<<2)
#define BMP_FLAG_RENDER_TARGET_MIPMAP (1<<3)
#define BMP_FLAG_RENDER_TARGET_DEPTH_ATTACHMENT (1<<4)
/**
* @brief Allocates memory for the given handle.
@@ -359,7 +344,7 @@ int bm_load_either(const char *filename, int *nframes = NULL, int *fps = NULL, i
* @returns A pointer to the bitmap that's valid until bm_unlock is called if successful, or
* @returns NULL if unsuccessful
*/
bitmap* bm_lock(int handle, int bpp, uint flags, bool nodebug = false);
bitmap* bm_lock(int handle, int bpp, ushort flags, bool nodebug = false);
/**
* @brief Returns the image type of the given bitmap handle
@@ -402,7 +387,7 @@ int bm_is_valid(int handle);
* @returns The handle to the first frame on success, or
* @returns -1 on failure
*/
int bm_get_info(int handle, int *w = nullptr, int * h = nullptr, uint* flags = nullptr, int *nframes = nullptr, int *fps = nullptr);
int bm_get_info(int handle, int *w = nullptr, int * h = nullptr, ushort* flags = nullptr, int *nframes = nullptr, int *fps = nullptr);
/**
* @brief Gets 3D info on the bitmap indexed by handle.
@@ -594,14 +579,6 @@ void bm_get_components(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a);
*/
int bm_is_compressed(int handle);
/**
* @brief Returns true if the bitmap indexed by handle was loaded from a cubemap image file
*
* @note Render targets return false, even cubemap ones, and so do BC7 (DX10) DDS cubemaps, whose cube flag the DDS
* loader does not keep
*/
bool bm_is_cubemap(int handle);
/**
* @brief Gets the correct TCACHE_TYPE for compressed graphics (uncompressed are assumed TCACHE_TYPE_NORMAL)
*/
+24 -46
View File
@@ -56,10 +56,6 @@ APPLY_TO_FOV_T(-, sub)
// Used to set the default value for in-game options
static float fov_default = DEFAULT_FOV;
static float cockpit_fov_default = DEFAULT_FOV;
static bool cockpit_fov_toggle_default = false;
bool Use_cockpit_fov = false;
static SCP_string fov_display(float val)
{
@@ -77,22 +73,6 @@ static void parse_fov_func()
fov_default = value;
}
static void parse_cockpit_fov_func()
{
float value;
stuff_float(&value);
CLAMP(value, 0.436332f, 1.5708f);
cockpit_fov_default = value;
}
static void parse_cockpit_fov_toggle_func()
{
bool value;
stuff_boolean(&value);
cockpit_fov_toggle_default = value;
}
// coverity[GLOBAL_INIT_ORDER] -- safe; OptionBuilder::finish() uses Meyers singleton
auto FovOption = options::OptionBuilder<float>("Graphics.FOV",
std::pair<const char*, int>{"Field Of View", 1703},
std::pair<const char*, int>{"The vertical field of view", 1704})
@@ -109,42 +89,41 @@ auto FovOption = options::OptionBuilder<float>("Graphics.FOV",
.parser(parse_fov_func)
.finish();
// coverity[GLOBAL_INIT_ORDER] -- safe; OptionBuilder::finish() uses Meyers singleton
bool Use_cockpit_fov = false;
auto CockpitFOVToggleOption = options::OptionBuilder<bool>("Graphics.CockpitFOVToggle",
std::pair<const char*, int>{"Cockpit FOV Toggle", 1838},
std::pair<const char*, int>{"Whether or not to use a different FOV for cockpit rendering from normal rendering", 1839})
.category(std::make_pair("Graphics", 1825))
.default_val(false)
.change_listener([](bool val, bool) {
if (!val) {
COCKPIT_ZOOM_DEFAULT = VIEWER_ZOOM_DEFAULT;
}
return true; // This option will always persist so we never return false
})
.level(options::ExpertLevel::Advanced)
.bind_to(&Use_cockpit_fov)
.importance(61)
.finish();
auto CockpitFovOption = options::OptionBuilder<float>("Graphics.CockpitFOV",
std::pair<const char*, int>{"Cockpit Field Of View", 1840},
std::pair<const char*, int>{"The vertical field of view for cockpit rendering. Only works if cockpits are active and cockpit FOV toggle is turned on.", 1841})
.category(std::make_pair("Graphics", 1825))
.range(0.436332f, 1.5708f)
.change_listener([](const float& val, bool) {
// Graphics.CockpitFOVToggle has its own listener that re-applies this value, so the
// result is the same whichever of the two options the manager happens to load first.
COCKPIT_ZOOM_DEFAULT = Use_cockpit_fov ? fov_t(val) : VIEWER_ZOOM_DEFAULT;
if (Use_cockpit_fov){
COCKPIT_ZOOM_DEFAULT = val;
} else {
COCKPIT_ZOOM_DEFAULT = VIEWER_ZOOM_DEFAULT;
}
return true;
})
.display(fov_display)
.default_func([]() { return cockpit_fov_default; })
.default_val(fov_default)
.level(options::ExpertLevel::Advanced)
.importance(62)
.parser(parse_cockpit_fov_func)
.finish();
// coverity[GLOBAL_INIT_ORDER] -- safe; OptionBuilder::finish() uses Meyers singleton
auto CockpitFOVToggleOption = options::OptionBuilder<bool>("Graphics.CockpitFOVToggle",
std::pair<const char*, int>{"Cockpit FOV Toggle", 1838},
std::pair<const char*, int>{"Whether or not to use a different FOV for cockpit rendering from normal rendering", 1839})
.category(std::make_pair("Graphics", 1825))
.default_func([]() {return cockpit_fov_toggle_default;})
// This does the work of bind_to(&Use_cockpit_fov) and then re-applies Graphics.CockpitFOV,
// because that option's listener needs Use_cockpit_fov to already hold its final value.
// Doing it here makes the pair of options independent of the order the manager loads them in.
.change_listener([](bool val, bool) {
Use_cockpit_fov = val;
COCKPIT_ZOOM_DEFAULT = val ? fov_t(CockpitFovOption->getValue()) : VIEWER_ZOOM_DEFAULT;
return true; // This option will always persist so we never return false
})
.level(options::ExpertLevel::Advanced)
.importance(61)
.parser(parse_cockpit_fov_toggle_func)
.finish();
//*************************CLASS: camera*************************
@@ -753,7 +732,6 @@ subtitle::subtitle(int in_x_pos, int in_y_pos, const char* in_text, const char*
text_buf = in_text;
sexp_replace_variable_names_with_values(text_buf);
sexp_container_replace_refs_with_values(text_buf);
// (message_translate_tokens is called when the subtitle is queued, so does not need to be called here)
in_text = text_buf.c_str();
}
-609
View File
@@ -1,609 +0,0 @@
#include "freespace.h"
#include "actions/Action.h"
#include "camera/camera.h"
#include "camera/photomode.h"
#include "controlconfig/controlsconfig.h"
#include "debugconsole/console.h"
#include "globalincs/alphacolors.h"
#include "graphics/2d.h"
#include "graphics/font.h"
#include "hud/hud.h"
#include "io/keycontrol.h"
#include "localization/localize.h"
#include "mission/missionmessage.h"
#include "object/object.h"
#include "parse/parselo.h"
#include "playerman/player.h"
#include "render/3d.h"
#include "scripting/global_hooks.h"
#include "sound/audiostr.h"
bool Photo_mode_active = false;
camid Photo_mode_id;
fix Photo_mode_saved_time_compression = F1_0;
bool Photo_mode_saved_lock_state = false;
bool Photo_mode_screenshot_queued_this_frame = false;
bool Photo_mode_allowed = true;
bool Photo_mode_audio_paused = false;
const float Photo_mode_turn_rate = PI_2; // radians/sec
constexpr float Photo_mode_move_speed = 90.0f;
constexpr float Photo_mode_boost_multiplier = 6.0f;
constexpr float Photo_mode_time_compression = 0.01f;
struct photo_mode_post_effect_state {
SCP_string name;
float intensity = 0.0f;
vec3d rgb = vmd_zero_vector;
int effect_idx = -1; // index into Post_processing_manager->getPostEffects()
};
enum class photo_mode_param_type {
INT_RANGE, // adjustable integer value with min/max
BOOL_TOGGLE // on/off toggle
};
enum class photo_mode_param_role {
NONE,
GRID_OVERLAY, // bool toggle that enables the rule of thirds grid
POST_EFFECT // drives a post processing effect by name
};
struct photo_mode_param {
const char* label; // display name
int xstr_id; // XSTR localization ID
photo_mode_param_type type;
photo_mode_param_role role;
// For POST_EFFECT role: post processing effect name, range, and values
const char* effect_name; // post processing effect to control (nullptr if role != POST_EFFECT)
int effect_idx; // index into Post_processing_manager->getPostEffects() (-1 if unresolved)
int min_val;
int max_val;
int value;
int saved_value;
// For BOOL_TOGGLE
bool bool_value;
};
// Parameter definitions
SCP_vector<photo_mode_param> Photo_mode_params = {
{"Grid", 1906, photo_mode_param_type::BOOL_TOGGLE, photo_mode_param_role::GRID_OVERLAY, nullptr, -1, 0, 0, 0, 0, false},
{"Saturation", 1903, photo_mode_param_type::INT_RANGE, photo_mode_param_role::POST_EFFECT, "saturation", -1, 0, 200, 100, 100, false},
{"Brightness", 1904, photo_mode_param_type::INT_RANGE, photo_mode_param_role::POST_EFFECT, "brightness", -1, 0, 200, 100, 100, false},
{"Contrast", 1905, photo_mode_param_type::INT_RANGE, photo_mode_param_role::POST_EFFECT, "contrast", -1, 0, 200, 100, 100, false},
};
SCP_vector<photo_mode_post_effect_state> Photo_mode_saved_post_effects;
int Photo_mode_selected_parameter = 0;
int Photo_mode_panel_width = 0;
int Photo_mode_panel_padding_w = 0;
void photo_mode_capture_post_effect_state()
{
Photo_mode_saved_post_effects.clear();
if (graphics::Post_processing_manager == nullptr) {
return;
}
const auto& post_effects = graphics::Post_processing_manager->getPostEffects();
Photo_mode_saved_post_effects.reserve(post_effects.size());
for (int i = 0; i < static_cast<int>(post_effects.size()); ++i) {
const auto& effect = post_effects[i];
photo_mode_post_effect_state state;
state.name = effect.name;
state.intensity = effect.intensity;
state.rgb = effect.rgb;
state.effect_idx = i;
Photo_mode_saved_post_effects.push_back(state);
}
// Resolve effect indices for each param.
// Done once here rather than on every frame or every key press.
for (auto& param : Photo_mode_params) {
if (param.role != photo_mode_param_role::POST_EFFECT) {
param.effect_idx = -1;
continue;
}
param.effect_idx = -1;
for (int j = 0; j < static_cast<int>(post_effects.size()); ++j) {
if (!stricmp(post_effects[j].name.c_str(), param.effect_name)) {
param.effect_idx = j;
break;
}
}
}
}
void photo_mode_apply_saved_post_effect_state(bool clear_saved_state)
{
if (graphics::Post_processing_manager == nullptr) {
if (clear_saved_state) {
Photo_mode_saved_post_effects.clear();
}
return;
}
const auto& post_effects = graphics::Post_processing_manager->getPostEffects();
for (const auto& saved_state : Photo_mode_saved_post_effects) {
if (saved_state.effect_idx < 0 || saved_state.effect_idx >= static_cast<int>(post_effects.size())) {
continue;
}
const auto& effect = post_effects[saved_state.effect_idx];
const int value = static_cast<int>(std::lround((saved_state.intensity - effect.add) * effect.div));
gr_post_process_set_effect(saved_state.name.c_str(), value, &saved_state.rgb);
}
if (clear_saved_state) {
Photo_mode_saved_post_effects.clear();
}
}
int photo_mode_get_saved_post_effect_value(int effect_idx)
{
int value = 100;
if (effect_idx < 0 || graphics::Post_processing_manager == nullptr) {
return value;
}
const auto& post_effects = graphics::Post_processing_manager->getPostEffects();
if (effect_idx >= static_cast<int>(post_effects.size())) {
return value;
}
for (const auto& saved_state : Photo_mode_saved_post_effects) {
if (saved_state.effect_idx != effect_idx) {
continue;
}
const auto& effect = post_effects[effect_idx];
value = static_cast<int>(std::lround((saved_state.intensity - effect.add) * effect.div));
break;
}
return value;
}
void photo_mode_sync_parameter_values_from_saved_state()
{
for (auto& param : Photo_mode_params) {
if (param.role == photo_mode_param_role::POST_EFFECT) {
param.saved_value = photo_mode_get_saved_post_effect_value(param.effect_idx);
param.value = param.saved_value;
} else if (param.type == photo_mode_param_type::BOOL_TOGGLE) {
param.bool_value = false;
}
}
Photo_mode_selected_parameter = 0;
}
void photo_mode_apply_parameter_values()
{
for (const auto& param : Photo_mode_params) {
if (param.role == photo_mode_param_role::POST_EFFECT) {
gr_post_process_set_effect(param.effect_name, param.value, nullptr);
}
}
}
SCP_string format_photo_mode_keybind(int action)
{
auto primary = Control_config[action].first.textify();
auto secondary = Control_config[action].second.textify();
if (primary.empty() && secondary.empty()) {
return XSTR("Unbound", 1907);
}
if (primary.empty()) {
return secondary;
}
if (secondary.empty()) {
return primary;
}
return primary + " / " + secondary;
}
void photo_mode_compute_hud_layout()
{
const auto old_font = font::get_current_fontnum();
font::set_font(font::FONT1);
int max_text_width = 0;
char buf[512];
auto measure = [&](const char* text) {
int w = 0;
gr_get_string_size(&w, nullptr, text);
if (w > max_text_width) max_text_width = w;
};
// Find the longest string
measure(XSTR("Photo Mode", 1892));
measure(XSTR("Controls", 1893));
measure(XSTR("Status", 1900));
measure(XSTR("Effects", 1914));
snprintf(buf, sizeof(buf), XSTR("Toggle: %s", 1894), format_photo_mode_keybind(TOGGLE_PHOTO_MODE).c_str());
measure(buf);
snprintf(buf, sizeof(buf), XSTR("Previous Filter: %s", 1895), format_photo_mode_keybind(PHOTO_MODE_FILTER_PREV).c_str());
measure(buf);
snprintf(buf, sizeof(buf), XSTR("Next Filter: %s", 1896), format_photo_mode_keybind(PHOTO_MODE_FILTER_NEXT).c_str());
measure(buf);
snprintf(buf, sizeof(buf), XSTR("Reset Filters: %s", 1897), format_photo_mode_keybind(PHOTO_MODE_FILTER_RESET).c_str());
measure(buf);
snprintf(buf, sizeof(buf), XSTR("Decrease Parameter: %s", 1898), format_photo_mode_keybind(PHOTO_MODE_PARAM_DECREASE).c_str());
measure(buf);
snprintf(buf, sizeof(buf), XSTR("Increase Parameter: %s", 1899), format_photo_mode_keybind(PHOTO_MODE_PARAM_INCREASE).c_str());
measure(buf);
// Use worst case placeholder values for the dynamic status strings so the
// panel width stays stable as these change during a session.
snprintf(buf, sizeof(buf), XSTR("Time Compression: %.2fx", 1901), 64.0f); measure(buf);
snprintf(buf, sizeof(buf), XSTR("Cam Pos: X %.1f Y %.1f Z %.1f", 1902), -99999.9f, -99999.9f, -99999.9f); measure(buf);
for (const auto& param : Photo_mode_params) {
if (param.type == photo_mode_param_type::INT_RANGE) {
snprintf(buf, sizeof(buf), "%s: %d", XSTR(param.label, param.xstr_id), param.max_val);
} else {
snprintf(buf, sizeof(buf), "%s: %s", XSTR(param.label, param.xstr_id), XSTR("Off", 1286));
}
measure(buf);
}
font::set_font(old_font);
Photo_mode_panel_padding_w = max_text_width / 10;
Photo_mode_panel_width = max_text_width + Photo_mode_panel_padding_w * 2;
}
void photo_mode_set_active(bool active)
{
if (active == Photo_mode_active) {
return;
}
if (active) {
if (!Photo_mode_allowed) {
return;
}
if ((Game_mode & GM_MULTIPLAYER) != 0 || Player_obj == nullptr || !(Game_mode & GM_IN_MISSION)) {
return;
}
if (Time_compression_locked) {
return;
}
if (Player_obj->type != OBJ_SHIP) {
return;
}
Photo_mode_saved_time_compression = Game_time_compression;
Photo_mode_saved_lock_state = Time_compression_locked;
Photo_mode_id = cam_create("Photo Mode", &Eye_position, &Eye_matrix);
if (!Photo_mode_id.isValid() || !cam_set_camera(Photo_mode_id)) {
cam_delete(Photo_mode_id);
Photo_mode_id = camid();
return;
}
set_time_compression(Photo_mode_time_compression, 0.0f);
lock_time_compression(true);
photo_mode_capture_post_effect_state();
photo_mode_sync_parameter_values_from_saved_state();
photo_mode_apply_parameter_values();
photo_mode_compute_hud_layout();
audiostream_pause_all();
message_pause_all();
Photo_mode_audio_paused = true;
Photo_mode_active = true;
mprintf(("Photo Mode enabled.\n"));
if (scripting::hooks::OnPhotoModeStarted->isActive()) {
scripting::hooks::OnPhotoModeStarted->run();
}
return;
}
cam_reset_camera();
cam_delete(Photo_mode_id);
Photo_mode_id = camid();
set_time_compression(f2fl(Photo_mode_saved_time_compression), 0.0f);
lock_time_compression(Photo_mode_saved_lock_state);
if (Photo_mode_audio_paused) {
audiostream_unpause_all();
message_resume_all();
Photo_mode_audio_paused = false;
}
photo_mode_apply_saved_post_effect_state(true);
for (auto& param : Photo_mode_params) {
if (param.type == photo_mode_param_type::INT_RANGE) {
param.value = 100;
param.saved_value = 100;
} else if (param.type == photo_mode_param_type::BOOL_TOGGLE) {
param.bool_value = false;
}
}
Photo_mode_selected_parameter = 0;
Photo_mode_active = false;
mprintf(("Photo Mode disabled.\n"));
if (scripting::hooks::OnPhotoModeEnded->isActive()) {
scripting::hooks::OnPhotoModeEnded->run();
}
}
void photo_mode_do_frame(float frame_time)
{
if (!Photo_mode_active || !Photo_mode_id.isValid()) {
return;
}
if (!Photo_mode_allowed) {
photo_mode_set_active(false);
return;
}
auto photo_mode = Photo_mode_id.getCamera();
if (photo_mode == nullptr) {
photo_mode_set_active(false);
return;
}
vec3d cam_pos = vmd_zero_vector;
matrix cam_orient = vmd_identity_matrix;
photo_mode->get_info(&cam_pos, &cam_orient);
angles delta_angles{};
float pitch = check_control_timef(PITCH_FORWARD) - check_control_timef(PITCH_BACK);
float heading = check_control_timef(YAW_RIGHT) - check_control_timef(YAW_LEFT);
float bank = check_control_timef(BANK_LEFT) - check_control_timef(BANK_RIGHT);
int axis[Action::NUM_VALUES] = {0};
control_get_axes_readings(axis, flRealframetime);
pitch += -f2fl(axis[Action::PITCH]);
heading += f2fl(axis[Action::HEADING]);
bank -= f2fl(axis[Action::BANK]);
CLAMP(pitch, -1.0f, 1.0f);
CLAMP(heading, -1.0f, 1.0f);
CLAMP(bank, -1.0f, 1.0f);
delta_angles.p = pitch * Photo_mode_turn_rate * frame_time;
delta_angles.h = heading * Photo_mode_turn_rate * frame_time;
delta_angles.b = bank * Photo_mode_turn_rate * frame_time;
matrix delta_orient = vmd_identity_matrix;
vm_angles_2_matrix(&delta_orient, &delta_angles);
vm_matrix_x_matrix(&cam_orient, &cam_orient, &delta_orient);
vm_fix_matrix(&cam_orient);
float speed = Photo_mode_move_speed;
if (check_control(AFTERBURNER)) {
speed *= Photo_mode_boost_multiplier;
}
float forward = check_control_timef(FORWARD_THRUST) - check_control_timef(REVERSE_THRUST);
float right = check_control_timef(RIGHT_SLIDE_THRUST) - check_control_timef(LEFT_SLIDE_THRUST);
float up = check_control_timef(UP_SLIDE_THRUST) - check_control_timef(DOWN_SLIDE_THRUST);
CLAMP(forward, -1.0f, 1.0f);
CLAMP(right, -1.0f, 1.0f);
CLAMP(up, -1.0f, 1.0f);
vm_vec_scale_add2(&cam_pos, &cam_orient.vec.fvec, forward * speed * frame_time);
vm_vec_scale_add2(&cam_pos, &cam_orient.vec.rvec, right * speed * frame_time);
vm_vec_scale_add2(&cam_pos, &cam_orient.vec.uvec, up * speed * frame_time);
photo_mode->set_rotation(&cam_orient);
photo_mode->set_position(&cam_pos);
}
void photo_mode_maybe_render_hud()
{
if (!Photo_mode_active || Photo_mode_screenshot_queued_this_frame || gr_is_screenshot_requested()) {
return;
}
if (!Photo_mode_allowed) {
photo_mode_set_active(false);
return;
}
auto photo_mode = Photo_mode_id.getCamera();
if (photo_mode == nullptr) {
return;
}
vec3d cam_pos = vmd_zero_vector;
matrix cam_orient = vmd_identity_matrix;
photo_mode->get_info(&cam_pos, &cam_orient);
const auto toggle_keybind = format_photo_mode_keybind(TOGGLE_PHOTO_MODE);
const auto prev_filter_keybind = format_photo_mode_keybind(PHOTO_MODE_FILTER_PREV);
const auto next_filter_keybind = format_photo_mode_keybind(PHOTO_MODE_FILTER_NEXT);
const auto reset_filter_keybind = format_photo_mode_keybind(PHOTO_MODE_FILTER_RESET);
const auto decrease_param_keybind = format_photo_mode_keybind(PHOTO_MODE_PARAM_DECREASE);
const auto increase_param_keybind = format_photo_mode_keybind(PHOTO_MODE_PARAM_INCREASE);
gr_set_color_fast(&Color_silver);
const auto old_font = font::get_current_fontnum();
font::set_font(font::FONT1);
const int line_height = gr_get_font_height();
const int num_param_lines = static_cast<int>(Photo_mode_params.size());
const int panel_padding_h = line_height / 2;
const int panel_padding_w = Photo_mode_panel_padding_w;
const int panel_width = Photo_mode_panel_width;
const int panel_height = panel_padding_h * 2 + line_height * (15 + num_param_lines);
const int panel_x = gr_screen.center_offset_x + (gr_screen.center_w / 4);
const int panel_y = gr_screen.center_offset_y + gr_screen.center_h - panel_height - (gr_screen.center_h / 6);
gr_line(panel_x, panel_y, panel_x + panel_width, panel_y, GR_RESIZE_NONE);
gr_line(panel_x, panel_y + panel_height, panel_x + panel_width, panel_y + panel_height, GR_RESIZE_NONE);
gr_line(panel_x, panel_y, panel_x, panel_y + panel_height, GR_RESIZE_NONE);
gr_line(panel_x + panel_width, panel_y, panel_x + panel_width, panel_y + panel_height, GR_RESIZE_NONE);
gr_line(panel_x,
panel_y + line_height + panel_padding_h + 1,
panel_x + panel_width,
panel_y + line_height + panel_padding_h + 1,
GR_RESIZE_NONE);
bool grid_enabled = false;
for (const auto& param : Photo_mode_params) {
if (param.role == photo_mode_param_role::GRID_OVERLAY) {
grid_enabled = param.bool_value;
break;
}
}
if (grid_enabled) {
const int x1 = gr_screen.center_offset_x + gr_screen.center_w / 3;
const int x2 = gr_screen.center_offset_x + (gr_screen.center_w * 2) / 3;
const int y1 = gr_screen.center_offset_y + gr_screen.center_h / 3;
const int y2 = gr_screen.center_offset_y + (gr_screen.center_h * 2) / 3;
gr_line(x1, gr_screen.center_offset_y, x1, gr_screen.center_offset_y + gr_screen.center_h, GR_RESIZE_NONE);
gr_line(x2, gr_screen.center_offset_y, x2, gr_screen.center_offset_y + gr_screen.center_h, GR_RESIZE_NONE);
gr_line(gr_screen.center_offset_x, y1, gr_screen.center_offset_x + gr_screen.center_w, y1, GR_RESIZE_NONE);
gr_line(gr_screen.center_offset_x, y2, gr_screen.center_offset_x + gr_screen.center_w, y2, GR_RESIZE_NONE);
}
int line = panel_y + panel_padding_h;
const int text_x = panel_x + panel_padding_w;
gr_printf_no_resize(text_x, line, "%s", XSTR("Photo Mode", 1892));
line += line_height;
line += line_height;
gr_printf_no_resize(text_x, line, "%s", XSTR("Controls", 1893));
line += line_height;
gr_printf_no_resize(text_x, line, XSTR("Toggle: %s", 1894), toggle_keybind.c_str());
line += line_height;
gr_printf_no_resize(text_x, line, XSTR("Previous Filter: %s", 1895), prev_filter_keybind.c_str());
line += line_height;
gr_printf_no_resize(text_x, line, XSTR("Next Filter: %s", 1896), next_filter_keybind.c_str());
line += line_height;
gr_printf_no_resize(text_x, line, XSTR("Reset Filters: %s", 1897), reset_filter_keybind.c_str());
line += line_height;
gr_printf_no_resize(text_x, line, XSTR("Decrease Parameter: %s", 1898), decrease_param_keybind.c_str());
line += line_height;
gr_printf_no_resize(text_x, line, XSTR("Increase Parameter: %s", 1899), increase_param_keybind.c_str());
line += line_height;
line += line_height;
gr_printf_no_resize(text_x, line, "%s", XSTR("Status", 1900));
line += line_height;
gr_printf_no_resize(text_x, line, XSTR("Time Compression: %.2fx", 1901), f2fl(Game_time_compression));
line += line_height;
gr_printf_no_resize(text_x,
line,
XSTR("Cam Pos: X %.1f Y %.1f Z %.1f", 1902),
cam_pos.xyz.x,
cam_pos.xyz.y,
cam_pos.xyz.z);
line += line_height;
line += line_height;
gr_set_color_fast(&Color_silver);
gr_printf_no_resize(text_x, line, "%s", XSTR("Effects", 1914));
line += line_height;
for (int i = 0; i < static_cast<int>(Photo_mode_params.size()); ++i) {
const auto& param = Photo_mode_params[i];
gr_set_color_fast(Photo_mode_selected_parameter == i ? &Color_bright_white : &Color_silver);
if (param.type == photo_mode_param_type::INT_RANGE) {
gr_printf_no_resize(text_x, line, "%s: %d", XSTR(param.label, param.xstr_id), param.value);
} else if (param.type == photo_mode_param_type::BOOL_TOGGLE) {
gr_printf_no_resize(text_x, line, "%s: %s", XSTR(param.label, param.xstr_id),
param.bool_value ? XSTR("On", 1285) : XSTR("Off", 1286));
}
line += line_height;
}
font::set_font(old_font);
}
void photo_mode_clear_screenshot_queued_flag()
{
Photo_mode_screenshot_queued_this_frame = false;
}
void photo_mode_set_screenshot_queued_flag()
{
Photo_mode_screenshot_queued_this_frame = true;
}
void game_toggle_photo_mode()
{
photo_mode_set_active(!Photo_mode_active);
}
void game_set_photo_mode_allowed(bool allowed)
{
Photo_mode_allowed = allowed && ((Game_mode & GM_MULTIPLAYER) == 0);
if (!Photo_mode_allowed && Photo_mode_active) {
photo_mode_set_active(false);
}
}
bool game_get_photo_mode_allowed()
{
return Photo_mode_allowed && ((Game_mode & GM_MULTIPLAYER) == 0);
}
bool game_is_photo_mode_active()
{
return Photo_mode_active;
}
void game_cycle_photo_mode_filter(int direction)
{
if (!Photo_mode_active) {
return;
}
Photo_mode_selected_parameter = std::clamp(Photo_mode_selected_parameter + direction, 0, static_cast<int>(Photo_mode_params.size()) - 1);
}
void game_reset_photo_mode_filters()
{
if (!Photo_mode_active) {
return;
}
for (auto& param : Photo_mode_params) {
if (param.type == photo_mode_param_type::INT_RANGE) {
param.value = param.saved_value;
} else if (param.type == photo_mode_param_type::BOOL_TOGGLE) {
param.bool_value = false;
}
}
photo_mode_apply_parameter_values();
}
void game_adjust_photo_mode_filter_parameter(int delta)
{
if (!Photo_mode_active) {
return;
}
auto& param = Photo_mode_params[Photo_mode_selected_parameter];
if (param.type == photo_mode_param_type::BOOL_TOGGLE) {
param.bool_value = (delta > 0);
return;
}
param.value = std::clamp(param.value + delta, param.min_val, param.max_val);
photo_mode_apply_parameter_values();
}
-16
View File
@@ -1,16 +0,0 @@
#pragma once
void photo_mode_set_active(bool active);
void photo_mode_do_frame(float frame_time);
void photo_mode_maybe_render_hud();
void photo_mode_clear_screenshot_queued_flag();
void photo_mode_set_screenshot_queued_flag();
// mission-level permission to allow/disallow Photo Mode
void game_toggle_photo_mode();
void game_set_photo_mode_allowed(bool allowed);
bool game_get_photo_mode_allowed();
bool game_is_photo_mode_active();
void game_cycle_photo_mode_filter(int direction);
void game_reset_photo_mode_filters();
void game_adjust_photo_mode_filter_parameter(int delta);
+26 -102
View File
@@ -33,7 +33,7 @@
#include "parse/encrypt.h"
#include "cfilesystem.h"
#include <algorithm>
#include <limits>
char Cfile_root_dir[CFILE_ROOT_DIRECTORY_LEN] = "";
@@ -52,7 +52,7 @@ cf_pathtype Pathtypes[CF_MAX_PATH_TYPES] = {
// Root must be index 1!!
{ CF_TYPE_ROOT, "", ".mve .ogg", CF_TYPE_ROOT },
{ CF_TYPE_DATA, "data", ".cfg .txt", CF_TYPE_ROOT },
{ CF_TYPE_MAPS, "data" DIR_SEPARATOR_STR "maps", ".pcx .ani .eff .tga .jpg .png .dds .ktx", CF_TYPE_DATA },
{ CF_TYPE_MAPS, "data" DIR_SEPARATOR_STR "maps", ".pcx .ani .eff .tga .jpg .png .dds", CF_TYPE_DATA },
{ CF_TYPE_TEXT, "data" DIR_SEPARATOR_STR "text", ".txt .net", CF_TYPE_DATA },
{ CF_TYPE_MODELS, "data" DIR_SEPARATOR_STR "models", ".pof", CF_TYPE_DATA },
{ CF_TYPE_TABLES, "data" DIR_SEPARATOR_STR "tables", ".tbl .tbm .lua", CF_TYPE_DATA },
@@ -66,26 +66,26 @@ cf_pathtype Pathtypes[CF_MAX_PATH_TYPES] = {
{ CF_TYPE_VOICE_TRAINING, "data" DIR_SEPARATOR_STR "voice" DIR_SEPARATOR_STR "training", ".wav .ogg", CF_TYPE_VOICE },
{ CF_TYPE_MUSIC, "data" DIR_SEPARATOR_STR "music", ".wav .ogg", CF_TYPE_DATA },
{ CF_TYPE_MOVIES, "data" DIR_SEPARATOR_STR "movies", ".mve .msb .ogg .mp4 .srt .webm .png",CF_TYPE_DATA },
{ CF_TYPE_INTERFACE, "data" DIR_SEPARATOR_STR "interface", ".pcx .ani .dds .tga .eff .png .jpg .rml .rcss .ktx", CF_TYPE_DATA },
{ CF_TYPE_INTERFACE, "data" DIR_SEPARATOR_STR "interface", ".pcx .ani .dds .tga .eff .png .jpg .rml .rcss", CF_TYPE_DATA },
{ CF_TYPE_FONT, "data" DIR_SEPARATOR_STR "fonts", ".vf .ttf .otf", CF_TYPE_DATA },
{ CF_TYPE_EFFECTS, "data" DIR_SEPARATOR_STR "effects", ".ani .eff .pcx .neb .tga .jpg .png .dds .ktx .sdr .vert .frag .glsl", CF_TYPE_DATA },
{ CF_TYPE_HUD, "data" DIR_SEPARATOR_STR "hud", ".pcx .ani .eff .tga .jpg .png .dds .ktx", CF_TYPE_DATA },
{ CF_TYPE_EFFECTS, "data" DIR_SEPARATOR_STR "effects", ".ani .eff .pcx .neb .tga .jpg .png .dds .sdr", CF_TYPE_DATA },
{ CF_TYPE_HUD, "data" DIR_SEPARATOR_STR "hud", ".pcx .ani .eff .tga .jpg .png .dds", CF_TYPE_DATA },
{ CF_TYPE_PLAYERS, "data" DIR_SEPARATOR_STR "players", ".hcf", /* DON'T add pilot files here!! */ CF_TYPE_DATA },
{ CF_TYPE_PLAYER_IMAGES, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "images", ".pcx .png .dds .ktx", CF_TYPE_PLAYERS },
{ CF_TYPE_SQUAD_IMAGES, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "squads", ".pcx .png .dds .ktx", CF_TYPE_PLAYERS },
{ CF_TYPE_PLAYER_IMAGES, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "images", ".pcx .png .dds", CF_TYPE_PLAYERS },
{ CF_TYPE_SQUAD_IMAGES, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "squads", ".pcx .png .dds", CF_TYPE_PLAYERS },
{ CF_TYPE_SINGLE_PLAYERS, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "single", ".pl2 .cs2 .plr .csg .css .json", CF_TYPE_PLAYERS },
{ CF_TYPE_MULTI_PLAYERS, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "multi", ".plr .json", CF_TYPE_PLAYERS },
{ CF_TYPE_PLAYER_BINDS, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "presets", ".json", CF_TYPE_PLAYERS },
{ CF_TYPE_CACHE, "data" DIR_SEPARATOR_STR "cache", ".clr .tmp .bx", CF_TYPE_DATA }, //clr=cached color
{ CF_TYPE_MULTI_CACHE, "data" DIR_SEPARATOR_STR "multidata", ".pcx .png .jpg .dds .fs2 .txt .ktx", CF_TYPE_DATA },
{ CF_TYPE_MULTI_CACHE, "data" DIR_SEPARATOR_STR "multidata", ".pcx .png .jpg .dds .fs2 .txt", CF_TYPE_DATA },
{ CF_TYPE_MISSIONS, "data" DIR_SEPARATOR_STR "missions", ".fs2 .fc2 .ntl .ssv", CF_TYPE_DATA },
{ CF_TYPE_CONFIG, "data" DIR_SEPARATOR_STR "config", ".cfg .tbl .tbm .xml .csv", CF_TYPE_DATA },
{ CF_TYPE_DEMOS, "data" DIR_SEPARATOR_STR "demos", ".fsd", CF_TYPE_DATA },
{ CF_TYPE_CBANIMS, "data" DIR_SEPARATOR_STR "cbanims", ".pcx .ani .eff .tga .jpg .png .dds .ktx", CF_TYPE_DATA },
{ CF_TYPE_INTEL_ANIMS, "data" DIR_SEPARATOR_STR "intelanims", ".pcx .ani .eff .tga .jpg .png .dds .ktx", CF_TYPE_DATA },
{ CF_TYPE_CBANIMS, "data" DIR_SEPARATOR_STR "cbanims", ".pcx .ani .eff .tga .jpg .png .dds", CF_TYPE_DATA },
{ CF_TYPE_INTEL_ANIMS, "data" DIR_SEPARATOR_STR "intelanims", ".pcx .ani .eff .tga .jpg .png .dds", CF_TYPE_DATA },
{ CF_TYPE_SCRIPTS, "data" DIR_SEPARATOR_STR "scripts", ".lua .lc .fnl", CF_TYPE_DATA },
{ CF_TYPE_FICTION, "data" DIR_SEPARATOR_STR "fiction", ".txt", CF_TYPE_DATA },
{ CF_TYPE_FREDDOCS, "data" DIR_SEPARATOR_STR "freddocs", ".html .css .png .jpg", CF_TYPE_DATA }
{ CF_TYPE_FREDDOCS, "data" DIR_SEPARATOR_STR "freddocs", ".html", CF_TYPE_DATA }
};
// clang-format on
@@ -185,13 +185,7 @@ int cfile_init(const char *exe_dir, const char *cdrom_dir)
char buf[CFILE_ROOT_DIRECTORY_LEN];
#ifndef __ANDROID__
strncpy(buf, exe_dir, CFILE_ROOT_DIRECTORY_LEN - 1);
#else
(void)exe_dir;
strncpy(buf, os_android_get_working_folder_path().c_str(), CFILE_ROOT_DIRECTORY_LEN - 1);
#endif
strncpy(buf, exe_dir, CFILE_ROOT_DIRECTORY_LEN - 1);
buf[CFILE_ROOT_DIRECTORY_LEN - 1] = '\0';
// are we in a root directory?
@@ -837,7 +831,7 @@ static int cfget_cfile_block()
mprintf(("Out of cfile blocks! Currently opened files:\n"));
dump_opened_files();
Warning(LOCATION, "There are no more free cfile blocks. This means that there are too many files opened by FSO.\n"
UNREACHABLE("There are no more free cfile blocks. This means that there are too many files opened by FSO.\n"
"This is probably caused by a programming or scripting error where a file does not get closed."); // out of free cfile blocks
return -1;
}
@@ -1110,98 +1104,28 @@ void cfread_string(char *buf, int n, CFILE *file)
} while (c != 0 );
}
namespace {
struct string_len_header {
int len = 0;
int stored = 0;
int start = 0;
bool length_cut = false;
};
// a past-the-end length is clamped like any cfread, but a negative one has nothing to clamp to, so inside a
// limited section it throws and the loader skips the rest of the section
string_len_header read_string_len_header(CFILE* file)
void cfread_string_len(char *buf, int buffer_size, CFILE *file)
{
string_len_header h;
if (!cf_is_valid(file)) {
return h;
int len;
len = cfread_int(file);
Assertion( (len <= buffer_size), "String cannot fit in buffer, len: %i, buffer: %i", len, buffer_size);
if (len) {
cfread(buf, len, 1, file);
Assertion(len != buffer_size || buf[len - 1] == 0, "Unterminated string does not fit in buffer");
}
int before = cftell(file);
h.length_cut = cfread(&h.len, sizeof(h.len), 1, file) != 1;
h.start = cftell(file);
if (h.length_cut) {
// a clean end of file reads as an empty string without a warning, as cfread_int does
h.length_cut = (h.start != before) || (cfeof(file) == 0);
return h;
}
h.len = INTEL_INT(h.len);
if ((h.len < 0) && (file->max_read_len != 0)) {
throw cfile::max_read_length("Attempted to read a string of negative length " + std::to_string(h.len));
}
h.stored = static_cast<int>(cf_check_read_size(file, static_cast<size_t>(std::max(h.len, 0))));
return h;
}
// reads count of the stored characters and leaves the file just past the whole string; false if the read failed
bool read_string_len_body(const string_len_header& h, char* dest, int count, CFILE* file)
{
bool ok = (count <= 0) || (cfread(dest, count, 1, file) == 1);
if (!ok || (h.stored > count)) {
cfseek(file, h.start + h.stored, CF_SEEK_SET);
}
return ok;
}
// warned last, so the file position is right even if a debug build stops here
void warn_string_len(const string_len_header& h, bool read_ok, bool cut, int buffer_size, CFILE* file)
{
if (h.length_cut) {
Warning(LOCATION, "cfread_string_len: cut-off string length field in %s", cf_get_filename(file));
} else if (!read_ok) {
Warning(LOCATION,
"cfread_string_len: could not read a string of %d characters in %s",
h.stored,
cf_get_filename(file));
} else if (h.len != h.stored) {
Warning(LOCATION, "cfread_string_len: corrupt string length %d in %s", h.len, cf_get_filename(file));
} else if (cut) {
Warning(LOCATION,
"cfread_string_len: a string of %d bytes was cut to fit a buffer of %d in %s",
h.len,
buffer_size,
cf_get_filename(file));
}
}
} // namespace
void cfread_string_len(char* buf, int buffer_size, CFILE* file)
{
Assertion(buffer_size > 0, "cfread_string_len needs room for at least the terminator, buffer: %i", buffer_size);
string_len_header h = read_string_len_header(file);
if (buffer_size <= 0) {
bool read_ok = read_string_len_body(h, buf, 0, file);
warn_string_len(h, read_ok, h.stored > 0, buffer_size, file);
return;
}
int count = std::min(h.stored, buffer_size);
bool read_ok = read_string_len_body(h, buf, count, file);
int kept = read_ok ? count : 0;
bool cut = (kept == buffer_size) && (memchr(buf, 0, buffer_size) == nullptr);
buf[std::min(kept, buffer_size - 1)] = 0;
warn_string_len(h, read_ok, cut, buffer_size, file);
buf[MIN(len, buffer_size - 1)] = 0;
}
SCP_string cfread_string_len(CFILE *file)
{
string_len_header h = read_string_len_header(file);
int len = cfread_int(file);
SCP_string str;
str.resize(h.stored);
bool read_ok = read_string_len_body(h, str.data(), h.stored, file);
if (!read_ok) {
str.clear();
}
warn_string_len(h, read_ok, false, 0, file);
str.resize(len);
if (len)
cfread(&str[0], len, 1, file);
return str;
}
+2 -8
View File
@@ -320,26 +320,20 @@ void cfread_string(char *buf,int n, CFILE *file);
/**
* @brief Read a fixed length string that is not null-terminated, with the length stored in file.
*
* Keeps at most buffer_size - 1 characters and leaves the file just past the whole string, unless it throws.
*
* If it is not null-terminated, the length of the string *must* be less than the size of the buffer (to make room for one)
*
* @param buf Pre-allocated array to store string
* @param buffer_size Size of pre-allocated array
* @param file File to read from
*
* @note Appends NULL character to string (buf)
* @note Bad data gets a warning; at a clean end of file, or with an invalid file, the string is empty and nothing is
* warned. Inside a limited section (cf_set_max_read_len), a negative length, or a read that still passes the limit
* once clamped to the end of the file, throws cfile::max_read_length.
*/
void cfread_string_len(char *buf,int buffer_size, CFILE *file);
/**
* @brief Read a string from the file where the length is stored in the file
*
* @param file The file to read the string from
* @return The string that was read
*
* @note Warns and throws like the char* overload, except that nothing is cut.
*/
SCP_string cfread_string_len(CFILE *file);
+14 -24
View File
@@ -193,8 +193,21 @@ int cfseek( CFILE *cfile, int offset, int where )
}
size_t cf_check_read_size(CFILE* cfile, size_t size)
// cfread() reads from a file
//
// returns: returns the number of full elements read
//
//
int cfread(void *buf, int elsize, int nelem, CFILE *cfile)
{
if(!cf_is_valid(cfile))
return 0;
size_t size = elsize*nelem;
if(buf == NULL || size <= 0)
return 0;
if ( (cfile->raw_position+size) > cfile->size ) {
Assertion(cfile->raw_position <= cfile->size, "Invalid raw_position value detected!");
size = cfile->size - cfile->raw_position;
@@ -213,29 +226,6 @@ size_t cf_check_read_size(CFILE* cfile, size_t size)
}
}
return size;
}
// cfread() reads from a file
//
// returns: returns the number of full elements read
//
//
int cfread(void *buf, int elsize, int nelem, CFILE *cfile)
{
if(!cf_is_valid(cfile))
return 0;
size_t size = elsize*nelem;
if(buf == nullptr || size <= 0)
return 0;
size = cf_check_read_size(cfile, size);
if (size < 1) {
return 0;
}
size_t bytes_read;
if (cfile->data != nullptr) {
// This is a file from memory
-5
View File
@@ -62,9 +62,4 @@ void cf_check_compression(CFILE* cfile);
// Used to clear compression info data and free dynamic memory used by compression
void cf_clear_compression_info(CFILE* cfile);
// Clamps a read of size bytes to the end of the file and returns the clamped size, or 0 at the end of the file
// without checking the limit; throws cfile::max_read_length if the clamped read would pass the file's read limit
// (cf_set_max_read_len).
size_t cf_check_read_size(CFILE* cfile, size_t size);
#endif
+7 -9
View File
@@ -532,7 +532,7 @@ void cf_build_pack_list( cf_root *root )
s_root.roottype = CF_ROOTTYPE_PACK;
s_root.cf_type = i;
temp_roots_sort.push_back(std::move(s_root));
temp_roots_sort.push_back(s_root);
}
}
@@ -1083,7 +1083,7 @@ void cf_search_root_pack(int root_index)
file.pathtype = path_type;
file.offset = find.offset;
files.push_back(std::move(file));
files.push_back(file);
//mprintf(( "Found pack file '%s'\n", find.filename ));
}
@@ -1356,7 +1356,7 @@ CFileLocation cf_find_file_location(const char* filespec, int pathtype, uint32_t
fclose(fp);
res.offset = 0;
res.full_name = std::move(longname);
res.full_name = longname;
res.name_ext = filespec;
return res;
@@ -1549,8 +1549,8 @@ CFileLocationExt cf_find_file_location_ext(const char *filename, const int ext_n
fclose(fp);
res.offset = 0;
res.full_name = std::move(longname);
res.name_ext = std::move(filespec_ext);
res.full_name = longname;
res.name_ext = filespec_ext;
return res;
}
@@ -2437,9 +2437,7 @@ int cf_create_default_path_string(SCP_string& path, int pathtype, const char* fi
}
if (!root) {
if (filename == nullptr) {
return 0;
}
Assert( filename != NULL );
path.assign(filename);
return 1;
}
@@ -2482,7 +2480,7 @@ void cfile_spew_pack_file_crcs()
my_time = time(NULL);
memset( datetime, 0, sizeof(datetime) );
snprintf(datetime, sizeof(datetime), "%s", ctime(&my_time));
snprintf(datetime, sizeof(datetime)-1, "%s", ctime(&my_time));
// ctime() adds a newline char, so we have to strip it off
datetime[strlen(datetime)-1] = '\0';
+2 -2
View File
@@ -135,7 +135,7 @@ void parse_cheat_table(const char* filename) {
}
if (shipSpawn) {
std::unique_ptr<CustomCheat> shipCheat(new SpawnShipCheat(code, std::move(msg), requireCheats, std::move(shipClass), std::move(shipName)));
std::unique_ptr<CustomCheat> shipCheat(new SpawnShipCheat(code, msg, requireCheats, shipClass, shipName));
if(customCheats.count(code) == 1) {
Warning(LOCATION, "A cheat for code '%s' already exists. It will be replaced.", code.c_str());
@@ -144,7 +144,7 @@ void parse_cheat_table(const char* filename) {
customCheats.emplace(code, std::move(shipCheat));
}
} else {
std::unique_ptr<CustomCheat> cheat(new CustomCheat(code, std::move(msg), requireCheats));
std::unique_ptr<CustomCheat> cheat(new CustomCheat(code, msg, requireCheats));
if(customCheats.count(code) == 1) {
Warning(LOCATION, "A cheat for code '%s' already exists. It will be replaced.", code.c_str());
+1 -1
View File
@@ -35,7 +35,7 @@ class SpawnShipCheat : public CustomCheat {
SCP_string shipName;
public:
SpawnShipCheat(SCP_string cheat_code, SCP_string cheat_msg, bool require_cheats_enabled, SCP_string class_name, SCP_string ship_name) : CustomCheat(std::move(cheat_code), std::move(cheat_msg), require_cheats_enabled),
SpawnShipCheat(SCP_string cheat_code, SCP_string cheat_msg, bool require_cheats_enabled, SCP_string class_name, SCP_string ship_name) : CustomCheat(cheat_code, cheat_msg, require_cheats_enabled),
shipClassName(std::move(class_name)),
shipName(std::move(ship_name)) { }
+73 -224
View File
@@ -15,7 +15,6 @@
#include "globalincs/pstypes.h"
#include "globalincs/systemvars.h"
#include "globalincs/version.h"
#include "graphics/2d.h"
#include "graphics/openxr.h"
#include "graphics/shadows.h"
#include "hud/hudconfig.h"
@@ -75,7 +74,6 @@ const char *cmdline_arg_types[] =
enum class flag_output_type {
Binary,
Json_V1,
Json_V2,
};
// variables
@@ -358,7 +356,6 @@ cmdline_parm fb_explosions_arg("-fb_explosions", NULL, AT_NONE);
cmdline_parm fb_thrusters_arg("-fb_thrusters", NULL, AT_NONE);
cmdline_parm shadow_quality_arg("-shadow_quality", NULL, AT_INT);
cmdline_parm enable_shadows_arg("-enable_shadows", NULL, AT_NONE);
cmdline_parm rt_shadows_arg("-rt_shadows", nullptr, AT_NONE);
cmdline_parm no_deferred_lighting_arg("-no_deferred", NULL, AT_NONE); // Cmdline_no_deferred
cmdline_parm deferred_lighting_cockpit_arg("-deferred_cockpit", nullptr, AT_NONE);
cmdline_parm anisotropy_level_arg("-anisotropic_filter", NULL, AT_INT);
@@ -516,7 +513,6 @@ cmdline_parm deprecated_res_arg("-res", "Deprecated, resolution, formatted like
cmdline_parm render_res_arg("-render_res", "Resolution, formatted like 1600x900", AT_STRING);
cmdline_parm window_res_arg("-window_res", "Window resolution, formatted like 1600x900.", AT_STRING);
cmdline_parm center_res_arg("-center_res", "Resolution of center monitor, formatted like 1600x900", AT_STRING);
cmdline_parm hdr_nits_arg("-hdr", "Forces HDR output on, overriding the in-game HDR setting. Optionally takes paper white and peak luminance in nits, formatted like 400,1500, overriding the in-game HDR nits settings.", AT_STRING);
cmdline_parm verify_vps_arg("-verify_vps", NULL, AT_NONE); // Cmdline_verify_vps -- spew VP crcs to vp_crcs.txt
cmdline_parm parse_cmdline_only(PARSE_COMMAND_LINE_STRING, "Ignore any cmdline_fso.cfg files", AT_NONE);
cmdline_parm reparse_mainhall_arg("-reparse_mainhall", NULL, AT_NONE); //Cmdline_reparse_mainhall
@@ -531,7 +527,6 @@ cmdline_parm show_video_info("-show_video_info", NULL, AT_NONE); //Cmdline_show_
cmdline_parm frame_profile_arg("-profile_frame_time", NULL, AT_NONE); //Cmdline_frame_profile
cmdline_parm debug_window_arg("-debug_window", NULL, AT_NONE); // Cmdline_debug_window
cmdline_parm graphics_debug_output_arg("-gr_debug", nullptr, AT_NONE); // Cmdline_graphics_debug_output
cmdline_parm gr_sync_validation_arg("-gr_sync_validation", nullptr, AT_NONE); // Cmdline_gr_sync_validation (implies -gr_debug)
cmdline_parm log_to_stdout_arg("-stdout_log", nullptr, AT_NONE); // Cmdline_log_to_stdout
cmdline_parm slow_frames_ok_arg("-slow_frames_ok", nullptr, AT_NONE); // Cmdline_slow_frames_ok
cmdline_parm fixed_seed_rand("-seed", nullptr, AT_INT); // Cmdline_rng_seed,Cmdline_reuse_rng_seed;
@@ -539,7 +534,6 @@ cmdline_parm luadev_arg("-luadev", "Make lua errors non-fatal", AT_NONE); // Cmd
cmdline_parm override_arg("-override_data", "Enable override directory", AT_NONE); // Cmdline_override_data
cmdline_parm imgui_debug_arg("-imgui_debug", nullptr, AT_NONE);
cmdline_parm vulkan("-vulkan", nullptr, AT_NONE);
cmdline_parm opengl("-opengl", nullptr, AT_NONE);
cmdline_parm multithreading("-threads", nullptr, AT_INT);
char *Cmdline_start_mission = NULL;
@@ -556,12 +550,7 @@ int Cmdline_show_pos = 0;
int Cmdline_show_stats = 0;
int Cmdline_save_render_targets = 0;
bool Cmdline_window = false;
#ifdef __ANDROID__
// Default to borderless in the legacy window-mode path as well.
bool Cmdline_fullscreen_window = true;
#else
bool Cmdline_fullscreen_window = false;
#endif
std::optional<std::pair<uint16_t, uint16_t>>Cmdline_window_res = std::nullopt;
char *Cmdline_res = 0;
char *Cmdline_center_res = 0;
@@ -578,13 +567,12 @@ bool Cmdline_frame_profile = false;
bool Cmdline_show_video_info = false;
bool Cmdline_debug_window = false;
bool Cmdline_graphics_debug_output = false;
bool Cmdline_gr_sync_validation = false;
bool Cmdline_log_to_stdout = false;
bool Cmdline_slow_frames_ok = false;
bool Cmdline_lua_devmode = false;
bool Cmdline_override_data = false;
bool Cmdline_show_imgui_debug = false;
GraphicsAPI Cmdline_graphics_api = GraphicsAPI::Default;
bool Cmdline_vulkan = false;
int Cmdline_multithreading = 1;
// Other
@@ -1334,7 +1322,7 @@ static void handle_unix_modlist(char **modlist, size_t *len)
for (char *cur_mod = strtok(*modlist, ","); cur_mod != NULL; cur_mod = strtok(NULL, ",")) {
SCP_string path = get_real_mod_path(cur_mod);
mod_paths.push_back(std::move(path));
mod_paths.push_back(path);
}
// create new char[] to replace modlist
@@ -1364,58 +1352,51 @@ static void handle_unix_modlist(char **modlist, size_t *len)
// external entry point into this modules
static void json_add_version(json_t* root) {
auto version_obj = json_object();
json_object_set_new(version_obj, "full", json_string(FS_VERSION_FULL));
json_object_set_new(version_obj, "major", json_integer(FS_VERSION_MAJOR));
json_object_set_new(version_obj, "minor", json_integer(FS_VERSION_MINOR));
json_object_set_new(version_obj, "build", json_integer(FS_VERSION_BUILD));
json_object_set_new(version_obj, "has_revision", json_boolean(FS_VERSION_HAS_REVIS));
json_object_set_new(version_obj, "revision", json_integer(FS_VERSION_REVIS));
json_object_set_new(version_obj, "revision_str", json_string(FS_VERSION_REVIS_STR));
json_object_set_new(root, "version", version_obj);
}
static void json_add_easy_flags(json_t* root) {
auto easy_array = json_array();
for (auto& easy_flag : easy_flags) {
json_array_append_new(easy_array, json_string(easy_flag.name));
}
json_object_set_new(root, "easy_flags", easy_array);
}
static void json_add_flags(json_t* root) {
auto flags_array = json_array();
for (auto& flag : exe_params) {
auto flag_obj = json_object();
json_object_set_new(flag_obj, "name", json_string(flag.name));
json_object_set_new(flag_obj, "description", json_string(flag.desc));
json_object_set_new(flag_obj, "fso_only", json_boolean(flag.fso_only));
json_object_set_new(flag_obj, "on_flags", json_integer(flag.on_flags));
json_object_set_new(flag_obj, "off_flags", json_integer(flag.off_flags));
json_object_set_new(flag_obj, "type", json_string(flag.type));
json_object_set_new(flag_obj, "web_url", json_string(flag.web_url));
json_array_append_new(flags_array, flag_obj);
}
json_object_set_new(root, "flags", flags_array);
}
static json_t* json_get_v1() {
auto root = json_object();
json_add_version(root);
json_add_easy_flags(root);
json_add_flags(root);
{
auto version_obj = json_object();
json_object_set_new(version_obj, "full", json_string(FS_VERSION_FULL));
json_object_set_new(version_obj, "major", json_integer(FS_VERSION_MAJOR));
json_object_set_new(version_obj, "minor", json_integer(FS_VERSION_MINOR));
json_object_set_new(version_obj, "build", json_integer(FS_VERSION_BUILD));
json_object_set_new(version_obj, "has_revision", json_boolean(FS_VERSION_HAS_REVIS));
json_object_set_new(version_obj, "revision", json_integer(FS_VERSION_REVIS));
json_object_set_new(version_obj, "revision_str", json_string(FS_VERSION_REVIS_STR));
json_object_set_new(root, "version", version_obj);
}
{
auto easy_array = json_array();
for (auto& easy_flag : easy_flags) {
json_array_append_new(easy_array, json_string(easy_flag.name));
}
json_object_set_new(root, "easy_flags", easy_array);
}
{
auto flags_array = json_array();
for (auto& flag : exe_params) {
auto flag_obj = json_object();
json_object_set_new(flag_obj, "name", json_string(flag.name));
json_object_set_new(flag_obj, "description", json_string(flag.desc));
json_object_set_new(flag_obj, "fso_only", json_boolean(flag.fso_only));
json_object_set_new(flag_obj, "on_flags", json_integer(flag.on_flags));
json_object_set_new(flag_obj, "off_flags", json_integer(flag.off_flags));
json_object_set_new(flag_obj, "type", json_string(flag.type));
json_object_set_new(flag_obj, "web_url", json_string(flag.web_url));
json_array_append_new(flags_array, flag_obj);
}
json_object_set_new(root, "flags", flags_array);
}
{
auto caps_array = json_array();
@@ -1433,7 +1414,7 @@ static json_t* json_get_v1() {
auto voices = speech_enumerate_voices();
for (auto& voice : voices) {
json_array_append_new(voices_array, json_string(voice.second.c_str()));
json_array_append_new(voices_array, json_string(voice.c_str()));
}
json_object_set_new(root, "voices", voices_array);
@@ -1526,19 +1507,6 @@ static json_t* json_get_v1() {
return root;
}
// json_v2 reports version, supported flags, and the preferences path for launchers,
// without querying graphics, audio, or joystick devices.
static json_t* json_get_v2() {
auto root = json_object();
json_add_version(root);
json_add_easy_flags(root);
json_add_flags(root);
json_object_set_new(root, "pref_path", json_string(os_get_config_path().c_str()));
return root;
}
static void write_flags_file() {
FILE *fp = fopen("flags.lch","w");
@@ -1596,8 +1564,6 @@ static flag_output_type get_flags_output_type() {
return flag_output_type::Binary;
} else if (type == "json_v1") {
return flag_output_type::Json_V1;
} else if (type == "json_v2") {
return flag_output_type::Json_V2;
} else {
// This is supposed to make it easy for the launcher to recognize an unsupported type
printf("OUTPUT TYPE NOT SUPPORTED!\n");
@@ -1608,23 +1574,17 @@ static flag_output_type get_flags_output_type() {
static void write_flags() {
auto type = get_flags_output_type();
if (type == flag_output_type::Binary) {
switch(type) {
case flag_output_type::Binary:
write_flags_file();
return;
break;
case flag_output_type::Json_V1:
json_t* root = json_get_v1();
json_dumpf(root, stdout, JSON_INDENT(4));
json_decref(root);
break;
}
json_t* root = (type == flag_output_type::Json_V1) ? json_get_v1() : json_get_v2();
#ifdef __ANDROID__
char* dumped = json_dumps(root, JSON_INDENT(4));
os_android_set_flags_string(dumped ? dumped : "");
free(dumped);
#else
json_dumpf(root, stdout, JSON_INDENT(4));
#endif
json_decref(root);
}
bool SetCmdlineParams()
@@ -1815,45 +1775,38 @@ bool SetCmdlineParams()
}
// d3d windowed
// We need to set both the raw global (for the legacy !Using_in_game_options path) and the
// Option<T> override (for the modern path) since either backend may be the one actually consulted.
if(window_arg.found()) {
options::OptionsManager::instance()->setOverride("Graphics.WindowMode",
std::unique_ptr<json_t>(json_integer(static_cast<int>(os::ViewportState::Windowed))), "-window");
// We need to set both values since we don't know if we are going to use the new config system
//options::OptionsManager::instance()->setOverride("Graphics.WindowMode", "0");
Cmdline_window = true;
Cmdline_fullscreen_window = false;
}
if ( fullscreen_window_arg.found( ) )
{
options::OptionsManager::instance()->setOverride("Graphics.WindowMode",
std::unique_ptr<json_t>(json_integer(static_cast<int>(os::ViewportState::Borderless))),
"-fullscreen_window");
//options::OptionsManager::instance()->setOverride("Graphics.WindowMode", "1");
Cmdline_fullscreen_window = true;
Cmdline_window = false; /* Make sure no-one sets both */
}
if(render_res_arg.found() || deprecated_res_arg.found()){
const char* res_flag_name;
if (render_res_arg.found()) {
Cmdline_res = render_res_arg.str();
res_flag_name = "-render_res";
}
else {
Cmdline_res = deprecated_res_arg.str();
res_flag_name = "-res";
mprintf(("Deprecated -res argument. Use -render_res instead...\n"));
}
int width = 0;
/*int width = 0;
int height = 0;
if (sscanf(Cmdline_res, "%dx%d", &width, &height) == 2) {
options::OptionsManager::instance()->setOverride("Graphics.Resolution",
std::unique_ptr<json_t>(json_pack("{s:i, s:i}", "width", width, "height", height)), res_flag_name);
SCP_string override;
sprintf(override, "{\"width\":%d,\"height\":%d}", width, height);
options::OptionsManager::instance()->setOverride("Graphics.Resolution", override);
} else {
Warning(LOCATION, "Failed to parse -res parameter \"%s\". Must be in format \"<width>x<height>\".\n", Cmdline_res);
}
}*/
}
if(window_res_arg.found()){
int width = 0;
@@ -1869,24 +1822,6 @@ bool SetCmdlineParams()
if(center_res_arg.found()){
Cmdline_center_res = center_res_arg.str();
}
if (hdr_nits_arg.found()) {
// presence of the flag alone forces HDR output on, overriding the in-game HDR setting
options::OptionsManager::instance()->setOverride("Graphics.HDR",
std::unique_ptr<json_t>(json_true()), "-hdr");
if (hdr_nits_arg.has_param()) {
float paperwhite_nits = 0.0f, peak_nits = 0.0f;
if (sscanf(hdr_nits_arg.str(), "%f,%f", &paperwhite_nits, &peak_nits) == 2 && paperwhite_nits > 0.0f && peak_nits > 0.0f) {
// json_real keeps these JSON reals; json_unpack's "f" format rejects a bare integer like "400"
options::OptionsManager::instance()->setOverride("Graphics.HDRPaperWhite",
std::unique_ptr<json_t>(json_real(paperwhite_nits)), "-hdr");
options::OptionsManager::instance()->setOverride("Graphics.HDRPeakLuminance",
std::unique_ptr<json_t>(json_real(peak_nits)), "-hdr");
} else {
Warning(LOCATION, "Failed to parse -hdr parameter \"%s\". Must be in format \"<paperwhite_nits>,<peak_nits>\".\n", hdr_nits_arg.str());
}
}
}
if(almission_arg.found()){//DTP for autoload mission // developer oritentated
Cmdline_almission = almission_arg.str();
Cmdline_use_last_pilot = 1;
@@ -1979,20 +1914,17 @@ bool SetCmdlineParams()
if ( fov_arg.found() ) {
auto val = fov_arg.get_float();
if (val <= 0.1f) {
val = DEFAULT_FOV;
if (val > 0.1) {
VIEWER_ZOOM_DEFAULT = val;
} else {
VIEWER_ZOOM_DEFAULT = DEFAULT_FOV;
}
VIEWER_ZOOM_DEFAULT = val;
options::OptionsManager::instance()->setOverride("Graphics.FOV",
std::unique_ptr<json_t>(json_real(val)), "-fov");
}
if ( fov_cockpit_arg.found() ) {
auto val = fov_cockpit_arg.get_float();
if (val > 0.1f) {
if (val > 0.1) {
COCKPIT_ZOOM_DEFAULT = val;
options::OptionsManager::instance()->setOverride("Graphics.CockpitFOV",
std::unique_ptr<json_t>(json_real(val)), "-fov_cockpit");
}
else {
COCKPIT_ZOOM_DEFAULT = VIEWER_ZOOM_DEFAULT;
@@ -2015,18 +1947,13 @@ bool SetCmdlineParams()
Cmdline_fullscreen_window = false;
Cmdline_window = true; /* Make sure no-one sets both */
// These replace the removeWindowModeOption()/removeVSyncOption() calls that used to hide these two
// options in VR. An override keeps them visible but disabled in the options menu, with the tooltip
// naming -vr as the reason, which tells the player more than the control simply not being there.
options::OptionsManager::instance()->setOverride("Graphics.WindowMode",
std::unique_ptr<json_t>(json_integer(static_cast<int>(os::ViewportState::Windowed))), "-vr");
removeWindowModeOption();
// Turn off VSync, since we definitely don't want to be capped by the main monitor
// the OpenXR runtime should have a buffered wait which will behave, effectively,
// as a VSync to VR goggle driver
Gr_enable_vsync = false;
options::OptionsManager::instance()->setOverride("Graphics.VSync",
std::unique_ptr<json_t>(json_false()), "-vr");
removeVSyncOption();
openxr_prepare();
}
@@ -2081,8 +2008,6 @@ bool SetCmdlineParams()
if(no_vsync_arg.found() )
{
Gr_enable_vsync = false;
options::OptionsManager::instance()->setOverride("Graphics.VSync",
std::unique_ptr<json_t>(json_false()), "-no_vsync");
}
if ( normal_arg.found() ) {
@@ -2116,15 +2041,11 @@ bool SetCmdlineParams()
case 5:
Gr_aa_mode = AntiAliasMode::SMAA_High;
break;
case 6:
case 6:
Gr_aa_mode = AntiAliasMode::SMAA_Ultra;
break;
}
}
options::OptionsManager::instance()->setOverride("Graphics.AAMode",
std::unique_ptr<json_t>(json_integer(static_cast<int>(Gr_aa_mode))),
post_process_aa_preset_arg.found() ? "-aa_preset" : "-aa");
}
if (msaa_enabled_arg.found()) {
@@ -2140,9 +2061,6 @@ bool SetCmdlineParams()
Cmdline_msaa_enabled = 0;
break;
}
options::OptionsManager::instance()->setOverride("Graphics.MSAASamples",
std::unique_ptr<json_t>(json_integer(Cmdline_msaa_enabled)), "-msaa");
}
if ( glow_arg.found() )
@@ -2268,8 +2186,6 @@ bool SetCmdlineParams()
if ( softparticles_arg.found() )
{
Cmdline_softparticles = 1;
options::OptionsManager::instance()->setOverride("Graphics.SoftParticles",
std::unique_ptr<json_t>(json_true()), "-soft_particles");
}
if ( fb_explosions_arg.found() )
@@ -2277,31 +2193,14 @@ bool SetCmdlineParams()
Gr_framebuffer_effects.set(FramebufferEffects::Shockwaves, true);
}
if (fb_thrusters_arg.found())
if (fb_thrusters_arg.found())
{
Gr_framebuffer_effects.set(FramebufferEffects::Thrusters, true);
}
if (fb_explosions_arg.found() || fb_thrusters_arg.found()) {
SCP_string reason;
if (fb_explosions_arg.found()) {
reason = "-fb_explosions";
}
if (fb_thrusters_arg.found()) {
if (!reason.empty()) {
reason += " ";
}
reason += "-fb_thrusters";
}
options::OptionsManager::instance()->setOverride("Graphics.FramebufferEffects",
std::unique_ptr<json_t>(json_integer(static_cast<json_int_t>(Gr_framebuffer_effects.to_u64()))), reason);
}
if ( no_postprocess_arg.found() )
{
Gr_post_processing_enabled = false;
options::OptionsManager::instance()->setOverride("Graphics.PostProcessing",
std::unique_ptr<json_t>(json_false()), "-no_post_process");
}
if( reparse_mainhall_arg.found() )
@@ -2315,19 +2214,12 @@ bool SetCmdlineParams()
Shadow_quality_uses_mod_option = true;
Shadow_quality = ShadowQuality::Medium;
// Deliberately not calling setOverride() here: mod_table_init() (which runs after cmdline parsing but
// before OptionsManager::loadInitialValues()) may still adjust Shadow_quality via game_settings.tbl's
// "$Shadow Quality Default:" when Shadow_quality_uses_mod_option is set, and an override registered now
// would freeze in the Medium fallback and ignore that later adjustment. Graphics.Shadows' default_func
// reads Shadow_quality instead, so this value reaches the in-game options path that way, and the
// player keeps the ability to change it.
}
if( shadow_quality_arg.found() )
{
// set that we are not using default shadow quality level --wookieejedi
Shadow_quality_uses_mod_option = false;
Shadow_quality_uses_mod_option = false;
switch (shadow_quality_arg.get_int()) {
case 0:
@@ -2350,47 +2242,21 @@ bool SetCmdlineParams()
Shadow_quality = ShadowQuality::Disabled;
break;
}
// Unlike `-enable_shadows` alone, an explicit quality level is an unambiguous hard override that
// nothing else (mod defaults included) should be able to silently override.
options::OptionsManager::instance()->setOverride("Graphics.Shadows",
std::unique_ptr<json_t>(json_integer(static_cast<int>(Shadow_quality))), "-shadow_quality");
}
if( rt_shadows_arg.found() )
{
// Equivalent to picking "Raytraced" in the Shadow Method option. Silently
// has no effect if the renderer/hardware doesn't support
// CAPABILITY_RAYTRACED_SHADOWS -- the CSM path is used either way.
Shadow_render_method = ShadowRenderMethod::Raytraced;
// No need to gate this on shadows_raytracing_supported(): that answer is only meaningful after
// gr_init(), which runs later, and shadows_remove_unsupported_options() then removes this option
// altogether on hardware that cannot raytrace, so the override never reaches the options menu there.
options::OptionsManager::instance()->setOverride("Graphics.ShadowRenderMethod",
std::unique_ptr<json_t>(json_integer(static_cast<int>(ShadowRenderMethod::Raytraced))), "-rt_shadows");
}
if( no_deferred_lighting_arg.found() )
{
Cmdline_no_deferred_lighting = 1;
options::OptionsManager::instance()->setOverride("Graphics.DeferredLighting",
std::unique_ptr<json_t>(json_false()), "-no_deferred");
}
if( deferred_lighting_cockpit_arg.found() )
{
Cmdline_deferred_lighting_cockpit = true;
options::OptionsManager::instance()->setOverride("Graphics.DeferredCockpitLighting",
std::unique_ptr<json_t>(json_true()), "-deferred_cockpit");
}
if (anisotropy_level_arg.found())
if (anisotropy_level_arg.found())
{
Cmdline_aniso_level = anisotropy_level_arg.get_int();
options::OptionsManager::instance()->setOverride("Graphics.Anisotropy",
std::unique_ptr<json_t>(json_real(static_cast<double>(Cmdline_aniso_level))), "-anisotropic_filter");
}
if (frame_profile_write_file.found())
@@ -2441,16 +2307,6 @@ bool SetCmdlineParams()
Cmdline_graphics_debug_output = true;
}
if (gr_sync_validation_arg.found()) {
// Enables the Vulkan validation layer + debug messenger + synchronization
// validation feature (see VulkanRenderer::initializeInstance), but NOT the
// engine-level graphics debug output: -gr_debug additionally draws debug
// overlays (e.g. output_uniform_debug_data), which are unrelated to GPU
// sync validation and would otherwise appear as spurious on-screen
// artifacts. Keep this a pure GPU-validation switch.
Cmdline_gr_sync_validation = true;
}
if (log_to_stdout_arg.found()) {
Cmdline_log_to_stdout = true;
}
@@ -2476,14 +2332,7 @@ bool SetCmdlineParams()
}
if (vulkan.found()) {
Cmdline_graphics_api = GraphicsAPI::Vulkan;
options::OptionsManager::instance()->setOverride("Graphics.RenderAPI",
std::unique_ptr<json_t>(json_integer(static_cast<int>(GraphicsAPI::Vulkan))), "-vulkan");
}
else if (opengl.found()) {
Cmdline_graphics_api = GraphicsAPI::OpenGL;
options::OptionsManager::instance()->setOverride("Graphics.RenderAPI",
std::unique_ptr<json_t>(json_integer(static_cast<int>(GraphicsAPI::OpenGL))), "-opengl");
Cmdline_vulkan = true;
}
//Deprecated flags - CommanderDJ
+3 -3
View File
@@ -13,7 +13,6 @@
#define FS_CMDLINE_HEADER_FILE
#include <optional>
#include "graphics/2d.h"
int parse_cmdline(int argc, char *argv[]);
@@ -154,18 +153,19 @@ extern bool Cmdline_frame_profile;
extern bool Cmdline_show_video_info;
extern bool Cmdline_debug_window;
extern bool Cmdline_graphics_debug_output;
extern bool Cmdline_gr_sync_validation;
extern bool Cmdline_log_to_stdout;
extern bool Cmdline_slow_frames_ok;
extern bool Cmdline_lua_devmode;
extern bool Cmdline_override_data;
extern bool Cmdline_show_imgui_debug;
extern GraphicsAPI Cmdline_graphics_api;
extern bool Cmdline_vulkan;
extern int Cmdline_multithreading;
enum class WeaponSpewType { NONE = 0, STANDARD, ALL };
extern WeaponSpewType Cmdline_spew_weapon_stats;
extern void removeVSyncOption();
extern void removeWindowModeOption();
extern void removeResolutionOption();
extern void removeResolutionVROption();
+12 -26
View File
@@ -25,33 +25,18 @@ const float CMEASURE_DETONATE_DISTANCE = 40.0f;
//Used to set a countermeasure velocity after being launched from a ship as a countermeasure
//ie not as a primary or secondary.
void cmeasure_set_ship_launch_vel(object* objp, object* parent_objp, int arand)
void cmeasure_set_ship_launch_vel(object *objp, object *parent_objp, int arand)
{
vec3d vel;
vec3d rand_vec;
vec3d world_dir;
vec3d vel, rand_vec;
weapon* wp = &Weapons[objp->instance];
auto* wip = &Weapon_info[wp->weapon_info_index];
//Get cmeasure rear velocity in world
vm_vec_scale_add(&vel, &parent_objp->phys_info.vel, &parent_objp->orient.vec.fvec, -25.0f);
// Start with parent velocity
vel = parent_objp->phys_info.vel;
//Get random velocity vector
static_randvec(arand+1, &rand_vec);
// Normalize direction
vec3d local_dir = wip->cm_launch_vec;
if (vm_vec_mag_squared(&local_dir) > 0.0f) {
vm_vec_normalize(&local_dir);
}
// Convert from ship to world space
vm_vec_unrotate(&world_dir, &local_dir, &parent_objp->orient);
// Apply launch impulse
vm_vec_scale_add2(&vel, &world_dir, wip->cm_launch_speed);
// Add random variance
static_randvec(arand + 1, &rand_vec);
vm_vec_scale_add2(&vel, &rand_vec, wip->cm_launch_variance);
//Add it to the rear velocity
vm_vec_scale_add2(&vel, &rand_vec, 2.0f);
objp->phys_info.vel = vel;
@@ -59,16 +44,17 @@ void cmeasure_set_ship_launch_vel(object* objp, object* parent_objp, int arand)
vm_vec_zero(&objp->phys_info.rotvel);
vm_vec_zero(&objp->phys_info.max_vel);
vm_vec_zero(&objp->phys_info.max_rotvel);
// blow out his reverse thrusters. Or drag, same thing.
objp->phys_info.rotdamp = 10000.0f;
objp->phys_info.side_slip_time_const = 10000.0f;
// Desired velocity should align with launch direction, not hardcoded backward
vm_vec_copy_scale(&objp->phys_info.desired_vel, &world_dir, wip->cm_launch_speed);
objp->phys_info.max_vel.xyz.z = -25.0f;
vm_vec_copy_scale(&objp->phys_info.desired_vel, &objp->orient.vec.fvec, objp->phys_info.max_vel.xyz.z );
// if this cmeasure has a single segment trail, let the trail know since we just changed the velocity
// yeah this is hacky but that's what this function gets for CHANGING the velocity on objects with a ""CONSTANT VELOCITY""
weapon* wp = &Weapons[objp->instance];
if (wp->trail_ptr && wp->trail_ptr->single_segment) {
wp->trail_ptr->vel[0] = objp->phys_info.vel;
wp->trail_ptr->vel[1] = objp->phys_info.vel;
+25 -33
View File
@@ -10,7 +10,6 @@
#include "camera/photomode.h"
#include "cfile/cfile.h"
#include "cmdline/cmdline.h"
#include "controlconfig/controlsconfig.h"
@@ -621,11 +620,6 @@ void control_config_conflict_check()
continue;
}
// Skip conflict check between items in different conflict groups
if ((item_i.conflict_groups & item_j.conflict_groups) == 0) {
continue;
}
if (item_i.disabled && (item_i.has_first_conflict(item_j) || item_i.has_second_conflict(item_j))) {
// item_i conflicts with item_j and is disabled. Silently clear item_i
item_i.clear();
@@ -739,7 +733,7 @@ void control_config_bind(int i, const CC_bind &new_bind, selItem order, bool API
Undo_stack stack;
stack.save(Control_config[i].first);
stack.save(Control_config[i].second);
Undo_controls.save_stack(std::move(stack));
Undo_controls.save_stack(stack);
CCB old(Control_config[i]);
@@ -770,7 +764,7 @@ bool control_config_remove_binding(int ctrl, selItem item, bool API_Access)
stack.save(Control_config[ctrl].first);
stack.save(Control_config[ctrl].second);
Undo_controls.save_stack(std::move(stack));
Undo_controls.save_stack(stack);
Control_config[ctrl].first.clear();
Control_config[ctrl].second.clear();
@@ -804,7 +798,7 @@ bool control_config_remove_binding(int ctrl, selItem item, bool API_Access)
default:
// Coder forgot to add a case!
UNREACHABLE("Unhandled selItem case: %i", static_cast<int>(item));
UNREACHABLE("Unhandled selItem case.");
}
if (success)
@@ -873,7 +867,7 @@ bool control_config_clear_other(int ctrl, bool API_Access)
return false;
}
Undo_controls.save_stack(std::move(stack));
Undo_controls.save_stack(stack);
control_config_conflict_check();
if (!API_Access) {
@@ -911,7 +905,7 @@ bool control_config_clear_all(bool API_Access)
return false;
}
Undo_controls.save_stack(std::move(stack));
Undo_controls.save_stack(stack);
control_config_conflict_check();
if (!API_Access) {
@@ -975,7 +969,7 @@ bool control_config_do_reset(bool cycle, bool API_Access)
stack.save(item.first);
stack.save(item.second);
}
Undo_controls.save_stack(std::move(stack));
Undo_controls.save_stack(stack);
control_config_use_preset(Control_config_presets[Defaults_cycle_pos]);
@@ -1097,7 +1091,7 @@ bool control_config_toggle_modifier(int bit, int ctrl, bool API_Access)
Undo_stack stack;
stack.save(Control_config[ctrl].first);
stack.save(Control_config[ctrl].second);
Undo_controls.save_stack(std::move(stack));
Undo_controls.save_stack(stack);
Control_config[ctrl].take(CC_bind(CID_KEYBOARD, static_cast<short>(k ^ bit)), -1);
control_config_conflict_check();
@@ -1322,7 +1316,7 @@ bool control_config_accept(bool API_Access)
// Check if a hardcoded preset with name already exists. If so, complain to user and force retry
auto it = std::find_if(Control_config_presets.begin(), Control_config_presets.end(), [str](CC_preset& p) {
return ((p.name == str) && ((p.get_type() == Preset_t::tbl) || (p.get_type() == Preset_t::hardcode)));
return ((p.name == str) && ((p.type == Preset_t::tbl) || (p.type == Preset_t::hardcode)));
});
if (it != Control_config_presets.end()) {
@@ -1353,14 +1347,15 @@ bool control_config_accept(bool API_Access)
}
// Pack the current bindings into a preset, then save the file
CC_preset preset(std::move(str), Preset_t::pst);
CC_preset preset;
preset.name = std::move(str);
std::copy(Control_config.begin(), Control_config.end(), std::back_inserter(preset.bindings));
Control_config_presets.push_back(preset);
save_preset_file(preset, true);
// Reload the presets from file. Do this instead of just pushing the preset to the vector direct to get
// consistant ordering
Control_config_presets.erase(Control_config_presets.begin() + 1, Control_config_presets.end());
Control_config_presets.resize(1);
load_preset_files();
// finally, save the new preset so that changes will get saved to this preset
@@ -1777,7 +1772,7 @@ bool control_config_create_new_preset(const SCP_string& newName, bool overwrite)
// Check if a hardcoded preset with name already exists. If so, complain to user and force retry
auto it = std::find_if(Control_config_presets.begin(), Control_config_presets.end(), [newName](CC_preset& p) {
return (p.name == newName) && ((p.get_type() == Preset_t::tbl) || (p.get_type() == Preset_t::hardcode));
return (p.name == newName) && ((p.type == Preset_t::tbl) || (p.type == Preset_t::hardcode));
});
if (it != Control_config_presets.end()) {
@@ -1790,7 +1785,9 @@ bool control_config_create_new_preset(const SCP_string& newName, bool overwrite)
}
// Pack the current bindings into a preset, then save the file
CC_preset preset(newName, Preset_t::pst);
CC_preset preset;
preset.name = newName;
preset.type = Preset_t::pst;
std::copy(Control_config.begin(), Control_config.end(), std::back_inserter(preset.bindings));
// Done with the file
@@ -1802,7 +1799,7 @@ bool control_config_create_new_preset(const SCP_string& newName, bool overwrite)
save_preset_file(preset, true);
// Reload the presets from file.
Control_config_presets.erase(Control_config_presets.begin() + 1, Control_config_presets.end());
Control_config_presets.resize(1);
load_preset_files(newName);
// use the newly created preset
@@ -1810,9 +1807,10 @@ bool control_config_create_new_preset(const SCP_string& newName, bool overwrite)
return true;
} else if ((clone->name != preset.name) || (clone->get_type() != Preset_t::pst)) {
} else if ((clone->name != preset.name) || (clone->type != Preset_t::pst)) {
// Complain and ignore if the preset names or the type differs
return false;
}
return false; //should be unreachable, but just in case
@@ -1822,7 +1820,7 @@ bool control_config_clone_preset(const CC_preset& preset, const SCP_string& newN
// Check if a hardcoded preset with name already exists. If so, complain to user and force retry
auto it = std::find_if(Control_config_presets.begin(), Control_config_presets.end(), [newName](CC_preset& p) {
return (p.name == newName) && ((p.get_type() == Preset_t::tbl) || (p.get_type() == Preset_t::hardcode));
return (p.name == newName) && ((p.type == Preset_t::tbl) || (p.type == Preset_t::hardcode));
});
if (it != Control_config_presets.end()) {
@@ -1834,13 +1832,13 @@ bool control_config_clone_preset(const CC_preset& preset, const SCP_string& newN
return false;
}
CC_preset newPreset(newName, Preset_t::pst);
newPreset.bindings = preset.bindings;
CC_preset newPreset = preset;
newPreset.name = newName;
bool success = save_preset_file(newPreset, false);
// Reload the presets from file.
Control_config_presets.erase(Control_config_presets.begin() + 1, Control_config_presets.end());
Control_config_presets.resize(1);
load_preset_files(newName);
// use the newly cloned preset
@@ -2720,7 +2718,8 @@ void control_config_do_frame(float frametime)
strcpy_s(buf, Control_config[i].text.c_str());
}
w = font::force_fit_string(buf, 255, Conflict_wnd_coords[gr_screen.res][CONTROL_W_COORD]);
font::force_fit_string(buf, 255, Conflict_wnd_coords[gr_screen.res][CONTROL_W_COORD]);
gr_get_string_size(&w, NULL, buf);
gr_printf_menu(x - w / 2, y, "%s", buf);
} else if (*bound_string) {
@@ -2838,13 +2837,6 @@ int check_control_used(int id, int key)
if (item.disabled || item.locked)
return 0;
// Filter actions based on conflict groups and current mode
{
int active_group = game_is_photo_mode_active() ? CONFLICT_GROUP_PHOTO_MODE : CONFLICT_GROUP_DEFAULT;
if (!(item.conflict_groups & active_group))
return 0;
}
short z = item.get_btn(CID_KEYBOARD); // Get the key that's bound to this control
if (item.type == CC_TYPE_CONTINUOUS) {
@@ -3116,7 +3108,7 @@ void control_get_axes_readings(int *axis_v, float frame_time)
case CC_TYPE_AXIS_BTN_POS:
default:
//This should never happen, especially with the above Assertion. This is required as incomplete switches on an enum generate warnings
UNREACHABLE("Unhandled control item type %d", static_cast<int>(item.type));
UNREACHABLE("Unhandled control item type");
break;
}
}
+11 -31
View File
@@ -308,13 +308,6 @@ enum IoActionId : int {
CYCLE_PRIMARY_WEAPON_PATTERN,
TOGGLE_PHOTO_MODE,
PHOTO_MODE_FILTER_PREV,
PHOTO_MODE_FILTER_NEXT,
PHOTO_MODE_FILTER_RESET,
PHOTO_MODE_PARAM_DECREASE,
PHOTO_MODE_PARAM_INCREASE,
/*!
* This must always be below the last defined item
*/
@@ -572,38 +565,26 @@ public:
* A preset, a collection of bindings for use in Control_config with an associated name
*/
class CC_preset {
public:
public:
SCP_vector<CCB> bindings;
SCP_string name;
Preset_t type = Preset_t::hardcode;
private:
// No default value: the type is always set explicitly by the constructor
Preset_t type;
public:
CC_preset() = default;
CC_preset(const CC_preset& A) = default;
public:
// No default constructor: every preset must be created with an explicit type
CC_preset(SCP_string preset_name, Preset_t preset_type) : name(std::move(preset_name)), type(preset_type) {}
CC_preset(const CC_preset&) = default;
// Preserve target's preset type during copy assignment
CC_preset& operator=(const CC_preset& other);
Preset_t get_type() const
{
return type;
}
bool is_duplicate_of(const CC_preset& other) const;
CC_preset& operator=(const CC_preset&);
/*!
* Checks if the given preset is a duplicate of this one
*/
bool is_duplicate_of(CC_preset&);
};
/*!
* Control configuration item type.
* @detail Contains binding info, documentation, behavior, etc. for a single control
*/
// Conflict group bitmasks. Bindings only conflict if their groups overlap (bitwise AND != 0).
static const int CONFLICT_GROUP_DEFAULT = (1 << 0); //!< Standard gameplay bindings
static const int CONFLICT_GROUP_PHOTO_MODE = (1 << 1); //!< Bindings used within photo mode
class CCI : public CCB {
public:
// Inherited from CCB
@@ -612,7 +593,6 @@ public:
// Items Set in menu
char tab; //!< what tab (category) it belongs in
int conflict_groups = CONFLICT_GROUP_DEFAULT; //!< Bitmask of conflict groups. Bindings only conflict with others sharing at least one group.
int indexXSTR; //!< what string index we should use to translate this with an XSTR 0 = None, 1= Use item index + CONTROL_CONFIG_XSTR, 2 <= use CCI::indexXSTR directly
SCP_string text; //!< describes the action in the config screen
@@ -685,7 +665,7 @@ public:
* If the type is CC_TYPE_TRIGGER or CC_TYPE_CONTINOUS, the primary is assumed to be a key combo and secondary is assumed to be a joy button.
* If the type is CC_TYPE_AXIS_ABS, CC_TYPE_AXIS_REL, CC_TYPE_AXIS_BTN_POS, or CC_TYPE_AXIS_BTN_NEG, the primary is a Joy0 axis and the secondary is a Mouse axis
*/
CCI_builder& operator()(IoActionId action_id, short primary, short secondary, char tab, int indexXSTR, const char *text, CC_type type, bool disabled = false, int conflict_groups = CONFLICT_GROUP_DEFAULT);
CCI_builder& operator()(IoActionId action_id, short primary, short secondary, char tab, int indexXSTR, const char *text, CC_type type, bool disabled = false);
private:
CCI_builder(); // Only one builder per Control Config, so a default constructor is useless
+46 -103
View File
@@ -45,7 +45,6 @@ int Failed_key_index;
// Joystick configuration
int Joy_dead_zone_size = 10;
// coverity[GLOBAL_INIT_ORDER] -- safe; OptionBuilder::finish() uses Meyers singleton
auto DeadZoneOption = options::OptionBuilder<int>("Input.JoystickDeadZone",
std::pair<const char*, int>{"Deadzone", 1377},
std::pair<const char*, int>{"The deadzone used for all joysticks", 1744})
@@ -60,7 +59,6 @@ auto DeadZoneOption = options::OptionBuilder<int>("Input.JoystickDeadZone",
int Joy_sensitivity = 9;
// coverity[GLOBAL_INIT_ORDER] -- safe; OptionBuilder::finish() uses Meyers singleton
auto SensitivityOption = options::OptionBuilder<int>("Input.JoystickSensitivity",
std::pair<const char*, int>{"Sensitivity", 1745},
std::pair<const char*, int>{"The sensitivity used for all joysticks", 1746})
@@ -138,12 +136,12 @@ void control_config_common_init_bindings() {
(TARGET_PREV_BOMB, KEY_SHIFTED | KEY_B, -1, TARGET_TAB, 1, "Target Previous Hostile Bomb or Bomber", CC_TYPE_TRIGGER)
// flight controls (Rotation)
(BANK_LEFT, KEY_PAD7, -1, SHIP_TAB, 1, "Bank Left", CC_TYPE_CONTINUOUS, false, CONFLICT_GROUP_DEFAULT | CONFLICT_GROUP_PHOTO_MODE)
(BANK_RIGHT, KEY_PAD9, -1, SHIP_TAB, 1, "Bank Right", CC_TYPE_CONTINUOUS, false, CONFLICT_GROUP_DEFAULT | CONFLICT_GROUP_PHOTO_MODE)
(PITCH_FORWARD, KEY_PAD8, -1, SHIP_TAB, 1, "Pitch Forward", CC_TYPE_CONTINUOUS, false, CONFLICT_GROUP_DEFAULT | CONFLICT_GROUP_PHOTO_MODE)
(PITCH_BACK, KEY_PAD2, -1, SHIP_TAB, 1, "Pitch Backward", CC_TYPE_CONTINUOUS, false, CONFLICT_GROUP_DEFAULT | CONFLICT_GROUP_PHOTO_MODE)
(YAW_LEFT, KEY_PAD4, -1, SHIP_TAB, 1, "Yaw Left", CC_TYPE_CONTINUOUS, false, CONFLICT_GROUP_DEFAULT | CONFLICT_GROUP_PHOTO_MODE)
(YAW_RIGHT, KEY_PAD6, -1, SHIP_TAB, 1, "Yaw Right", CC_TYPE_CONTINUOUS, false, CONFLICT_GROUP_DEFAULT | CONFLICT_GROUP_PHOTO_MODE)
(BANK_LEFT, KEY_PAD7, -1, SHIP_TAB, 1, "Bank Left", CC_TYPE_CONTINUOUS)
(BANK_RIGHT, KEY_PAD9, -1, SHIP_TAB, 1, "Bank Right", CC_TYPE_CONTINUOUS)
(PITCH_FORWARD, KEY_PAD8, -1, SHIP_TAB, 1, "Pitch Forward", CC_TYPE_CONTINUOUS)
(PITCH_BACK, KEY_PAD2, -1, SHIP_TAB, 1, "Pitch Backward", CC_TYPE_CONTINUOUS)
(YAW_LEFT, KEY_PAD4, -1, SHIP_TAB, 1, "Yaw Left", CC_TYPE_CONTINUOUS)
(YAW_RIGHT, KEY_PAD6, -1, SHIP_TAB, 1, "Yaw Right", CC_TYPE_CONTINUOUS)
// flight controls (Throttle)
(ZERO_THROTTLE, KEY_BACKSP, -1, SHIP_TAB, 1, "Set Throttle to Zero", CC_TYPE_TRIGGER)
@@ -154,16 +152,16 @@ void control_config_common_init_bindings() {
(MINUS_5_PERCENT_THROTTLE, KEY_MINUS, -1, SHIP_TAB, 1, "Decrease Throttle 5 Percent", CC_TYPE_TRIGGER)
// flight controls (Thrust)
(FORWARD_THRUST, KEY_A, -1, SHIP_TAB, 1, "Forward Thrust", CC_TYPE_CONTINUOUS, false, CONFLICT_GROUP_DEFAULT | CONFLICT_GROUP_PHOTO_MODE)
(REVERSE_THRUST, KEY_Z, -1, SHIP_TAB, 1, "Reverse Thrust", CC_TYPE_CONTINUOUS, false, CONFLICT_GROUP_DEFAULT | CONFLICT_GROUP_PHOTO_MODE)
(RIGHT_SLIDE_THRUST, KEY_SHIFTED | KEY_3, -1, SHIP_TAB, 1, "Right Thrust", CC_TYPE_CONTINUOUS, false, CONFLICT_GROUP_DEFAULT | CONFLICT_GROUP_PHOTO_MODE)
(LEFT_SLIDE_THRUST, KEY_SHIFTED | KEY_1, -1, SHIP_TAB, 1, "Left Thrust", CC_TYPE_CONTINUOUS, false, CONFLICT_GROUP_DEFAULT | CONFLICT_GROUP_PHOTO_MODE)
(UP_SLIDE_THRUST, KEY_SHIFTED | KEY_PADPLUS, -1, SHIP_TAB, 1, "Up Thrust", CC_TYPE_CONTINUOUS, false, CONFLICT_GROUP_DEFAULT | CONFLICT_GROUP_PHOTO_MODE)
(DOWN_SLIDE_THRUST, KEY_SHIFTED | KEY_PADENTER, -1, SHIP_TAB, 1, "Down Thrust", CC_TYPE_CONTINUOUS, false, CONFLICT_GROUP_DEFAULT | CONFLICT_GROUP_PHOTO_MODE)
(FORWARD_THRUST, KEY_A, -1, SHIP_TAB, 1, "Forward Thrust", CC_TYPE_CONTINUOUS)
(REVERSE_THRUST, KEY_Z, -1, SHIP_TAB, 1, "Reverse Thrust", CC_TYPE_CONTINUOUS)
(RIGHT_SLIDE_THRUST, KEY_SHIFTED | KEY_3, -1, SHIP_TAB, 1, "Right Thrust", CC_TYPE_CONTINUOUS)
(LEFT_SLIDE_THRUST, KEY_SHIFTED | KEY_1, -1, SHIP_TAB, 1, "Left Thrust", CC_TYPE_CONTINUOUS)
(UP_SLIDE_THRUST, KEY_SHIFTED | KEY_PADPLUS, -1, SHIP_TAB, 1, "Up Thrust", CC_TYPE_CONTINUOUS)
(DOWN_SLIDE_THRUST, KEY_SHIFTED | KEY_PADENTER, -1, SHIP_TAB, 1, "Down Thrust", CC_TYPE_CONTINUOUS)
// flight controls (flight modes)
(BANK_WHEN_PRESSED, -1, -1, SHIP_TAB, 1, "Bank When Pressed", CC_TYPE_CONTINUOUS)
(AFTERBURNER, KEY_TAB, 5, SHIP_TAB, 1, "Afterburner", CC_TYPE_CONTINUOUS, false, CONFLICT_GROUP_DEFAULT | CONFLICT_GROUP_PHOTO_MODE)
(AFTERBURNER, KEY_TAB, 5, SHIP_TAB, 1, "Afterburner", CC_TYPE_CONTINUOUS)
(GLIDE_WHEN_PRESSED, -1, -1, SHIP_TAB, 1774, "Glide When Pressed", CC_TYPE_CONTINUOUS)
(TOGGLE_GLIDING, KEY_ALTED | KEY_G, -1, SHIP_TAB, 1775, "Toggle Gliding", CC_TYPE_TRIGGER)
@@ -267,12 +265,6 @@ void control_config_common_init_bindings() {
(TOGGLE_HUD_CONTRAST, KEY_L, -1, COMPUTER_TAB, 1, "Toggle High HUD Contrast", CC_TYPE_TRIGGER)
(TOGGLE_HUD_SHADOWS, KEY_ALTED | KEY_L, -1, COMPUTER_TAB, 1781, "Toggle HUD Drop Shadows", CC_TYPE_TRIGGER)
(HUD_TARGETBOX_TOGGLE_WIREFRAME, KEY_ALTED | KEY_SHIFTED | KEY_Q, -1, COMPUTER_TAB, 1, "Toggle HUD Wireframe Target View", CC_TYPE_TRIGGER)
(TOGGLE_PHOTO_MODE, KEY_ALTED | KEY_1, -1, COMPUTER_TAB, 1908, "Toggle Photo Mode", CC_TYPE_TRIGGER, false, CONFLICT_GROUP_DEFAULT | CONFLICT_GROUP_PHOTO_MODE)
(PHOTO_MODE_FILTER_PREV, KEY_UP, -1, COMPUTER_TAB, 1909, "Photo Mode Previous Parameter", CC_TYPE_TRIGGER, false, CONFLICT_GROUP_PHOTO_MODE)
(PHOTO_MODE_FILTER_NEXT, KEY_DOWN, -1, COMPUTER_TAB, 1910, "Photo Mode Next Parameter", CC_TYPE_TRIGGER, false, CONFLICT_GROUP_PHOTO_MODE)
(PHOTO_MODE_FILTER_RESET, KEY_ALTED | KEY_2, -1, COMPUTER_TAB, 1911, "Photo Mode Reset Parameters", CC_TYPE_TRIGGER, false, CONFLICT_GROUP_PHOTO_MODE)
(PHOTO_MODE_PARAM_DECREASE, KEY_LEFT, -1, COMPUTER_TAB, 1912, "Photo Mode Decrease Selected Parameter", CC_TYPE_TRIGGER, false, CONFLICT_GROUP_PHOTO_MODE)
(PHOTO_MODE_PARAM_INCREASE, KEY_RIGHT, -1, COMPUTER_TAB, 1913, "Photo Mode Increase Selected Parameter", CC_TYPE_TRIGGER, false, CONFLICT_GROUP_PHOTO_MODE)
// Custom Controls
(CUSTOM_CONTROL_1, KEY_ALTED | KEY_SHIFTED | KEY_1, -1, COMPUTER_TAB, 1784, "Custom Control 1", CC_TYPE_TRIGGER, true)
@@ -292,8 +284,10 @@ void control_config_common_init_bindings() {
// init default preset
Control_config_presets.clear();
CC_preset preset("default", Preset_t::hardcode);
CC_preset preset;
preset.bindings.reserve(Control_config.size());
preset.name = "default";
preset.type = Preset_t::hardcode;
for (auto &item : Control_config) {
preset.bindings.push_back(CCB(item));
@@ -438,12 +432,6 @@ SCP_unordered_map<SCP_string, IoActionId> old_text = {
{"Up Thrust", UP_SLIDE_THRUST},
{"Down Thrust", DOWN_SLIDE_THRUST},
{"Toggle HUD Wireframe Target View", HUD_TARGETBOX_TOGGLE_WIREFRAME},
{"Toggle Photo Mode", TOGGLE_PHOTO_MODE},
{"Photo Mode Previous Parameter", PHOTO_MODE_FILTER_PREV},
{"Photo Mode Next Parameter", PHOTO_MODE_FILTER_NEXT},
{"Photo Mode Reset Parameters", PHOTO_MODE_FILTER_RESET},
{"Photo Mode Decrease Selected Parameter", PHOTO_MODE_PARAM_DECREASE},
{"Photo Mode Increase Selected Parameter", PHOTO_MODE_PARAM_INCREASE},
{"Top-Down View", VIEW_TOPDOWN},
{"Target Padlock View", VIEW_TRACK_TARGET},
@@ -680,7 +668,7 @@ const char *textify_scancode(int code)
}
SCP_string name;
unicode::convert_encoding(name, SDL_GetKeyName(SDL_GetKeyFromScancode(fs2_to_sdl(keycode), SDL_KMOD_NONE, false)), unicode::Encoding::Encoding_utf8);
unicode::convert_encoding(name, SDL_GetKeyName(SDL_GetKeyFromScancode(fs2_to_sdl(keycode))), unicode::Encoding::Encoding_utf8);
strcat_s(text, name.c_str());
return text;
}
@@ -1163,12 +1151,6 @@ void LoadEnumsIntoActionMap() {
ADD_ENUM_TO_ACTION_MAP(UP_SLIDE_THRUST)
ADD_ENUM_TO_ACTION_MAP(DOWN_SLIDE_THRUST)
ADD_ENUM_TO_ACTION_MAP(HUD_TARGETBOX_TOGGLE_WIREFRAME)
ADD_ENUM_TO_ACTION_MAP(TOGGLE_PHOTO_MODE)
ADD_ENUM_TO_ACTION_MAP(PHOTO_MODE_FILTER_PREV)
ADD_ENUM_TO_ACTION_MAP(PHOTO_MODE_FILTER_NEXT)
ADD_ENUM_TO_ACTION_MAP(PHOTO_MODE_FILTER_RESET)
ADD_ENUM_TO_ACTION_MAP(PHOTO_MODE_PARAM_DECREASE)
ADD_ENUM_TO_ACTION_MAP(PHOTO_MODE_PARAM_INCREASE)
ADD_ENUM_TO_ACTION_MAP(VIEW_TOPDOWN)
ADD_ENUM_TO_ACTION_MAP(VIEW_TRACK_TARGET)
@@ -1731,13 +1713,14 @@ size_t read_bind_1(CC_preset &preset) {
*/
void control_config_common_read_section(int s, bool first_override) {
Assertion((s == 0) || (s == 1), "Expected value of s to be either 0 or 1, found %i instead.", s);
CC_preset new_preset("", Preset_t::tbl);
CC_preset new_preset;
// Set references to the default preset and bindings
auto& default_preset = Control_config_presets[0];
auto& default_bindings = default_preset.bindings;
new_preset.bindings.clear();
new_preset.type = Preset_t::tbl;
if (s == 0) {
// #ControlConfigOverride
@@ -2385,7 +2368,7 @@ SCP_string ValToCID(CID id) {
if (it == mCIDNameToVal.cend()) {
// Shouldn't happen
UNREACHABLE("Unknown CID value %i", id);
Error(LOCATION, "Unknown CID value %i", id);
return "NONE";
} else {
@@ -2515,11 +2498,9 @@ SCP_string ValToJoy(const CC_bind &bind) {
if (it == mAxisNameToVal.end()) {
// should never happen
UNREACHABLE("Unknown error occured during reverse lookup of joy input string.");
str = "NONE";
} else {
// print out value
str = it->first;
}
} // else print out value
str = it->first;
/* } else if (bind.flags & CCF_HAT) {
// TODO Still currently encoded as buttons
@@ -2608,51 +2589,25 @@ void CC_bind::invert_toggle() {
flags ^= CCF_INVERTED;
}
static bool compare_btn(short cid, const CC_bind& A, char& A_flags, const CC_bind& B, char& B_flags)
{
auto A_btn = A.get_btn();
auto B_btn = B.get_btn();
auto current = io::joystick::getPlayerJoystick(cid);
if (current && current->isGamepad()) {
if (A_btn >= SDL_GAMEPAD_BUTTON_COUNT) {
A_btn = (A_btn - SDL_GAMEPAD_BUTTON_COUNT) + SDL_GAMEPAD_AXIS_LEFT_TRIGGER;
A_flags |= CCF_AXIS_BTN;
}
if (B_btn >= SDL_GAMEPAD_BUTTON_COUNT) {
B_btn = (B_btn - SDL_GAMEPAD_BUTTON_COUNT) + SDL_GAMEPAD_AXIS_LEFT_TRIGGER;
B_flags |= CCF_AXIS_BTN;
}
}
return (A_btn == B_btn);
}
bool CC_bind::conflicts_with(const CC_bind& B) const {
char A_flags = flags;
char B_flags = B.flags;
// Bail early if CID or btn are not the same
if ((cid != B.cid) || !compare_btn(cid, *this, A_flags, B, B_flags)) {
if ((cid != B.cid) || (btn != B.btn)) {
return false;
}
// Check if A is an Axis or Axis Button, and if B is an Axis or Axis Button
char mask = (CCF_AXIS_BTN | CCF_AXIS);
if ((A_flags & mask) && (B_flags & mask)) {
if ((flags & mask) && (B.flags & mask)) {
return true;
}
// Check if Hat
if (A_flags & B_flags & CCF_HAT) {
if (flags & B.flags & CCF_HAT) {
return true;
}
// Check if Ball
if (A_flags & B_flags & CCF_BALL) {
if (flags & B.flags & CCF_BALL) {
return true;
}
@@ -2664,7 +2619,7 @@ bool CC_bind::conflicts_with(const CC_bind& B) const {
// First off, check if A or B is NOT a button, as according to the mask. Buttons do not have a flag, so we check
// if they are any of the other input types
// Next, we return the inverse of the result. Negative of a Negative = Positive. Not Not a button = Is a button
return !((A_flags | B_flags) & mask);
return !((flags | B.flags) & mask);
}
bool CC_bind::is_inverted() const {
@@ -2755,19 +2710,10 @@ SCP_string CC_bind::textify() const {
case CID_JOY0:
case CID_JOY1:
case CID_JOY2:
case CID_JOY3: {
auto axis = joy_get_button_axis(cid, btn);
if (axis < 0) {
Assert((btn >= 0) && (btn < JOY_TOTAL_BUTTONS));
retval = SCP_string(textify_button(btn));
} else {
Assert((axis >= 0) && (axis < NUM_AXIS_TEXT));
retval = SCP_string(Axis_text[axis]);
}
case CID_JOY3:
Assert((btn >= 0) && (btn < JOY_TOTAL_BUTTONS));
retval = SCP_string(textify_button(btn));
break;
}
case CID_NONE:
default:
@@ -2872,7 +2818,6 @@ CCI& CCI::operator=(const CCI& A) {
locked = A.locked;
scriptEnabledByDefault = A.scriptEnabledByDefault;
continuous_ongoing = A.continuous_ongoing;
conflict_groups = A.conflict_groups;
return *this;
};
@@ -2955,7 +2900,7 @@ CCI_builder& CCI_builder::start() {
void CCI_builder::end() {};
CCI_builder& CCI_builder::operator()(IoActionId action_id, short primary, short secondary, char tab, int indexXSTR, const char *text, CC_type type, bool disabled, int conflict_groups) {
CCI_builder& CCI_builder::operator()(IoActionId action_id, short primary, short secondary, char tab, int indexXSTR, const char *text, CC_type type, bool disabled) {
Assert(action_id < CCFG_MAX);
CCI& item = ControlConfig[action_id];
@@ -2993,28 +2938,26 @@ CCI_builder& CCI_builder::operator()(IoActionId action_id, short primary, short
item.disabled = false;
}
// Assign the conflict group
item.conflict_groups = conflict_groups;
return *this;
}
CC_preset& CC_preset::operator=(const CC_preset& other)
{
if (this != &other) {
bindings = other.bindings;
name = other.name;
// 'type' is intentionally preserved to maintain instance identity
}
return *this;
}
CC_preset& CC_preset::operator=(const CC_preset& A) {
name = A.name;
type = A.type;
bool CC_preset::is_duplicate_of(const CC_preset& other) const
{
for (size_t i = 0; i < other.bindings.size(); ++i) {
if (bindings[i] != other.bindings[i]) {
std::copy(A.bindings.begin(), A.bindings.end(), bindings.begin());
return *this;
};
bool CC_preset::is_duplicate_of(CC_preset& A) {
for (size_t i = 0; i < A.bindings.size(); ++i) {
if (bindings[i] != A.bindings[i]) {
// Found a binding that's different. Thus, this preset is not a duplicate
return false;
}
}
// Else, did not find any differences in the bindings. Thus, this preset is a duplicate
return true;
}
+5 -3
View File
@@ -74,7 +74,9 @@ void load_preset_files(SCP_string clone) {
// Start reading in data
CC_preset preset(file, Preset_t::pst);
CC_preset preset;
preset.name = file;
preset.type = Preset_t::pst;
preset.bindings.resize(Control_config.size());
size_t size;
@@ -132,7 +134,7 @@ void load_preset_files(SCP_string clone) {
if ((clone == preset.name) || (it == Control_config_presets.end())) {
Control_config_presets.push_back(preset);
} else if ((it->name != preset.name) || ((it->get_type() != Preset_t::pst))) {
} else if ((it->name != preset.name) || (it->type != Preset_t::pst)) {
if (gameseq_get_state() == GS_STATE_CONTROL_CONFIG) {
popup(PF_TITLE_WHITE | PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, "Preset '%s' is a duplicate of an existing preset, ignoring", preset.name.c_str());
} else {
@@ -171,7 +173,7 @@ bool delete_preset_file(CC_preset preset) {
cf_delete(filename.c_str(), CF_TYPE_PLAYER_BINDS, CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT);
// Reload the presets from file.
Control_config_presets.erase(Control_config_presets.begin() + 1, Control_config_presets.end());
Control_config_presets.resize(1);
load_preset_files();
return true;
+3 -3
View File
@@ -49,7 +49,7 @@ VideoPresenter::VideoPresenter(const MovieProperties& props) : _properties(props
material_set_unlit(&_rgb_material, _planeTextureHandles[0], 1.0f, true, false);
break;
default:
UNREACHABLE("Unhandled enum value %d!", static_cast<int>(props.pixelFormat));
UNREACHABLE("Unhandled enum value!");
break;
}
}
@@ -86,7 +86,7 @@ void VideoPresenter::uploadVideoFrame(const VideoFramePtr& frame) {
bpp = 32;
break;
default:
UNREACHABLE("Unhandled enum value %d!", static_cast<int>(_properties.pixelFormat));
UNREACHABLE("Unhandled enum value!");
break;
}
@@ -145,7 +145,7 @@ void VideoPresenter::displayFrame(float x1, float y1, float x2, float y2, float
gr_render_primitives(&_rgb_material, PRIM_TYPE_TRISTRIP, &layout, 0, 4, gr_immediate_buffer_handle, offset);
break;
default:
UNREACHABLE("Unhandled enum value %d!", static_cast<int>(_properties.pixelFormat));
UNREACHABLE("Unhandled enum value!");
break;
}
}
+1 -2
View File
@@ -537,8 +537,7 @@ void cutscenes_screen_init()
int u = 0;
for (auto cut = Cutscenes.begin(); cut != Cutscenes.end(); ++cut, ++u)
{
if ((cut->flags.any_of(Cutscene::Cutscene_Flags::Viewable,Cutscene::Cutscene_Flags::Always_viewable)) &&
!cut->flags[Cutscene::Cutscene_Flags::Never_viewable])
if (cut->flags[Cutscene::Cutscene_Flags::Viewable, Cutscene::Cutscene_Flags::Always_viewable] && !cut->flags[Cutscene::Cutscene_Flags::Never_viewable])
{
Cutscene_list.push_back(u);
}
+4 -4
View File
@@ -14,8 +14,8 @@
#include <windows.h>
#endif
#include "globalincs/pstypes.h"
#include "freespace.h"
#include "globalincs/pstypes.h"
#include "globalincs/alphacolors.h"
#include "globalincs/systemvars.h"
#include "io/cursor.h"
@@ -208,7 +208,7 @@ void movie_display_loop(Player* player, PlaybackState* state) {
auto sleepTime = static_cast<std::uint64_t>((1. / (4. * player->getMovieProperties().fps)) * 1000.);
auto listener = [state](const SDL_Event& event) {
switch (event.key.key) {
switch (event.key.keysym.sym) {
case SDLK_ESCAPE:
case SDLK_KP_ENTER:
case SDLK_RETURN:
@@ -220,7 +220,7 @@ void movie_display_loop(Player* player, PlaybackState* state) {
}
};
// Use a dedicated listener here since we want to listen for the KEYUP event
auto key_handle = os::events::addEventListener(SDL_EVENT_KEY_UP, os::events::DEFAULT_LISTENER_WEIGHT - 10, listener);
auto key_handle = os::events::addEventListener(SDL_KEYUP, os::events::DEFAULT_LISTENER_WEIGHT - 10, listener);
// slight hack to make sure that game_set_frametime() doesn't also try to cap the framerate
auto fpsCapSave = Cmdline_NoFPSCap;
@@ -279,7 +279,7 @@ bool play(const char* filename, bool via_tech_room = false)
{
auto paramList = scripting::hook_param_list(scripting::hook_param("Filename", 's', filename), scripting::hook_param("ViaTechRoom", 'b', via_tech_room));
bool skip = scripting::hooks::OnMovieAboutToPlay->isOverride(paramList);
scripting::hooks::OnMovieAboutToPlay->run(std::move(paramList));
scripting::hooks::OnMovieAboutToPlay->run(paramList);
if (skip)
return false;
}
+1 -3
View File
@@ -4,8 +4,6 @@
#include "cutscene/VideoPresenter.h"
#include "cutscene/ffmpeg/FFMPEGDecoder.h"
#include "cmdline/cmdline.h"
#include "graphics/2d.h"
#include "globalincs/alphacolors.h"
@@ -54,7 +52,7 @@ void videoPlaybackInit(PlayerState* state) {
Assert(state != NULL);
if (gr_screen.mode != GraphicsAPI::Stub) {
if (gr_screen.mode != GR_STUB) {
// The video presenter is independent of the underlying graphics API
state->videoPresenter.reset(new VideoPresenter(state->props));
}
+9 -116
View File
@@ -1,10 +1,13 @@
#include "ddsutils/ddsutils.h"
#include "cfile/cfile.h"
#include "graphics/2d.h"
#include "osapi/osregistry.h"
#ifdef USE_OPENGL_ES
#include "graphics/opengl/es_compatibility.h"
#ifdef WITH_OPENGL
#include <glad/glad.h>
#else
static constexpr int GLAD_GL_EXT_texture_compression_s3tc = 0;
static constexpr int GLAD_GL_ARB_texture_compression_bptc = 0;
#endif
#define BCDEC_IMPLEMENTATION 1
@@ -54,11 +57,11 @@ static bool conversion_needed(const DDS_HEADER &dds_header)
case FOURCC_DXT1:
case FOURCC_DXT3:
case FOURCC_DXT5:
return !gr_is_capable(gr_capability::CAPABILITY_S3TC);
return !GLAD_GL_EXT_texture_compression_s3tc;
case FOURCC_DX10:
// anything other than BC7 will end up invalid
return !gr_is_capable(gr_capability::CAPABILITY_BPTC);
return !GLAD_GL_ARB_texture_compression_bptc;
default:
break;
@@ -220,7 +223,7 @@ static size_t compute_dds_size(const DDS_HEADER &dds_header, bool converting = f
if (dds_header.ddspf.dwFlags & DDPF_FOURCC) {
// size of data block (4x4)
d_size += dds_compressed_mip_size(d_width, d_height, (dds_header.ddspf.dwFourCC == FOURCC_DXT1) ? 8 : 16) * d_depth;
d_size += ((d_width + 3) / 4) * ((d_height + 3) / 4) * d_depth * ((dds_header.ddspf.dwFourCC == FOURCC_DXT1) ? 8 : 16);
} else {
d_size += d_width * d_height * d_depth * (dds_header.ddspf.dwRGBBitCount / 8);
}
@@ -546,116 +549,6 @@ int dds_read_bitmap(const char *filename, ubyte *data, ubyte *bpp, int cf_type)
return DDS_ERROR_NONE;
}
int dds_decompress_top_mip_bgra(const char *filename, int cf_type,
int *out_width, int *out_height,
SCP_vector<ubyte> &out_pixels)
{
Assert(filename != nullptr);
// normalize to a .dds extension, same as dds_read_bitmap
char real_name[MAX_FILENAME_LEN];
strcpy_s(real_name, filename);
char *p = strchr(real_name, '.');
if (p) { *p = 0; }
strcat_s(real_name, ".dds");
CFILE *cfp = cfopen(real_name, "rb", cf_type);
if (cfp == nullptr)
return DDS_ERROR_INVALID_FILENAME;
DDS_HEADER dds_header;
DDS_HEADER_DXT10 dx10_header;
int retval = _dds_read_header(cfp, dds_header, &dx10_header);
if (retval != DDS_ERROR_NONE) {
cfclose(cfp);
return retval;
}
// only 2D FOURCC-compressed images are supported here
if (!(dds_header.ddspf.dwFlags & DDPF_FOURCC) ||
(dds_header.dwCaps2 & (DDSCAPS2_CUBEMAP | DDSCAPS2_VOLUME)) ||
(dds_header.dwFlags & DDSD_DEPTH) ||
(dds_header.dwDepth > 1)) {
cfclose(cfp);
return DDS_ERROR_UNSUPPORTED;
}
void (*decode)(const void *, void *, int) = nullptr;
int block_size = 0;
switch (dds_header.ddspf.dwFourCC) {
case FOURCC_DXT1: decode = bcdec_bc1; block_size = BCDEC_BC1_BLOCK_SIZE; break;
case FOURCC_DXT3: decode = bcdec_bc2; block_size = BCDEC_BC2_BLOCK_SIZE; break;
case FOURCC_DXT5: decode = bcdec_bc3; block_size = BCDEC_BC3_BLOCK_SIZE; break;
case FOURCC_DX10:
if (!valid_dx10_format(dx10_header) ||
dx10_header.resourceDimension != D3D10_RESOURCE_DIMENSION::D3D10_RESOURCE_DIMENSION_TEXTURE2D ||
dx10_header.arraySize > 1) {
cfclose(cfp);
return DDS_ERROR_UNSUPPORTED;
}
decode = bcdec_bc7;
block_size = BCDEC_BC7_BLOCK_SIZE;
break;
default:
cfclose(cfp);
return DDS_ERROR_UNSUPPORTED;
}
const int w = static_cast<int>(dds_header.dwWidth);
const int h = static_cast<int>(dds_header.dwHeight);
if (w <= 0 || h <= 0) {
cfclose(cfp);
return DDS_ERROR_INVALID_FORMAT;
}
// BCn data is stored as ceil(w/4) * ceil(h/4) 4x4 blocks; dimensions
// don't have to be multiples of 4.
const int blocks_w = (w + 3) / 4;
const int blocks_h = (h + 3) / 4;
const int padded_w = blocks_w * 4;
const int padded_h = blocks_h * 4;
const size_t compressed_size = static_cast<size_t>(blocks_w) * blocks_h * block_size;
// _dds_read_header leaves the file positioned right after the header
// (including the DX10 sub-header if present), so the next read is the
// top mip's pixel data.
SCP_vector<ubyte> compressed(compressed_size);
const int got = cfread(compressed.data(), 1, static_cast<int>(compressed_size), cfp);
cfclose(cfp);
if (got != static_cast<int>(compressed_size))
return DDS_ERROR_INVALID_FORMAT;
// Decode into a padded buffer so edge blocks have room, then crop to w*h.
SCP_vector<ubyte> decoded(static_cast<size_t>(padded_w) * padded_h * 4);
const int dec_stride = padded_w * 4;
const ubyte *src = compressed.data();
for (int by = 0; by < blocks_h; ++by) {
for (int bx = 0; bx < blocks_w; ++bx) {
ubyte *blk_dst = decoded.data() + (by * 4) * dec_stride + (bx * 4) * 4;
decode(src, blk_dst, dec_stride);
src += block_size;
}
}
out_pixels.assign(static_cast<size_t>(w) * h * 4, 0);
const int dst_stride = w * 4;
for (int y = 0; y < h; ++y) {
std::memcpy(out_pixels.data() + static_cast<size_t>(y) * dst_stride,
decoded.data() + static_cast<size_t>(y) * dec_stride,
static_cast<size_t>(dst_stride));
}
// bcdec outputs RGBA byte-order; swap to BGRA
for (size_t x = 0; x < out_pixels.size(); x += 4) {
std::swap(out_pixels[x], out_pixels[x + 2]);
}
if (out_width) *out_width = w;
if (out_height) *out_height = h;
return DDS_ERROR_NONE;
}
// save some image data as a DDS image
// NOTE: we only support, uncompressed, 24-bit RGB and 32-bit RGBA images here!!
void dds_save_image(int width, int height, int bpp, int num_mipmaps, ubyte *data, int cubemap, const char *filename)
-30
View File
@@ -273,27 +273,6 @@ typedef struct {
} DDS_HEADER_DXT10;
#pragma pack()
// Block size in bytes for a 4x4 texel block of a compressed DDS format.
// comp_type is one of the DDS_DXT*/DDS_CUBEMAP_DXT* constants.
inline int dds_block_size(int comp_type) {
switch (comp_type) {
case DDS_DXT1:
case DDS_CUBEMAP_DXT1:
return 8;
case DDS_DXT3: case DDS_CUBEMAP_DXT3:
case DDS_DXT5: case DDS_CUBEMAP_DXT5:
case DDS_BC7:
return 16;
default:
return 0;
}
}
// Size in bytes of one mip level of a block-compressed texture.
inline size_t dds_compressed_mip_size(int w, int h, int block_size) {
return static_cast<size_t>(((w + 3) / 4) * ((h + 3) / 4) * block_size);
}
#define DDS_OFFSET 4+sizeof(DDS_HEADER) //place where the data starts -- should be 128
#define DX10_OFFSET DDS_OFFSET+sizeof(DDS_HEADER_DXT10) // Unless a DX10 header is present
@@ -306,15 +285,6 @@ int dds_read_header(const char *filename, CFILE *img_cfp = NULL, int *width = 0,
//size of the data it stored in size
int dds_read_bitmap(const char *filename, ubyte *data, ubyte *bpp = NULL, int cf_type = CF_TYPE_ANY);
// Decompress just the top mip of a 2D FOURCC-compressed DDS (DXT1/3/5, BC7)
// to 32-bpp BGRA, regardless of what the renderer's compression support is.
// Intended for tool/preview code that needs raw pixels and doesn't care
// about mipmaps or cubemap faces. On success, out_pixels is sized to
// width*height*4 in BGRA byte order.
int dds_decompress_top_mip_bgra(const char *filename, int cf_type,
int *out_width, int *out_height,
SCP_vector<ubyte> &out_pixels);
// writes a DDS file using given data
void dds_save_image(int width, int height, int bpp, int num_mipmaps, ubyte *data = NULL, int cubemap = 0, const char *filename = NULL);
Loaded 100 of 1662 files, more files were not shown because too many files have changed in this diff. Show more