mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-07 22:56:30 -10:00
Compare commits
47
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d8df07e612 | ||
|
|
5a93ecace2 | ||
|
|
1caf89a034 | ||
|
|
995299ffac | ||
|
|
58682b8bbf | ||
|
|
9e4fe90d6d | ||
|
|
5ccd4fb9ee | ||
|
|
f4e7bef89b | ||
|
|
0dab72c27a | ||
|
|
241c46fe3f | ||
|
|
49544a598e | ||
|
|
93a608bd79 | ||
|
|
ce227f72d8 | ||
|
|
e76875f39c | ||
|
|
e43b81b669 | ||
|
|
1a7e8283df | ||
|
|
9d0bbeed53 | ||
|
|
8bfed9e612 | ||
|
|
a68cf42299 | ||
|
|
f8dff7f419 | ||
|
|
da18a2cea4 | ||
|
|
e17b2fd0b6 | ||
|
|
5978f99ad9 | ||
|
|
151a6f6d66 | ||
|
|
c84f0b0b69 | ||
|
|
182f10f94f | ||
|
|
a9a44162d7 | ||
|
|
a3f5b086fe | ||
|
|
4a4d997285 | ||
|
|
157cf0ad52 | ||
|
|
268fcad1a3 | ||
|
|
43a9154dab | ||
|
|
7528756867 | ||
|
|
946c03c825 | ||
|
|
74cea66877 | ||
|
|
5c192bb645 | ||
|
|
3f1163c55c | ||
|
|
143cf3d36d | ||
|
|
05865b8d13 | ||
|
|
a158c829e9 | ||
|
|
9f8602ea4d | ||
|
|
ff802cc75a | ||
|
|
cd9e61396d | ||
|
|
914c66fea9 | ||
|
|
5b54ddfd53 | ||
|
|
931f6118fe | ||
|
|
20d86c6079 |
No files matched your search
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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}")
|
||||
@@ -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"
|
||||
@@ -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 ..
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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
@@ -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({
|
||||
|
||||
@@ -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"])}
|
||||
|
||||
@@ -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
|
||||
@@ -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.
@@ -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()
|
||||
@@ -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 "
")
|
||||
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()
|
||||
@@ -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()
|
||||
@@ -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()
|
||||
@@ -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()
|
||||
@@ -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")
|
||||
+1
Submodule cmake/external/rpavlik-cmake-modules added at 7cef9577d6.
@@ -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
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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/)
|
||||
|
||||
@@ -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}")
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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)
|
||||
@@ -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>()));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
|
||||
+171
-488
File diff suppressed because it is too large.
Load diff
Whitespace-only changes.
+19
-72
@@ -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
@@ -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
@@ -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, false));
|
||||
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, false));
|
||||
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
@@ -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;
|
||||
}
|
||||
|
||||
+14
-34
@@ -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) {
|
||||
@@ -1439,9 +1431,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 +1608,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 +1680,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 +2221,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 +2319,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 +2608,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 +2636,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 +2690,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();
|
||||
|
||||
@@ -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
@@ -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
-27
@@ -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)
|
||||
@@ -359,7 +345,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 +388,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 +580,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
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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 1648 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user