mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-08 17:48:46 -10:00
Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0945dee99e | ||
|
|
9e8003bd8a | ||
|
|
47d77aa9d5 | ||
|
|
2b49a0d780 |
No files matched your search
@@ -48,7 +48,5 @@ CheckOptions:
|
||||
value: 'std::vector;std::deque;std::list;SCP_vector;SCP_deque;SCP_list'
|
||||
- key: 'readability-braces-around-statements.ShortStatementLines'
|
||||
value: '4' # Avoid flagging simple if (...) return false; statements
|
||||
- key: 'performance-move-const-arg.CheckTriviallyCopyableMove' # This isn't actually performance relevant, but using move on trivially copyable types can well indicate that the variable should not be used anymore, such as when passing a builder type to the finialization function
|
||||
value: 'false'
|
||||
...
|
||||
|
||||
@@ -23,13 +23,10 @@ jobs:
|
||||
runs-on: ${{ matrix.os }}
|
||||
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 }}
|
||||
@@ -54,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
|
||||
@@ -62,26 +59,23 @@ jobs:
|
||||
name: Build Linux distribution zip
|
||||
needs: build_linux
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/sftp_upload:sha-844131c
|
||||
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
|
||||
@@ -112,13 +106,10 @@ jobs:
|
||||
name: Windows
|
||||
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: Cache Qt
|
||||
# id: cache-qt-win
|
||||
# uses: actions/cache@v1
|
||||
@@ -164,13 +155,13 @@ jobs:
|
||||
-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 ..
|
||||
-G "Visual Studio 16 2019" -T "v142" ..
|
||||
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 ..
|
||||
-G "Visual Studio 16 2019" -T "v142" ..
|
||||
fi
|
||||
- name: Compile
|
||||
working-directory: ./build
|
||||
@@ -188,7 +179,7 @@ jobs:
|
||||
shell: bash
|
||||
run: ./bin/$CONFIGURATION/unittests --gtest_shuffle
|
||||
- name: Upload build result
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: windows-${{ matrix.configuration }}-${{ matrix.arch }}-${{ matrix.simd }}
|
||||
path: ${{ github.workspace }}/build/install/*
|
||||
@@ -196,27 +187,24 @@ jobs:
|
||||
name: Build Windows distribution zip
|
||||
needs: build_windows
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/sftp_upload:sha-844131c
|
||||
container: ghcr.io/scp-fs2open/sftp_upload:sha-748b19d
|
||||
strategy:
|
||||
matrix:
|
||||
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: Download Release builds
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
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-${{ matrix.arch }}-${{ matrix.simd }}
|
||||
path: builds
|
||||
@@ -261,14 +249,11 @@ jobs:
|
||||
# setup-python: 'false'
|
||||
# aqtversion: ==1.1.3
|
||||
# py7zrversion: '==0.19.*'
|
||||
- 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: Prepare Vulkan SDK
|
||||
uses: humbletim/[email protected]
|
||||
with:
|
||||
@@ -317,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
|
||||
@@ -325,27 +310,24 @@ jobs:
|
||||
name: Build Mac distribution zip
|
||||
needs: build_mac
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/sftp_upload:sha-844131c
|
||||
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
|
||||
|
||||
@@ -52,15 +52,12 @@ jobs:
|
||||
runs-on: ${{ matrix.os }}
|
||||
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 }}
|
||||
@@ -85,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.
|
||||
@@ -102,29 +99,26 @@ jobs:
|
||||
name: Build Linux distribution zip
|
||||
needs: build_linux
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/sftp_upload:sha-844131c
|
||||
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
|
||||
@@ -141,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 }}
|
||||
@@ -163,15 +157,12 @@ jobs:
|
||||
name: Windows
|
||||
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: Cache Qt
|
||||
# # Cache Qt
|
||||
# id: cache-qt-win
|
||||
@@ -220,13 +211,13 @@ jobs:
|
||||
-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 ..
|
||||
-G "Visual Studio 16 2019" -T "v142" ..
|
||||
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 ..
|
||||
-G "Visual Studio 16 2019" -T "v142" ..
|
||||
fi
|
||||
- name: Compile
|
||||
working-directory: ./build
|
||||
@@ -244,7 +235,7 @@ jobs:
|
||||
shell: bash
|
||||
run: ./bin/$CONFIGURATION/unittests --gtest_shuffle
|
||||
- name: Upload build result
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: windows-${{ matrix.configuration }}-${{ matrix.arch }}-${{ matrix.simd }}
|
||||
path: ${{ github.workspace }}/build/install/*
|
||||
@@ -253,7 +244,7 @@ jobs:
|
||||
name: Build Windows distribution zip
|
||||
needs: build_windows
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/sftp_upload:sha-844131c
|
||||
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:
|
||||
@@ -261,23 +252,20 @@ jobs:
|
||||
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: Download Release builds
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
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-${{ matrix.arch }}-${{ matrix.simd }}
|
||||
path: builds
|
||||
@@ -292,13 +280,13 @@ jobs:
|
||||
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 }}
|
||||
@@ -336,15 +324,12 @@ jobs:
|
||||
# cached: ${{ steps.cache-qt-mac.outputs.cache-hit }}
|
||||
# setup-python: 'false'
|
||||
# aqtversion: ==1.1.3
|
||||
- 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: Prepare Vulkan SDK
|
||||
uses: humbletim/[email protected]
|
||||
with:
|
||||
@@ -387,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
|
||||
@@ -395,27 +380,24 @@ jobs:
|
||||
name: Build Mac distribution zip
|
||||
needs: build_mac
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/sftp_upload:sha-844131c
|
||||
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
|
||||
@@ -431,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 }}
|
||||
|
||||
@@ -17,13 +17,10 @@ jobs:
|
||||
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: |
|
||||
@@ -54,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 }}
|
||||
path: ${{ github.workspace }}/build/install/*.AppImage
|
||||
@@ -62,24 +59,21 @@ jobs:
|
||||
name: Build Linux distribution zip
|
||||
needs: build_linux
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/sftp_upload:sha-844131c
|
||||
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
|
||||
path: builds
|
||||
- name: Download FastDebug builds
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: linux-FastDebug
|
||||
path: builds
|
||||
@@ -104,13 +98,10 @@ jobs:
|
||||
name: Windows
|
||||
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: |
|
||||
@@ -162,13 +153,13 @@ jobs:
|
||||
-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 ..
|
||||
-G "Visual Studio 16 2019" -T "v142" ..
|
||||
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 ..
|
||||
-G "Visual Studio 16 2019" -T "v142" ..
|
||||
fi
|
||||
- name: Compile
|
||||
working-directory: ./build
|
||||
@@ -186,7 +177,7 @@ jobs:
|
||||
shell: bash
|
||||
run: ./bin/$CONFIGURATION/unittests --gtest_shuffle
|
||||
- name: Upload build result
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: windows-${{ matrix.configuration }}-${{ matrix.arch }}-${{ matrix.simd }}
|
||||
path: ${{ github.workspace }}/build/install/*
|
||||
@@ -194,28 +185,25 @@ jobs:
|
||||
name: Build Windows distribution zip
|
||||
needs: build_windows
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/sftp_upload:sha-844131c
|
||||
container: ghcr.io/scp-fs2open/sftp_upload:sha-748b19d
|
||||
strategy:
|
||||
matrix:
|
||||
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: Download Release builds
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
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-${{ matrix.arch }}-${{ matrix.simd }}
|
||||
path: builds
|
||||
@@ -260,14 +248,11 @@ jobs:
|
||||
# setup-python: 'false'
|
||||
# aqtversion: ==1.1.3
|
||||
# py7zrversion: '==0.19.*'
|
||||
- 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: Prepare Vulkan SDK
|
||||
uses: humbletim/[email protected]
|
||||
with:
|
||||
@@ -315,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
|
||||
@@ -323,27 +308,24 @@ jobs:
|
||||
name: Build Mac distribution zip
|
||||
needs: build_mac
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/sftp_upload:sha-844131c
|
||||
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
|
||||
|
||||
@@ -27,15 +27,10 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-71099c9
|
||||
steps:
|
||||
- name: Install Qt dependencies
|
||||
run: apt-get -yq update && apt-get -yq install libfontconfig1
|
||||
- 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
|
||||
with:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -30,16 +30,11 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-71099c9
|
||||
steps:
|
||||
- name: Install Qt dependencies
|
||||
run: apt-get -yq update && apt-get -yq install libfontconfig1
|
||||
- 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
|
||||
with:
|
||||
@@ -81,7 +76,7 @@ jobs:
|
||||
build_windows:
|
||||
strategy:
|
||||
matrix:
|
||||
configuration: [Debug, FastDebug, Release]
|
||||
configuration: [Debug, Release]
|
||||
compiler: [MSVC]
|
||||
arch: [Win32, x64]
|
||||
name: Windows
|
||||
@@ -89,13 +84,10 @@ jobs:
|
||||
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: Cache Qt
|
||||
# id: cache-qt-win
|
||||
# uses: actions/cache@v1
|
||||
@@ -147,12 +139,12 @@ jobs:
|
||||
else
|
||||
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 ..
|
||||
-DFORCED_SIMD_INSTRUCTIONS=SSE2 -DFSO_BUILD_FRED2="ON" -DFSO_BUILD_WITH_VULKAN="OFF" -G "Visual Studio 16 2019" \
|
||||
-DFSO_BUILD_QTFRED=OFF -T "v142" -A "$ARCHITECTURE" ..
|
||||
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 ..
|
||||
-DFORCED_SIMD_INSTRUCTIONS=SSE2 -DFSO_BUILD_FRED2="ON" -G "Visual Studio 16 2019" \
|
||||
-DFSO_BUILD_QTFRED=OFF -T "v142" -A "$ARCHITECTURE" ..
|
||||
fi
|
||||
fi
|
||||
- name: Compile
|
||||
@@ -205,14 +197,11 @@ jobs:
|
||||
# setup-python: 'false'
|
||||
# aqtversion: ==1.1.3
|
||||
# py7zrversion: '==0.19.*'
|
||||
- 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
|
||||
with:
|
||||
|
||||
@@ -29,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
|
||||
|
||||
@@ -42,7 +42,6 @@ _ReSharper*/
|
||||
|
||||
#Project files
|
||||
[Bb]uild/
|
||||
[Oo]ut/
|
||||
|
||||
#Subversion files
|
||||
.svn
|
||||
@@ -260,5 +259,3 @@ CMakePresets.json
|
||||
!/code/scripting/lua/LuaConvert.h
|
||||
!/code/debugconsole/
|
||||
!/docker/build
|
||||
CMakeFiles/cmake.check_cache
|
||||
CMakeCache.txt
|
||||
+16
-33
@@ -1,5 +1,5 @@
|
||||
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 3.21)
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 3.9)
|
||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
|
||||
# Make sure the source and binary directory are not the sample
|
||||
@@ -8,12 +8,12 @@ if ("${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
endif()
|
||||
|
||||
include(cmake/util.cmake)
|
||||
include(cmake/embed_file.cmake)
|
||||
|
||||
# Set a few policies
|
||||
set_policy(CMP0051 NEW)
|
||||
set_policy(CMP0053 NEW)
|
||||
set_policy(CMP0054 NEW)
|
||||
set_policy(CMP0091 NEW) # Enable use of CMAKE_MSVC_RUNTIME_LIBRARY
|
||||
|
||||
SET(FSO_PROJECT_DESCRIPTION "Open source project based on the original FreeSpace 2 source code.")
|
||||
|
||||
@@ -57,16 +57,12 @@ LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/finder")
|
||||
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)
|
||||
include(embed_file)
|
||||
|
||||
IF(RESET_INSTALL_PREFIX)
|
||||
IF(NOT $ENV{FS2PATH} STREQUAL "")
|
||||
IF(NOT IS_DIRECTORY $ENV{FS2PATH})
|
||||
MESSAGE(WARNING "The path '$ENV{FS2PATH}' of the environment variable FS2PATH does not point to a directory! Install prefix wasn't set.")
|
||||
ELSE(NOT IS_DIRECTORY $ENV{FS2PATH})
|
||||
SET(CMAKE_INSTALL_PREFIX "$ENV{FS2PATH}" CACHE PATH "Install path" FORCE)
|
||||
SET(CMAKE_INSTALL_PREFIX "$ENV{FS2PATH}" CACHE FILEPATH "Install path" FORCE)
|
||||
FILE(TO_CMAKE_PATH ${CMAKE_INSTALL_PREFIX} CMAKE_INSTALL_PREFIX)
|
||||
ENDIF(NOT IS_DIRECTORY $ENV{FS2PATH})
|
||||
ELSE(NOT $ENV{FS2PATH} STREQUAL "")
|
||||
@@ -74,11 +70,9 @@ IF(RESET_INSTALL_PREFIX)
|
||||
ENDIF(NOT $ENV{FS2PATH} STREQUAL "")
|
||||
ENDIF(RESET_INSTALL_PREFIX)
|
||||
|
||||
IF(WIN32 OR APPLE 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)
|
||||
@@ -111,7 +105,7 @@ OPTION(FSO_USE_OPENALSOFT "Download and build OpenAL Soft instead of using the s
|
||||
|
||||
OPTION(FSO_FATAL_WARNINGS "Determines if warnings in the build are considered fatal errors, primarily used for CI" OFF)
|
||||
|
||||
SET(FSO_FREESPACE_PATH "${CMAKE_INSTALL_PREFIX}" CACHE PATH "The path of the FreeSpace directory you want to use. Please note that you will have to change CMAKE_INSTALL_PREFIX if you change this at some point.")
|
||||
SET(FSO_FREESPACE_PATH "${CMAKE_INSTALL_PREFIX}" CACHE FILEPATH "The path of the FreeSpace directory you want to use. Please note that you will have to change CMAKE_INSTALL_PREFIX if you change this at some point.")
|
||||
|
||||
SET(FSO_RUN_ARGUMENTS "" CACHE STRING "Additional arguments passed to a generated executable when run with the generated build files.")
|
||||
|
||||
@@ -127,25 +121,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 (External shaders only!)" OFF)
|
||||
|
||||
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 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)
|
||||
@@ -173,11 +152,15 @@ 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)
|
||||
|
||||
# Include cotire file from https://github.com/sakra/cotire/
|
||||
include(cotire)
|
||||
|
||||
INCLUDE(globals)
|
||||
INCLUDE(toolchain)
|
||||
INCLUDE(platforms)
|
||||
include(version)
|
||||
|
||||
@@ -188,8 +171,7 @@ 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)
|
||||
@@ -245,7 +227,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}")
|
||||
@@ -259,6 +243,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}")
|
||||
@@ -26,5 +26,5 @@ git diff -U0 --no-color "$BASE_COMMIT..$2" | \
|
||||
-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)' \
|
||||
-regex '(code(?!((\/graphics\/shaders\/compiled)|(\/globalincs\/windebug)))|freespace2|qtfred|test|build|tools)\/.*\.(cpp|h)' \
|
||||
-clang-tidy-binary /usr/bin/clang-tidy-16 -j$(nproc) -export-fixes "$(pwd)/clang-fixes.yaml"
|
||||
@@ -42,7 +42,7 @@ export CXXFLAGS
|
||||
export CFLAGS
|
||||
export LD_LIBRARY_PATH
|
||||
|
||||
if [ "$RUNNER_OS" = "macOS" ] && [ ! -x "$(which ninja)" ]; then
|
||||
if [ "$RUNNER_OS" = "macOS" ]; then
|
||||
brew install ninja
|
||||
fi
|
||||
|
||||
|
||||
@@ -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 -name 'fs2_open_*' -type f -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 -iname 'qtfred_*' -type f -printf "%f\n").AppImage"
|
||||
./bin/appimagetool -n "$INSTALL_FOLDER/qtFRED" "$INSTALL_FOLDER/$FILENAME"
|
||||
chmod +x "$INSTALL_FOLDER/$FILENAME"
|
||||
fi
|
||||
|
||||
ls -al $INSTALL_FOLDER
|
||||
+6
-8
@@ -33,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
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
Mako==1.3.12
|
||||
requests==2.33.0
|
||||
Mako==1.2.2
|
||||
requests==2.32.0
|
||||
semantic-version==2.8.5
|
||||
File renamed without changes.
File renamed without changes.
@@ -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")
|
||||
Vendored
+4054
File diff suppressed because it is too large.
Load diff
@@ -11,8 +11,6 @@ if (WIN32)
|
||||
endif()
|
||||
elseif(APPLE)
|
||||
# it should just work
|
||||
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
-6
@@ -9,19 +9,14 @@ else()
|
||||
endif()
|
||||
|
||||
set(IS_ARM64 FALSE)
|
||||
set(IS_ARMV7A FALSE)
|
||||
|
||||
if (NOT "${CMAKE_GENERATOR_PLATFORM}" STREQUAL "") # needed to cover Visual Studio generator
|
||||
if(CMAKE_GENERATOR_PLATFORM MATCHES "^(aarch64|arm64|ARM64)")
|
||||
set(IS_ARM64 TRUE)
|
||||
elseif(CMAKE_GENERATOR_PLATFORM MATCHES "^(armv7)")
|
||||
set(IS_ARMV7A TRUE)
|
||||
endif()
|
||||
else()
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64|arm64|ARM64)")
|
||||
set(IS_ARM64 TRUE)
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(armv7)")
|
||||
set(IS_ARMV7A TRUE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -38,6 +33,6 @@ else()
|
||||
endif()
|
||||
|
||||
set(IS_X86 FALSE)
|
||||
if (NOT IS_ARM64 AND NOT IS_RISCV AND NOT IS_ARMV7A)
|
||||
if (NOT IS_ARM64 AND NOT IS_RISCV)
|
||||
set(IS_X86 TRUE)
|
||||
endif()
|
||||
@@ -15,4 +15,4 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fcolor-diagnostics")
|
||||
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -Wno-unused-variable -Wno-unused-parameter")
|
||||
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g -Wshadow")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "-Og -g -Wshadow")
|
||||
@@ -119,14 +119,14 @@ string(REGEX MATCH "-O[a-zA-Z|0-9]+" C_OPT_FLAG ${C_BASE_FLAGS})
|
||||
# If no user-set opt flag, set -O3 and -Og
|
||||
if ("${CXX_OPT_FLAG}" STREQUAL "")
|
||||
set(CXX_OPT_FLAG_RELEASE "-O3")
|
||||
set(CXX_OPT_FLAG_DEBUG "-O0")
|
||||
set(CXX_OPT_FLAG_DEBUG "-Og")
|
||||
else()
|
||||
set(CXX_OPT_FLAG_RELEASE "${CXX_OPT_FLAG}")
|
||||
set(CXX_OPT_FLAG_DEBUG "${CXX_OPT_FLAG}")
|
||||
endif()
|
||||
if ("${C_OPT_FLAG}" STREQUAL "")
|
||||
set(C_OPT_FLAG_RELEASE "-O3")
|
||||
set(C_OPT_FLAG_DEBUG "-O0")
|
||||
set(C_OPT_FLAG_DEBUG "-Og")
|
||||
else()
|
||||
set(C_OPT_FLAG_RELEASE "${C_OPT_FLAG}")
|
||||
set(C_OPT_FLAG_DEBUG "${C_OPT_FLAG}")
|
||||
|
||||
@@ -161,14 +161,14 @@ string(REGEX MATCH "-O[a-zA-Z|0-9]+" C_OPT_FLAG ${C_BASE_FLAGS})
|
||||
# If no user-set opt flag, set -O3 and -Og
|
||||
if ("${CXX_OPT_FLAG}" STREQUAL "")
|
||||
set(CXX_OPT_FLAG_RELEASE "-O3")
|
||||
set(CXX_OPT_FLAG_DEBUG "-O0")
|
||||
set(CXX_OPT_FLAG_DEBUG "-Og")
|
||||
else()
|
||||
set(CXX_OPT_FLAG_RELEASE "${CXX_OPT_FLAG}")
|
||||
set(CXX_OPT_FLAG_DEBUG "${CXX_OPT_FLAG}")
|
||||
endif()
|
||||
if ("${C_OPT_FLAG}" STREQUAL "")
|
||||
set(C_OPT_FLAG_RELEASE "-O3")
|
||||
set(C_OPT_FLAG_DEBUG "-O0")
|
||||
set(C_OPT_FLAG_DEBUG "-Og")
|
||||
else()
|
||||
set(C_OPT_FLAG_RELEASE "${C_OPT_FLAG}")
|
||||
set(C_OPT_FLAG_DEBUG "${C_OPT_FLAG}")
|
||||
|
||||
@@ -71,19 +71,27 @@ if (MSVC_RELEASE_DEBUGGING)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# This should be kept in sync with the corresponding IF() in fred2/CMakeLists.txt
|
||||
IF(MSVC_USE_RUNTIME_DLL OR FSO_BUILD_QTFRED)
|
||||
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<NOT:$<CONFIG:Release>>:Debug>DLL")
|
||||
add_compile_definitions(_AFXDLL)
|
||||
ELSE()
|
||||
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<NOT:$<CONFIG:Release>>:Debug>")
|
||||
ENDIF()
|
||||
IF(MSVC_USE_RUNTIME_DLL)
|
||||
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /MD")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MD")
|
||||
ELSE(MSVC_USE_RUNTIME_DLL)
|
||||
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /MT")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
|
||||
ENDIF(MSVC_USE_RUNTIME_DLL)
|
||||
|
||||
# Debug
|
||||
set(CMAKE_C_FLAGS_DEBUG "/W4 /Gy /Zi /Od /RTC1 /Gd /Oy-")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "/W4 /Gy /Zi /Od /RTC1 /Gd /Oy-")
|
||||
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "/DEBUG /INCREMENTAL:NO /MAPINFO:EXPORTS /NODEFAULTLIB:libcmt.lib")
|
||||
|
||||
IF(MSVC_USE_RUNTIME_DLL)
|
||||
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /MDd")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MDd")
|
||||
ELSE(MSVC_USE_RUNTIME_DLL)
|
||||
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /MTd")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
|
||||
ENDIF(MSVC_USE_RUNTIME_DLL)
|
||||
|
||||
INCLUDE(MSVCMultipleProcessCompile)
|
||||
|
||||
# Visual Studio supports compiling for multiple vector instruction sets
|
||||
@@ -114,7 +122,8 @@ if(IS_X86)
|
||||
|
||||
endif()
|
||||
|
||||
target_compile_definitions(compiler INTERFACE _CRT_SECURE_NO_DEPRECATE _CRT_SECURE_NO_WARNINGS _SECURE_SCL=0 NOMINMAX _SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING)
|
||||
target_compile_definitions(compiler INTERFACE _CRT_SECURE_NO_DEPRECATE _CRT_SECURE_NO_WARNINGS _SECURE_SCL=0 NOMINMAX
|
||||
"$<$<CONFIG:FastDebug>:_ITERATOR_DEBUG_LEVEL=0>" _SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING)
|
||||
|
||||
if (FSO_FATAL_WARNINGS)
|
||||
# Make warnings fatal if the right variable is set
|
||||
|
||||
+21
-11
@@ -158,17 +158,27 @@ function(set_precompiled_header _target _headerPath)
|
||||
target_compile_definitions(${_target} PRIVATE CMAKE_PCH)
|
||||
target_precompile_headers(${_target} PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:${_headerPath}>")
|
||||
else()
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
target_compile_options(${_target} PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:-include${_headerPath}>")
|
||||
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
target_compile_options(${_target} PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:/FI ${_headerPath}>")
|
||||
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
target_compile_options(${_target} PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:-include${_headerPath}>")
|
||||
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang")
|
||||
target_compile_options(${_target} PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:-include${_headerPath}>")
|
||||
ELSE()
|
||||
MESSAGE("Unknown compiler for global includes. This will probably break the build.")
|
||||
ENDIF()
|
||||
if (ENABLE_COTIRE)
|
||||
message("${_headerPath}")
|
||||
set_target_properties(${_target} PROPERTIES COTIRE_CXX_PREFIX_HEADER_INIT "${_headerPath}")
|
||||
|
||||
# Disable unity build as it doesn't work well for us
|
||||
set_target_properties(${_target} PROPERTIES COTIRE_ADD_UNITY_BUILD FALSE)
|
||||
|
||||
cotire(${_target})
|
||||
else()
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
target_compile_options(${_target} PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:-include${_headerPath}>")
|
||||
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
target_compile_options(${_target} PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:/FI ${_headerPath}>")
|
||||
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
target_compile_options(${_target} PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:-include${_headerPath}>")
|
||||
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang")
|
||||
target_compile_options(${_target} PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:-include${_headerPath}>")
|
||||
ELSE()
|
||||
MESSAGE("Unknown compiler for global includes. This will probably break the build.")
|
||||
ENDIF()
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|
||||
+3
-3
@@ -6,9 +6,9 @@ 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_MINOR 0)
|
||||
set_if_not_defined(FSO_VERSION_BUILD 1)
|
||||
set_if_not_defined(FSO_VERSION_MAJOR 24)
|
||||
set_if_not_defined(FSO_VERSION_MINOR 3)
|
||||
set_if_not_defined(FSO_VERSION_BUILD 0)
|
||||
|
||||
# A numeric revision e.g. the CI build number
|
||||
set_if_not_defined(FSO_VERSION_REVISION 0)
|
||||
|
||||
+1
-1
@@ -59,7 +59,7 @@ endif()
|
||||
|
||||
target_link_libraries(code PUBLIC libRocket)
|
||||
|
||||
target_link_libraries(code PUBLIC pcpnatpmp)
|
||||
target_link_libraries(code PUBLIC pcp)
|
||||
|
||||
target_link_libraries(code PUBLIC parsers)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -51,8 +51,8 @@ class ExpressionBuilderVisitor : public ActionExpressionVisitor {
|
||||
operatorText = context->MINUS()->getText();
|
||||
}
|
||||
|
||||
const auto leftExpr = std::any_cast<std::shared_ptr<nodes::AbstractExpression>>(visit(context->expression(0)));
|
||||
const auto rightExpr = std::any_cast<std::shared_ptr<nodes::AbstractExpression>>(visit(context->expression(1)));
|
||||
const auto leftExpr = visit(context->expression(0)).as<std::shared_ptr<nodes::AbstractExpression>>();
|
||||
const auto rightExpr = visit(context->expression(1)).as<std::shared_ptr<nodes::AbstractExpression>>();
|
||||
|
||||
auto operatorExpression = std::make_shared<nodes::FunctionCallExpression>(operatorTok,
|
||||
true,
|
||||
@@ -88,8 +88,8 @@ class ExpressionBuilderVisitor : public ActionExpressionVisitor {
|
||||
antlrcpp::Any visitRandom_range_expression(ActionExpressionParser::Random_range_expressionContext* context) override
|
||||
{
|
||||
auto expression = std::make_shared<nodes::RandomRangeExpression>(context->RAND_L_PAREN()->getSymbol(),
|
||||
std::any_cast<std::shared_ptr<nodes::AbstractExpression>>(visit(context->expression(0))),
|
||||
std::any_cast<std::shared_ptr<nodes::AbstractExpression>>(visit(context->expression(1))));
|
||||
visit(context->expression(0)).as<std::shared_ptr<nodes::AbstractExpression>>(),
|
||||
visit(context->expression(1)).as<std::shared_ptr<nodes::AbstractExpression>>());
|
||||
return std::static_pointer_cast<nodes::AbstractExpression>(expression);
|
||||
}
|
||||
antlrcpp::Any visitLiteral_expression(ActionExpressionParser::Literal_expressionContext* context) override
|
||||
@@ -122,9 +122,9 @@ class ExpressionBuilderVisitor : public ActionExpressionVisitor {
|
||||
}
|
||||
antlrcpp::Any visitVec3d_constructor(ActionExpressionParser::Vec3d_constructorContext* context) override
|
||||
{
|
||||
const auto xExpression = std::any_cast<std::shared_ptr<nodes::AbstractExpression>>(visit(context->expression(0)));
|
||||
const auto yExpression = std::any_cast<std::shared_ptr<nodes::AbstractExpression>>(visit(context->expression(1)));
|
||||
const auto zExpression = std::any_cast<std::shared_ptr<nodes::AbstractExpression>>(visit(context->expression(2)));
|
||||
const auto xExpression = visit(context->expression(0)).as<std::shared_ptr<nodes::AbstractExpression>>();
|
||||
const auto yExpression = visit(context->expression(1)).as<std::shared_ptr<nodes::AbstractExpression>>();
|
||||
const auto zExpression = visit(context->expression(2)).as<std::shared_ptr<nodes::AbstractExpression>>();
|
||||
|
||||
auto expression = std::make_shared<nodes::VectorConstructorExpression>(context->L_PAREN()->getSymbol(),
|
||||
xExpression,
|
||||
@@ -157,7 +157,7 @@ std::shared_ptr<nodes::AbstractExpression> ExpressionParser::parse(const ParseCo
|
||||
if (errListener.diagnostics.empty()) {
|
||||
// Only do semantic checking if syntax is valid
|
||||
ExpressionBuilderVisitor builder;
|
||||
exprReturn = std::any_cast<std::shared_ptr<nodes::AbstractExpression>>(tree->accept(&builder));
|
||||
exprReturn = tree->accept(&builder).as<std::shared_ptr<nodes::AbstractExpression>>();
|
||||
|
||||
if (!exprReturn->validate(&parser, context)) {
|
||||
exprReturn = nullptr;
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
+4
-5
@@ -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)
|
||||
@@ -528,7 +527,7 @@ 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);
|
||||
extern void ai_attack_object(object *attacker, object *attacked, int ship_info_index = -1);
|
||||
extern void ai_evade_object(object *evader, object *evaded);
|
||||
extern void ai_ignore_object(object *ignorer, object *ignored, int ignore_new);
|
||||
extern void ai_ignore_wing(object *ignorer, int wingnum);
|
||||
@@ -560,7 +559,7 @@ extern void ai_set_guard_wing(object *objp, int wingnum);
|
||||
extern void ai_warp_out(object *objp, vec3d *vp);
|
||||
extern void ai_attack_wing(object *attacker, int wingnum);
|
||||
extern void ai_deathroll_start(object *ship_obj);
|
||||
extern int set_target_objnum(ai_info* aip, int objnum);
|
||||
extern int set_target_objnum(ai_info *aip, int objnum);
|
||||
extern void ai_form_on_wing(object *objp, object *goal_objp);
|
||||
extern void ai_do_stay_near(object *objp, object *other_obj, float dist, int additional_data);
|
||||
extern ship_subsys *set_targeted_subsys(ai_info *aip, ship_subsys *new_subsys, int parent_objnum);
|
||||
@@ -597,7 +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, int ship_info_index = -1, int class_type = -1);
|
||||
extern int find_enemy(int objnum, float range, int max_attackers, int ship_info_index = -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);
|
||||
@@ -618,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, 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);
|
||||
|
||||
// moved to header file by Goober5000
|
||||
void ai_announce_ship_dying(object *dying_objp);
|
||||
|
||||
+1
-23
@@ -44,15 +44,12 @@ namespace AI {
|
||||
Goal_on_hold, // when set, this goal cannot currently be satisfied, although it could be in the future
|
||||
Subsys_needs_fixup, // when set, the subsystem index (for a destroy subsystem goal) is invalid and must be gotten from the subsys name stored in docker.name field!!
|
||||
Goal_override, // paired with ai_goal_type::DYNAMIC to mean this goal overrides any other goal
|
||||
Want_override, // a goal should set this flag if Goal_override should be assigned when the goal is achievable
|
||||
Purge, // purge this goal next time we process
|
||||
Purge_when_new_goal_added, // this goal is perpetual until any other goal is added, at which time it sets its own Purge flag
|
||||
Goals_purged, // this goal has already caused other goals to get purged (because it is something like ai-disarm that renders other goals invalid)
|
||||
Goals_purged, // this goal has already caused other goals to get purged
|
||||
Depart_sound_played,// Goober5000 - replacement for AL's hack ;)
|
||||
Target_own_team, // this attack goal is allowed to target friendlies
|
||||
Afterburn_hard, // afterburn as hard as possible to the goal
|
||||
Waypoints_in_reverse, // decrement instead of increment
|
||||
Clear_all_goals_first, // this goal wipes all goals (including itself) before it runs (handled separately, and in a different place, from purging invalid goals)
|
||||
|
||||
NUM_VALUES
|
||||
};
|
||||
@@ -132,7 +129,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,
|
||||
@@ -146,7 +142,6 @@ namespace AI {
|
||||
Fightercraft_nonshielded_ships_can_manage_ets,
|
||||
Ships_playing_dead_dont_manage_ets,
|
||||
Better_combat_collision_avoidance,
|
||||
Better_combat_collision_avoid_includes_target,
|
||||
Better_guard_collision_avoidance,
|
||||
Require_exact_los,
|
||||
Improved_missile_avoidance,
|
||||
@@ -175,11 +170,6 @@ namespace AI {
|
||||
Debris_respects_big_damage,
|
||||
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 skips ships outside the attacker's actively-pursues list, and self-chosen targets
|
||||
// outside that list are dropped rather than held forever
|
||||
Standard_strafe_used_more,
|
||||
Unify_usage_ai_shield_manage_delay,
|
||||
Fix_AI_shield_management_bug,
|
||||
@@ -188,18 +178,6 @@ namespace AI {
|
||||
Freespace_1_missile_behavior,
|
||||
ETS_uses_power_output,
|
||||
ETS_energy_same_regardless_of_system_presence,
|
||||
Dont_form_on_wing_at_mission_start,
|
||||
Do_not_clear_goals_when_running_form_on_wing,
|
||||
Do_not_clear_goals_when_running_stay_still,
|
||||
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
|
||||
|
||||
NUM_VALUES
|
||||
};
|
||||
|
||||
+1
-75
@@ -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*);
|
||||
@@ -478,9 +477,6 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
|
||||
set_flag(profile, "$support don't add primaries:", AI::Profile_Flags::Support_dont_add_primaries);
|
||||
|
||||
if (optional_string("$max allies rearming threshold:"))
|
||||
stuff_int(&profile->max_allies_rearming_threshold);
|
||||
|
||||
set_flag(profile, "$firing requires exact los:", AI::Profile_Flags::Require_exact_los);
|
||||
|
||||
if (optional_string("$exact los minimum detection radius:")) {
|
||||
@@ -592,8 +588,6 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
stuff_float(&profile->better_collision_avoid_aggression_combat);
|
||||
}
|
||||
|
||||
set_flag(profile, "+combat collision avoidance for fightercraft includes target:", AI::Profile_Flags::Better_combat_collision_avoid_includes_target);
|
||||
|
||||
set_flag(profile, "$better guard collision avoidance for fightercraft:", AI::Profile_Flags::Better_guard_collision_avoidance);
|
||||
|
||||
if (optional_string("+guard collision avoidance aggression for fightercraft:")) {
|
||||
@@ -675,10 +669,6 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
|
||||
set_flag(profile, "$fix avoid-shockwave bugs:", AI::Profile_Flags::Fix_avoid_shockwave_bugs);
|
||||
|
||||
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 +683,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);
|
||||
}
|
||||
@@ -715,10 +697,6 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
}
|
||||
}
|
||||
|
||||
if (optional_string("$attack-any idle circle distance:")) {
|
||||
stuff_float(&profile->attack_any_idle_circle_distance);
|
||||
}
|
||||
|
||||
set_flag(profile, "$unify usage of AI Shield Manage Delay:", AI::Profile_Flags::Unify_usage_ai_shield_manage_delay);
|
||||
|
||||
set_flag(profile, "$fix AI shield management bug:", AI::Profile_Flags::Fix_AI_shield_management_bug);
|
||||
@@ -733,39 +711,6 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
|
||||
set_flag(profile, "$ETS energy same regardless of system presence:", AI::Profile_Flags::ETS_energy_same_regardless_of_system_presence);
|
||||
|
||||
set_flag(profile, "$don't issue form-on-wing goals at mission start:", AI::Profile_Flags::Dont_form_on_wing_at_mission_start);
|
||||
|
||||
if (optional_string("$default form-on-wing priority:")) {
|
||||
int priority;
|
||||
stuff_int(&priority);
|
||||
if (priority > 0) {
|
||||
profile->default_form_on_wing_priority = priority;
|
||||
} else {
|
||||
mprintf(("Warning: $default form-on-wing priority: should be > 0 (read %d). Value will not be used.\n", priority));
|
||||
}
|
||||
}
|
||||
|
||||
set_flag(profile, "$do not clear goals when running form-on-wing:", AI::Profile_Flags::Do_not_clear_goals_when_running_form_on_wing);
|
||||
|
||||
set_flag(profile, "$do not clear goals when running stay-still:", AI::Profile_Flags::Do_not_clear_goals_when_running_stay_still);
|
||||
|
||||
set_flag(profile, "$do not set override when assigning form-on-wing:", AI::Profile_Flags::Do_not_set_override_when_assigning_form_on_wing);
|
||||
|
||||
set_flag(profile, "$purge player-issued form-on-wing after subsequent order:", AI::Profile_Flags::Purge_player_issued_form_on_wing_after_subsequent_order);
|
||||
|
||||
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);
|
||||
|
||||
// end of options ----------------------------------------
|
||||
|
||||
@@ -834,7 +779,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))
|
||||
@@ -858,7 +803,6 @@ void ai_profile_t::reset()
|
||||
ai_range_aware_secondary_select_mode = AI_RANGE_AWARE_SEC_SEL_MODE_RETAIL;
|
||||
turret_target_recheck_time = 2000.0f;
|
||||
rot_fac_multiplier_ply_collisions = 0.0f;
|
||||
max_allies_rearming_threshold = 2;
|
||||
|
||||
better_collision_avoid_aggression_combat = 3.5f;
|
||||
better_collision_avoid_aggression_guard = 3.5f;
|
||||
@@ -866,14 +810,9 @@ 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;
|
||||
attack_any_idle_circle_distance = 100.0f;
|
||||
|
||||
default_form_on_wing_priority = 99; // as originally assigned in ai_add_goal_sub_sexp()
|
||||
|
||||
for (int i = 0; i < NUM_SKILL_LEVELS; ++i) {
|
||||
max_incoming_asteroids[i] = 0;
|
||||
@@ -988,18 +927,5 @@ void ai_profile_t::reset()
|
||||
}
|
||||
if (mod_supports_version(25, 0, 0)) {
|
||||
flags.set(AI::Profile_Flags::Fix_avoid_shockwave_bugs);
|
||||
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);
|
||||
}
|
||||
}
|
||||
+2
-13
@@ -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
|
||||
@@ -102,9 +101,6 @@ public:
|
||||
|
||||
float detail_distance_mult[MAX_DETAIL_VALUE + 1]; //MAX_DETAIL_VALUE really needs to be 4
|
||||
|
||||
// max number of allies allowed to be rearming at the same time
|
||||
int max_allies_rearming_threshold;
|
||||
|
||||
// minimum radius for the line-of-sight (los) detection --wookieejedi
|
||||
float los_min_detection_radius;
|
||||
|
||||
@@ -143,18 +139,11 @@ 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()
|
||||
float guard_big_orbit_max_speed_percent; // Max percent of forward speed that is used in ai_big_guard()
|
||||
|
||||
// AI attack any option --wookieejedi
|
||||
float attack_any_idle_circle_distance; // Radius that AI circles around a point while waiting for new enemies in attack-any mode
|
||||
|
||||
int default_form_on_wing_priority; // the priority used if not specified in the sexp
|
||||
|
||||
void reset();
|
||||
};
|
||||
|
||||
@@ -163,10 +152,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
|
||||
+84
-110
@@ -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
|
||||
|
||||
@@ -59,9 +62,9 @@
|
||||
void ai_big_evade_ship();
|
||||
void ai_big_chase_attack(ai_info *aip, ship_info *sip, vec3d *enemy_pos, float dist_to_enemy, int modelnum);
|
||||
void ai_big_avoid_ship();
|
||||
bool ai_big_maybe_follow_subsys_path(bool do_dot_check=true);
|
||||
int ai_big_maybe_follow_subsys_path(int do_dot_check=1);
|
||||
void ai_big_strafe_position();
|
||||
static bool ai_big_strafe_maybe_retreat(const vec3d *target_pos);
|
||||
static int 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);
|
||||
@@ -143,10 +146,6 @@ done_1:
|
||||
|
||||
*attack_point = best_point;
|
||||
|
||||
//The following raycast tends to make up 10%(!) of total AI-frametime for basically no benefit, especially in the common case for turrets where the normal isn't even queried.
|
||||
if (surface_normal == nullptr && Disable_expensive_turret_target_check)
|
||||
return;
|
||||
|
||||
// Cast from attack_objp_pos to local_attack_pos and check for nearest collision.
|
||||
// If no collision, cast to (0,0,0) [center of big ship]** [best_point initialized to 000]
|
||||
|
||||
@@ -348,10 +347,10 @@ void ai_big_subsys_path_cleanup(ai_info *aip)
|
||||
}
|
||||
|
||||
// Maybe Pl_objp needs to follow a path to get in line-of-sight to a subsystem
|
||||
// input: do_dot_check => default value true, flag to indicate whether check should be done to ensure
|
||||
// input: do_dot_check => default value 0, flag to indicate whether check should be done to ensure
|
||||
// subsystem is within certain field of view. We don't want to check fov when
|
||||
// strafing, since ship is weaving to avoid turret fire
|
||||
bool ai_big_maybe_follow_subsys_path(bool do_dot_check)
|
||||
int ai_big_maybe_follow_subsys_path(int do_dot_check)
|
||||
{
|
||||
ai_info *aip;
|
||||
float dot = 1.0f, min_dot;
|
||||
@@ -865,7 +864,7 @@ void ai_big_chase_ct()
|
||||
extern bool ai_select_secondary_weapon(object *objp, ship_weapon *swp, int priority1 = -1, int priority2 = -1);
|
||||
extern float set_secondary_fire_delay(ai_info *aip, ship *shipp, weapon_info *swip, bool burst);
|
||||
extern bool ai_choose_secondary_weapon(object *objp, ai_info *aip, object *en_objp);
|
||||
extern bool maybe_avoid_big_ship(object *objp, object *ignore_objp, ai_info *aip, vec3d *goal_point, float delta_time, float time_scale = 1.f);
|
||||
extern int maybe_avoid_big_ship(object *objp, object *ignore_objp, ai_info *aip, vec3d *goal_point, float delta_time, float time_scale = 1.f);
|
||||
|
||||
extern void maybe_cheat_fire_synaptic(object *objp);
|
||||
|
||||
@@ -1195,78 +1194,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) {
|
||||
@@ -1425,7 +1416,7 @@ void ai_big_attack_get_data(vec3d *enemy_pos, float *dist_to_enemy, float *dot_t
|
||||
|
||||
// check to see if Pl_objp has gotten too close to attacking point.. if so, break off by entering
|
||||
// AIS_STRAFE_RETREAT
|
||||
static bool ai_big_strafe_maybe_retreat(const vec3d *target_pos)
|
||||
static int ai_big_strafe_maybe_retreat(const vec3d *target_pos)
|
||||
{
|
||||
ai_info *aip;
|
||||
aip = &Ai_info[Ships[Pl_objp->instance].ai_index];
|
||||
@@ -1433,42 +1424,25 @@ static bool ai_big_strafe_maybe_retreat(const vec3d *target_pos)
|
||||
vec3d vec_to_target;
|
||||
vm_vec_sub(&vec_to_target, target_pos, &Pl_objp->pos);
|
||||
|
||||
float dist_to_target = vm_vec_mag(&vec_to_target);
|
||||
float dist_to_target, dist_normal_to_target, time_to_target;
|
||||
dist_to_target = vm_vec_mag_quick(&vec_to_target);
|
||||
if (vm_vec_mag_quick(&aip->big_attack_surface_normal) > 0.9) {
|
||||
dist_normal_to_target = -vm_vec_dot(&vec_to_target, &aip->big_attack_surface_normal);
|
||||
} else {
|
||||
dist_normal_to_target = 0.2f * vm_vec_mag_quick(&vec_to_target);
|
||||
}
|
||||
|
||||
dist_normal_to_target = MAX(0.2f*dist_to_target, dist_normal_to_target);
|
||||
time_to_target = dist_normal_to_target / Pl_objp->phys_info.speed;
|
||||
|
||||
// add distance penalty for going too fast
|
||||
float speed_to_dist_penalty = MAX(0.0f, (Pl_objp->phys_info.speed-50));
|
||||
|
||||
bool collide_time;
|
||||
bool collide_distance;
|
||||
if (The_mission.ai_profile->flags[AI::Profile_Flags::Fix_standard_strafe]) {
|
||||
// check if ship facing target, as likely will only collide if facing
|
||||
vec3d vec_to_tpos;
|
||||
vm_vec_normalized_dir(&vec_to_tpos, target_pos, &Pl_objp->pos);
|
||||
float dot = vm_vec_dot(&vec_to_tpos, &Pl_objp->orient.vec.fvec);
|
||||
if (dot <= 0.0f) {
|
||||
collide_time = false;
|
||||
collide_distance = false;
|
||||
} else {
|
||||
collide_time = (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);
|
||||
}
|
||||
} else {
|
||||
float dist_normal_to_target;
|
||||
if (vm_vec_mag(&aip->big_attack_surface_normal) > 0.9) {
|
||||
dist_normal_to_target =
|
||||
MAX(0.2f * dist_to_target, -vm_vec_dot(&vec_to_target, &aip->big_attack_surface_normal));
|
||||
} else {
|
||||
dist_normal_to_target = 0.2f * dist_to_target;
|
||||
}
|
||||
collide_time = (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);
|
||||
}
|
||||
|
||||
//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))
|
||||
|
||||
// Inside 2 sec retreat, setting goal point to box point + strafe_retreat_box_dist
|
||||
// If collision, use std collision resolution.
|
||||
if ( !(aip->ai_flags[AI::AI_Flags::Kamikaze]) && ((aip->ai_flags[AI::AI_Flags::Target_collision]) || (collide_time) || (collide_distance)) ) {
|
||||
if ( !(aip->ai_flags[AI::AI_Flags::Kamikaze]) && ((aip->ai_flags[AI::AI_Flags::Target_collision]) || (time_to_target < STRAFE_RETREAT_COLLIDE_TIME) || (dist_normal_to_target < STRAFE_RETREAT_COLLIDE_DIST + speed_to_dist_penalty)) ) {
|
||||
if (aip->ai_flags[AI::AI_Flags::Target_collision]) {
|
||||
// use standard collision resolution
|
||||
aip->ai_flags.remove(AI::AI_Flags::Target_collision);
|
||||
@@ -1512,7 +1486,7 @@ void ai_big_strafe_attack()
|
||||
if (aip->ai_profile_flags[AI::Profile_Flags::Improved_subsystem_attack_pathing]) {
|
||||
if (ai_new_maybe_reposition_attack_subsys())
|
||||
return;
|
||||
} else if (ai_big_maybe_follow_subsys_path(false))
|
||||
} else if (ai_big_maybe_follow_subsys_path(0))
|
||||
return;
|
||||
|
||||
ai_big_attack_get_data(&target_pos, &target_dist, &target_dot);
|
||||
@@ -1632,7 +1606,7 @@ void ai_big_strafe_glide_attack()
|
||||
if (aip->ai_profile_flags[AI::Profile_Flags::Improved_subsystem_attack_pathing]) {
|
||||
if (ai_new_maybe_reposition_attack_subsys())
|
||||
return;
|
||||
} else if (ai_big_maybe_follow_subsys_path(false))
|
||||
} else if (ai_big_maybe_follow_subsys_path(0))
|
||||
return;
|
||||
|
||||
//Gets a point on the target ship to attack, as well as distance and the angle between the nose of the attacker and that point.
|
||||
|
||||
+116
-424
File diff suppressed because it is too large.
Load diff
Whitespace-only changes.
+116
-274
@@ -40,43 +40,28 @@ struct ship_registry_entry;
|
||||
// dynamic goals are not handled here.
|
||||
|
||||
// defines for player issued goal priorities
|
||||
constexpr int PLAYER_PRIORITY_MIN = 90;
|
||||
constexpr int PLAYER_PRIORITY_SHIP = 100;
|
||||
constexpr int PLAYER_PRIORITY_WING = 95;
|
||||
constexpr int PLAYER_PRIORITY_SUPPORT_LOW = 10;
|
||||
#define PLAYER_PRIORITY_MIN 90
|
||||
#define PLAYER_PRIORITY_SHIP 100
|
||||
#define PLAYER_PRIORITY_WING 95
|
||||
#define PLAYER_PRIORITY_SUPPORT_LOW 10
|
||||
|
||||
constexpr int MAX_GOAL_PRIORITY = 200;
|
||||
constexpr int MIN_GOAL_PRIORITY = 1;
|
||||
|
||||
|
||||
// note: "purging" is not the same as "clearing" here
|
||||
// purging: any goal that no longer makes sense (i.e. is "invalid") in light of a new goal is removed
|
||||
// clearing: every goal is removed, including, ironically, the goal that caused the clearing
|
||||
#define MAX_GOAL_PRIORITY 200
|
||||
|
||||
// define for which goals cause other goals to get purged
|
||||
// Goober5000 - okay, this seems really stupid. If any ship in the mission is assigned a goal
|
||||
// in PURGE_GOALS_ALL_SHIPS, *every* other ship will have certain goals purged. So I added
|
||||
// PURGE_GOALS_ONE_SHIP for goals which should only purge other goals in the one ship.
|
||||
// Goober5000 - note that the new disable and disarm goals (AI_GOAL_DISABLE_SHIP_TACTICAL and
|
||||
// AI_GOAL_DISARM_SHIP_TACTICAL) do not purge ANY goals, not even the ones in the one ship
|
||||
[[nodiscard]] bool causes_invalid_goal_purge_all_ships(ai_goal_mode ai_mode)
|
||||
inline bool purge_goals_all_ships(ai_goal_mode ai_mode)
|
||||
{
|
||||
return ai_mode == AI_GOAL_IGNORE || ai_mode == AI_GOAL_DISABLE_SHIP || ai_mode == AI_GOAL_DISARM_SHIP;
|
||||
}
|
||||
[[nodiscard]] bool causes_invalid_goal_purge_one_ship(ai_goal_mode ai_mode)
|
||||
inline bool purge_goals_one_ship(ai_goal_mode ai_mode)
|
||||
{
|
||||
return ai_mode == AI_GOAL_IGNORE_NEW;
|
||||
}
|
||||
|
||||
// function for which goals cause other goals to be cleared -- see comments above on purging vs clearing
|
||||
// NOTE: this function is only evaluated in ai_add_goal_sub_player() and ai_add_goal_sub_scripting(); for
|
||||
// ai_add_goal_sub_sexp(), the goal clearing is integrated into the logic of the relevant sexp operators
|
||||
[[nodiscard]] bool causes_goal_clearing(ai_goal_mode ai_mode)
|
||||
{
|
||||
return ((ai_mode == AI_GOAL_STAY_STILL && !The_mission.ai_profile->flags[AI::Profile_Flags::Do_not_clear_goals_when_running_stay_still])
|
||||
|| (ai_mode == AI_GOAL_FORM_ON_WING && !The_mission.ai_profile->flags[AI::Profile_Flags::Do_not_clear_goals_when_running_form_on_wing])
|
||||
|| (ai_mode == AI_GOAL_PLAY_DEAD));
|
||||
}
|
||||
|
||||
// goals given from the player to other ships in the game are also handled in this
|
||||
// code
|
||||
|
||||
@@ -115,7 +100,6 @@ ai_goal_list Ai_goal_names[] =
|
||||
{ "Attack weapon", AI_GOAL_CHASE_WEAPON, 0 },
|
||||
{ "Fly to ship", AI_GOAL_FLY_TO_SHIP, 0 },
|
||||
{ "Attack ship class", AI_GOAL_CHASE_SHIP_CLASS, 0 },
|
||||
{ "Attack ship type", AI_GOAL_CHASE_SHIP_TYPE, 0 },
|
||||
};
|
||||
|
||||
int Num_ai_goals = sizeof(Ai_goal_names) / sizeof(ai_goal_list);
|
||||
@@ -130,7 +114,6 @@ const char *Ai_goal_text(ai_goal_mode goal, int submode)
|
||||
case AI_GOAL_CHASE:
|
||||
case AI_GOAL_CHASE_WING:
|
||||
case AI_GOAL_CHASE_SHIP_CLASS:
|
||||
case AI_GOAL_CHASE_SHIP_TYPE:
|
||||
return XSTR( "attack ", 474);
|
||||
case AI_GOAL_DOCK:
|
||||
return XSTR( "dock ", 475);
|
||||
@@ -212,15 +195,12 @@ void ai_maybe_add_form_goal(wing* wingp)
|
||||
return;
|
||||
}
|
||||
|
||||
// we may simply not want the mission to do this
|
||||
if (The_mission.ai_profile->flags[AI::Profile_Flags::Dont_form_on_wing_at_mission_start]) {
|
||||
return;
|
||||
}
|
||||
int j;
|
||||
|
||||
// iterate through the ship_index list of this wing and check for orders. We will do
|
||||
// this for all ships in the wing instead of on a wing only basis in case some ships
|
||||
// in the wing actually have different orders than others
|
||||
for (int j = 0; j < wingp->current_count; j++) {
|
||||
for (j = 0; j < wingp->current_count; j++) {
|
||||
ai_info* aip;
|
||||
|
||||
Assert(wingp->ship_index[j] != -1); // get Allender
|
||||
@@ -232,8 +212,7 @@ void ai_maybe_add_form_goal(wing* wingp)
|
||||
}
|
||||
|
||||
// need to add a form on my wing goal here. Ships are always forming on the player's wing.
|
||||
// it is sufficient enough to check the first goal entry to see if it has a valid goal.
|
||||
// Note: Although the player didn't explicitly order this, it is treated as a player-issued order
|
||||
// it is sufficient enough to check the first goal entry to see if it has a valid goal
|
||||
if (aip->goals[0].ai_mode == AI_GOAL_NONE) {
|
||||
// Need to have a more specific target in multi, or they may end up trying to target standalone placeholder.
|
||||
// So form on their team leader. In dogfight, all player-slot ai die, so just exclude.
|
||||
@@ -534,25 +513,13 @@ void ai_goal_purge_invalid_goals( ai_goal *aigp, ai_goal *goal_list, ai_info *ai
|
||||
if ( purge_goal->target_name == NULL )
|
||||
continue;
|
||||
|
||||
// goals operating on ship classes and ship types are handled slightly differently
|
||||
// goals operating on ship classes are handled slightly differently
|
||||
if ( purge_ai_mode == AI_GOAL_CHASE_SHIP_CLASS ) {
|
||||
// if the target of the purge goal is the same class of ship we are concerned about, then we have a match;
|
||||
// if it is not, then we can continue (see standard ship check below)
|
||||
if ( stricmp(purge_goal->target_name, Ship_info[Ships[ship_index].ship_info_index].name) != 0 )
|
||||
continue;
|
||||
}
|
||||
else if (purge_ai_mode == AI_GOAL_CHASE_SHIP_TYPE) {
|
||||
// Get the ship type of the ship we're concerned about
|
||||
int ship_type = Ship_info[Ships[ship_index].ship_info_index].class_type;
|
||||
|
||||
// If the ship type is invalid, we can't match it, so continue
|
||||
if (ship_type < 0)
|
||||
continue;
|
||||
|
||||
// Check if the target name of the purge goal matches the ship type name
|
||||
if (stricmp(purge_goal->target_name, Ship_types[ship_type].name) != 0)
|
||||
continue;
|
||||
}
|
||||
// standard goals operating on either wings or ships
|
||||
else {
|
||||
// determine if the purge goal is acting either on the ship or the ship's wing.
|
||||
@@ -621,8 +588,8 @@ void ai_goal_purge_all_invalid_goals(ai_goal *aigp)
|
||||
int i;
|
||||
ship_obj *sop;
|
||||
|
||||
// only purge goals if a new goal is one of the types that require purging
|
||||
if (!causes_invalid_goal_purge_all_ships(aigp->ai_mode))
|
||||
// only purge goals if a new goal is one of the types in next statement
|
||||
if (!purge_goals_all_ships(aigp->ai_mode))
|
||||
return;
|
||||
|
||||
for (sop = GET_FIRST(&Ship_obj_list); sop != END_OF_LIST(&Ship_obj_list); sop = GET_NEXT(sop))
|
||||
@@ -765,14 +732,12 @@ void ai_goal_fixup_dockpoints(ai_info *aip, ai_goal *aigp)
|
||||
// from the mission goals (i.e. those goals which come from events) in that we don't
|
||||
// use sexpressions for goals from the player...so we enumerate all the parameters
|
||||
|
||||
void ai_add_goal_sub_player(ai_goal_type type, ai_goal_mode mode, int submode, const char *target_name, ai_goal *aigp, int int_data, float float_data, const ai_lua_parameters& lua_target )
|
||||
void ai_add_goal_sub_player(ai_goal_type type, ai_goal_mode mode, int submode, const char *target_name, ai_goal *aigp, const ai_lua_parameters& lua_target )
|
||||
{
|
||||
Assert ( (type == ai_goal_type::PLAYER_WING) || (type == ai_goal_type::PLAYER_SHIP) );
|
||||
|
||||
ai_goal_reset(aigp, true, mode, submode, type);
|
||||
|
||||
aigp->int_data = int_data;
|
||||
aigp->float_data = float_data;
|
||||
aigp->lua_ai_target = lua_target;
|
||||
|
||||
if ( mode == AI_GOAL_WARP ) {
|
||||
@@ -790,18 +755,6 @@ void ai_add_goal_sub_player(ai_goal_type type, ai_goal_mode mode, int submode, c
|
||||
if ( target_name != NULL )
|
||||
aigp->target_name = ai_get_goal_target_name( target_name, &aigp->target_name_index );
|
||||
|
||||
// set up the clear-goals flag for certain goals
|
||||
if (causes_goal_clearing(mode))
|
||||
aigp->flags.set(AI::Goal_Flags::Clear_all_goals_first);
|
||||
|
||||
// also set up the override, since it's no longer done automatically in ai_mission_goal_achievable
|
||||
if (mode == AI_GOAL_FORM_ON_WING && !The_mission.ai_profile->flags[AI::Profile_Flags::Do_not_set_override_when_assigning_form_on_wing])
|
||||
aigp->flags.set(AI::Goal_Flags::Want_override);
|
||||
|
||||
// generally, players want ships to form-on-wing only until they need to do something else
|
||||
if (mode == AI_GOAL_FORM_ON_WING && The_mission.ai_profile->flags[AI::Profile_Flags::Purge_player_issued_form_on_wing_after_subsequent_order])
|
||||
aigp->flags.set(AI::Goal_Flags::Purge_when_new_goal_added);
|
||||
|
||||
if (The_mission.ai_profile->flags[AI::Profile_Flags::Player_orders_afterburn_hard])
|
||||
aigp->flags.set(AI::Goal_Flags::Afterburn_hard);
|
||||
|
||||
@@ -813,6 +766,10 @@ void ai_add_goal_sub_player(ai_goal_type type, ai_goal_mode mode, int submode, c
|
||||
if ( (mode == AI_GOAL_STAY_NEAR_SHIP) || (mode == AI_GOAL_KEEP_SAFE_DISTANCE) )
|
||||
aigp->priority = PLAYER_PRIORITY_SUPPORT_LOW;
|
||||
|
||||
// Goober5000 - same with form-on-wing, since it's a type of staying near
|
||||
else if ( mode == AI_GOAL_FORM_ON_WING )
|
||||
aigp->priority = PLAYER_PRIORITY_SUPPORT_LOW;
|
||||
|
||||
else if ( aigp->type == ai_goal_type::PLAYER_WING ) // NOLINT(readability-braces-around-statements)
|
||||
aigp->priority = PLAYER_PRIORITY_WING; // player wing goals not as high as ship goals
|
||||
else
|
||||
@@ -825,25 +782,19 @@ 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;
|
||||
int gindex, oldest_index;
|
||||
|
||||
for ( int gindex = 0; gindex < MAX_AI_GOALS; gindex++ )
|
||||
oldest_index = -1;
|
||||
for ( gindex = 0; gindex < MAX_AI_GOALS; gindex++ )
|
||||
{
|
||||
// get the index for the first unused goal
|
||||
if (goals[gindex].ai_mode == AI_GOAL_NONE)
|
||||
{
|
||||
if (first_empty_index < 0)
|
||||
first_empty_index = gindex;
|
||||
}
|
||||
// if any goal needs to be purged when we add a goal, set the flag
|
||||
else if (goals[gindex].flags[AI::Goal_Flags::Purge_when_new_goal_added])
|
||||
goals[gindex].flags.set(AI::Goal_Flags::Purge);
|
||||
return gindex;
|
||||
|
||||
// if this is the active goal, and a real goal, don't consider it for pre-emption!!
|
||||
if (gindex == active_goal && goals[gindex].ai_mode != AI_GOAL_NONE)
|
||||
// if this is the active goal, don't consider it for pre-emption!!
|
||||
if (gindex == active_goal)
|
||||
continue;
|
||||
|
||||
// store the index of the oldest goal
|
||||
@@ -853,10 +804,6 @@ int ai_goal_allocate_slot( ai_goal *goals, int active_goal )
|
||||
oldest_index = gindex;
|
||||
}
|
||||
|
||||
// try to use the first empty slot
|
||||
if (first_empty_index >= 0)
|
||||
return first_empty_index;
|
||||
|
||||
// if we didn't find an empty slot, use the oldest goal's slot
|
||||
return oldest_index;
|
||||
}
|
||||
@@ -889,26 +836,9 @@ void ai_add_goal_sub_scripting(ai_goal_type type, ai_goal_mode mode, int submode
|
||||
if ( target_name != NULL )
|
||||
aigp->target_name = ai_get_goal_target_name( target_name, &aigp->target_name_index );
|
||||
|
||||
// set up the clear-goals flag for certain goals
|
||||
if (causes_goal_clearing(mode))
|
||||
aigp->flags.set(AI::Goal_Flags::Clear_all_goals_first);
|
||||
|
||||
// also set up the override, since it's no longer done automatically in ai_mission_goal_achievable
|
||||
if (mode == AI_GOAL_FORM_ON_WING && !The_mission.ai_profile->flags[AI::Profile_Flags::Do_not_set_override_when_assigning_form_on_wing])
|
||||
aigp->flags.set(AI::Goal_Flags::Want_override);
|
||||
|
||||
aigp->priority = priority;
|
||||
aigp->int_data = int_data;
|
||||
aigp->float_data = float_data;
|
||||
|
||||
// range check
|
||||
if ( aigp->priority > MAX_GOAL_PRIORITY ) {
|
||||
nprintf (("AI", "bashing scripting priority of goal %d from %d to %d.\n", mode, aigp->priority, MAX_GOAL_PRIORITY));
|
||||
aigp->priority = MAX_GOAL_PRIORITY;
|
||||
} else if ( aigp->priority < MIN_GOAL_PRIORITY ) {
|
||||
nprintf (("AI", "bashing scripting priority of goal %d from %d to %d.\n", mode, aigp->priority, MIN_GOAL_PRIORITY));
|
||||
aigp->priority = MIN_GOAL_PRIORITY;
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -916,7 +846,7 @@ void ai_add_ship_goal_scripting(ai_goal_mode mode, int submode, int priority, co
|
||||
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);
|
||||
|
||||
@@ -935,14 +865,14 @@ void ai_add_ship_goal_scripting(ai_goal_mode mode, int submode, int priority, co
|
||||
// is issued to ship or wing (from player), mode is AI_GOAL_*. submode is the submode the
|
||||
// ship should go into. shipname is the object of the action. aip is the ai_info pointer
|
||||
// of the ship receiving the order
|
||||
void ai_add_ship_goal_player(ai_goal_type type, ai_goal_mode mode, int submode, const char *shipname, ai_info *aip, int int_data, float float_data, const ai_lua_parameters& lua_target)
|
||||
void ai_add_ship_goal_player(ai_goal_type type, ai_goal_mode mode, int submode, const char *shipname, ai_info *aip, const ai_lua_parameters& lua_target)
|
||||
{
|
||||
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 );
|
||||
ai_add_goal_sub_player( type, mode, submode, shipname, aigp, lua_target );
|
||||
|
||||
// if the goal is to dock, then we must determine which dock points on the two ships to use.
|
||||
// If the target of the dock is a cargo type container, then we should use DOCK_TYPE_CARGO
|
||||
@@ -956,7 +886,7 @@ void ai_add_ship_goal_player(ai_goal_type type, ai_goal_mode mode, int submode,
|
||||
|
||||
// adds a goal from the player to the given wing (which in turn will add it to the proper
|
||||
// ships in the wing
|
||||
void ai_add_wing_goal_player(ai_goal_type type, ai_goal_mode mode, int submode, const char *shipname, int wingnum, int int_data, float float_data, const ai_lua_parameters& lua_target)
|
||||
void ai_add_wing_goal_player(ai_goal_type type, ai_goal_mode mode, int submode, const char *shipname, int wingnum, const ai_lua_parameters& lua_target)
|
||||
{
|
||||
int i, empty_index;
|
||||
wing *wingp = &Wings[wingnum];
|
||||
@@ -967,15 +897,15 @@ void ai_add_wing_goal_player(ai_goal_type type, ai_goal_mode mode, int submode,
|
||||
int num = wingp->ship_index[i];
|
||||
if ( num == -1 ) // ship must have been destroyed or departed
|
||||
continue;
|
||||
ai_add_ship_goal_player( type, mode, submode, shipname, &Ai_info[Ships[num].ai_index], int_data, float_data, lua_target );
|
||||
ai_add_ship_goal_player( type, mode, submode, shipname, &Ai_info[Ships[num].ai_index], lua_target );
|
||||
}
|
||||
}
|
||||
|
||||
// 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 );
|
||||
ai_add_goal_sub_player( type, mode, submode, shipname, &wingp->ai_goals[empty_index], int_data, float_data, lua_target );
|
||||
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], lua_target );
|
||||
}
|
||||
|
||||
|
||||
@@ -1008,9 +938,11 @@ void ai_add_goal_sub_sexp( int sexp, ai_goal_type type, ai_info *aip, ai_goal *a
|
||||
// for achievability.
|
||||
aigp->target_name = ai_get_goal_target_name(CTEXT(CDR(node)), &aigp->target_name_index); // waypoint path name;
|
||||
|
||||
aigp->priority = eval_num(CDDR(node), priority_is_nan, priority_is_nan_forever);
|
||||
aigp->ai_mode = (op == OP_AI_WAYPOINTS_ONCE) ? AI_GOAL_WAYPOINTS_ONCE : AI_GOAL_WAYPOINTS;
|
||||
|
||||
aigp->priority = eval_num(CDDR(node), priority_is_nan, priority_is_nan_forever);
|
||||
aigp->ai_mode = AI_GOAL_WAYPOINTS;
|
||||
if ( op == OP_AI_WAYPOINTS_ONCE )
|
||||
aigp->ai_mode = AI_GOAL_WAYPOINTS_ONCE;
|
||||
if (CDDDDR(node) < 0)
|
||||
aigp->int_data = 0; // handle optional node separately because we don't subtract 1 here
|
||||
else
|
||||
@@ -1089,27 +1021,10 @@ void ai_add_goal_sub_sexp( int sexp, ai_goal_type type, ai_info *aip, ai_goal *a
|
||||
}
|
||||
|
||||
case OP_AI_STAY_STILL:
|
||||
{
|
||||
int n = CDR(node);
|
||||
|
||||
aigp->target_name = ai_get_goal_target_name(CTEXT(n), &aigp->target_name_index); // waypoint path name;
|
||||
n = CDR(n);
|
||||
|
||||
aigp->priority = eval_num(n, priority_is_nan, priority_is_nan_forever);
|
||||
n = CDR(n);
|
||||
|
||||
bool clear_goals = !The_mission.ai_profile->flags[AI::Profile_Flags::Do_not_clear_goals_when_running_stay_still];
|
||||
if (n >= 0)
|
||||
{
|
||||
clear_goals = is_sexp_true(n);
|
||||
n = CDR(n);
|
||||
}
|
||||
if (clear_goals)
|
||||
aigp->flags.set(AI::Goal_Flags::Clear_all_goals_first);
|
||||
|
||||
aigp->ai_mode = AI_GOAL_STAY_STILL;
|
||||
aigp->target_name = ai_get_goal_target_name(CTEXT(CDR(node)), &aigp->target_name_index); // waypoint path name;
|
||||
aigp->priority = eval_num(CDDR(node), priority_is_nan, priority_is_nan_forever);
|
||||
break;
|
||||
}
|
||||
|
||||
case OP_AI_DOCK:
|
||||
aigp->target_name = ai_get_goal_target_name( CTEXT(CDR(node)), &aigp->target_name_index );
|
||||
@@ -1127,12 +1042,13 @@ void ai_add_goal_sub_sexp( int sexp, ai_goal_type type, ai_info *aip, ai_goal *a
|
||||
break;
|
||||
|
||||
case OP_AI_PLAY_DEAD:
|
||||
// we don't clear out ship goals for the "persistent" goal variant
|
||||
aigp->flags.set(AI::Goal_Flags::Clear_all_goals_first);
|
||||
FALLTHROUGH;
|
||||
aigp->priority = eval_num(CDR(node), priority_is_nan, priority_is_nan_forever);
|
||||
aigp->ai_mode = AI_GOAL_PLAY_DEAD;
|
||||
break;
|
||||
|
||||
case OP_AI_PLAY_DEAD_PERSISTENT:
|
||||
aigp->priority = eval_num(CDR(node), priority_is_nan, priority_is_nan_forever);
|
||||
aigp->ai_mode = (op == OP_AI_PLAY_DEAD) ? AI_GOAL_PLAY_DEAD : AI_GOAL_PLAY_DEAD_PERSISTENT;
|
||||
aigp->ai_mode = AI_GOAL_PLAY_DEAD_PERSISTENT;
|
||||
break;
|
||||
|
||||
case OP_AI_KEEP_SAFE_DISTANCE:
|
||||
@@ -1168,53 +1084,14 @@ void ai_add_goal_sub_sexp( int sexp, ai_goal_type type, ai_info *aip, ai_goal *a
|
||||
}
|
||||
|
||||
case OP_AI_FORM_ON_WING:
|
||||
{
|
||||
int n = CDR(node);
|
||||
|
||||
aigp->target_name = ai_get_goal_target_name(CTEXT(n), &aigp->target_name_index);
|
||||
n = CDR(n);
|
||||
|
||||
if (n >= 0)
|
||||
{
|
||||
aigp->priority = eval_num(n, priority_is_nan, priority_is_nan_forever);
|
||||
n = CDR(n);
|
||||
}
|
||||
else
|
||||
aigp->priority = The_mission.ai_profile->default_form_on_wing_priority;
|
||||
|
||||
bool clear_goals = !The_mission.ai_profile->flags[AI::Profile_Flags::Do_not_clear_goals_when_running_form_on_wing];
|
||||
if (n >= 0)
|
||||
{
|
||||
clear_goals = is_sexp_true(n);
|
||||
n = CDR(n);
|
||||
}
|
||||
if (clear_goals)
|
||||
aigp->flags.set(AI::Goal_Flags::Clear_all_goals_first);
|
||||
|
||||
bool set_override = !The_mission.ai_profile->flags[AI::Profile_Flags::Do_not_set_override_when_assigning_form_on_wing];
|
||||
if (n >= 0)
|
||||
{
|
||||
set_override = is_sexp_true(n);
|
||||
n = CDR(n);
|
||||
}
|
||||
if (set_override)
|
||||
aigp->flags.set(AI::Goal_Flags::Want_override);
|
||||
|
||||
if (n >= 0)
|
||||
{
|
||||
if (is_sexp_true(n))
|
||||
aigp->flags.set(AI::Goal_Flags::Purge_when_new_goal_added);
|
||||
n = CDR(n);
|
||||
}
|
||||
|
||||
aigp->priority = 99;
|
||||
aigp->target_name = ai_get_goal_target_name(CTEXT(CDR(node)), &aigp->target_name_index);
|
||||
aigp->ai_mode = AI_GOAL_FORM_ON_WING;
|
||||
break;
|
||||
}
|
||||
|
||||
case OP_AI_CHASE:
|
||||
case OP_AI_CHASE_WING:
|
||||
case OP_AI_CHASE_SHIP_CLASS:
|
||||
case OP_AI_CHASE_SHIP_TYPE:
|
||||
case OP_AI_GUARD:
|
||||
case OP_AI_GUARD_WING:
|
||||
case OP_AI_EVADE_SHIP:
|
||||
@@ -1246,8 +1123,6 @@ void ai_add_goal_sub_sexp( int sexp, ai_goal_type type, ai_info *aip, ai_goal *a
|
||||
aigp->ai_mode = AI_GOAL_CHASE_WING;
|
||||
} else if (op == OP_AI_CHASE_SHIP_CLASS) {
|
||||
aigp->ai_mode = AI_GOAL_CHASE_SHIP_CLASS;
|
||||
} else if (op == OP_AI_CHASE_SHIP_TYPE) {
|
||||
aigp->ai_mode = AI_GOAL_CHASE_SHIP_TYPE;
|
||||
} else if ( op == OP_AI_IGNORE ) {
|
||||
aigp->ai_mode = AI_GOAL_IGNORE;
|
||||
} else if ( op == OP_AI_IGNORE_NEW ) {
|
||||
@@ -1289,13 +1164,10 @@ void ai_add_goal_sub_sexp( int sexp, ai_goal_type type, ai_info *aip, ai_goal *a
|
||||
} else if ( aigp->priority > MAX_GOAL_PRIORITY ) {
|
||||
nprintf (("AI", "bashing add-goal sexpression priority of goal %s from %d to %d.\n", Sexp_nodes[CAR(sexp)].text, aigp->priority, MAX_GOAL_PRIORITY));
|
||||
aigp->priority = MAX_GOAL_PRIORITY;
|
||||
} else if ( aigp->priority < MIN_GOAL_PRIORITY ) {
|
||||
nprintf (("AI", "bashing add-goal sexpression priority of goal %s from %d to %d.\n", Sexp_nodes[CAR(sexp)].text, aigp->priority, MIN_GOAL_PRIORITY));
|
||||
aigp->priority = MIN_GOAL_PRIORITY;
|
||||
}
|
||||
|
||||
// Goober5000 - we now have an extra optional chase argument to allow chasing our own team
|
||||
if (op == OP_AI_CHASE || op == OP_AI_CHASE_WING || op == OP_AI_CHASE_SHIP_CLASS || op == OP_AI_CHASE_SHIP_TYPE
|
||||
if ( op == OP_AI_CHASE || op == OP_AI_CHASE_WING || op == OP_AI_CHASE_SHIP_CLASS
|
||||
|| op == OP_AI_DISABLE_SHIP || op == OP_AI_DISABLE_SHIP_TACTICAL || op == OP_AI_DISARM_SHIP || op == OP_AI_DISARM_SHIP_TACTICAL ) {
|
||||
if (is_sexp_true(CDDDR(node)))
|
||||
aigp->flags.set(AI::Goal_Flags::Target_own_team);
|
||||
@@ -1320,7 +1192,6 @@ void ai_add_goal_sub_sexp( int sexp, ai_goal_type type, ai_info *aip, ai_goal *a
|
||||
if (op == OP_AI_CHASE ||
|
||||
op == OP_AI_CHASE_WING ||
|
||||
op == OP_AI_CHASE_SHIP_CLASS ||
|
||||
op == OP_AI_CHASE_SHIP_TYPE ||
|
||||
op == OP_AI_DISABLE_SHIP ||
|
||||
op == OP_AI_DISABLE_SHIP_TACTICAL ||
|
||||
op == OP_AI_DISARM_SHIP ||
|
||||
@@ -1404,11 +1275,6 @@ int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp, bool &remove_more )
|
||||
nprintf(("AI", "bashing remove-goal sexpression priority of goal %s from %d to %d.\n", Sexp_nodes[CAR(sexp)].text, _priority, MAX_GOAL_PRIORITY));
|
||||
_priority = MAX_GOAL_PRIORITY;
|
||||
}
|
||||
else if (_priority < MIN_GOAL_PRIORITY)
|
||||
{
|
||||
nprintf(("AI", "bashing remove-goal sexpression priority of goal %s from %d to %d.\n", Sexp_nodes[CAR(sexp)].text, _priority, MIN_GOAL_PRIORITY));
|
||||
_priority = MIN_GOAL_PRIORITY;
|
||||
}
|
||||
|
||||
if (n >= 0)
|
||||
{
|
||||
@@ -1429,9 +1295,12 @@ int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp, bool &remove_more )
|
||||
/* We now need to determine what the mode and submode values are*/
|
||||
switch( op )
|
||||
{
|
||||
case OP_AI_WAYPOINTS:
|
||||
case OP_AI_WAYPOINTS_ONCE:
|
||||
goalmode = (op == OP_AI_WAYPOINTS_ONCE) ? AI_GOAL_WAYPOINTS_ONCE : AI_GOAL_WAYPOINTS;
|
||||
goalmode = AI_GOAL_WAYPOINTS_ONCE;
|
||||
priority = eval_priority_et_seq(CDDR(node));
|
||||
break;
|
||||
case OP_AI_WAYPOINTS:
|
||||
goalmode = AI_GOAL_WAYPOINTS;
|
||||
priority = eval_priority_et_seq(CDDR(node));
|
||||
break;
|
||||
case OP_AI_DESTROY_SUBSYS:
|
||||
@@ -1509,10 +1378,6 @@ int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp, bool &remove_more )
|
||||
priority = eval_priority_et_seq(CDDR(node));
|
||||
goalmode = AI_GOAL_CHASE_SHIP_CLASS;
|
||||
break;
|
||||
case OP_AI_CHASE_SHIP_TYPE:
|
||||
priority = eval_priority_et_seq(CDDR(node));
|
||||
goalmode = AI_GOAL_CHASE_SHIP_TYPE;
|
||||
break;
|
||||
case OP_AI_EVADE_SHIP:
|
||||
priority = eval_priority_et_seq(CDDR(node));
|
||||
goalmode = AI_GOAL_EVADE_SHIP;
|
||||
@@ -1527,7 +1392,7 @@ int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp, bool &remove_more )
|
||||
goalmode = (op == OP_AI_IGNORE) ? AI_GOAL_IGNORE : AI_GOAL_IGNORE_NEW;
|
||||
break;
|
||||
case OP_AI_FORM_ON_WING:
|
||||
priority = eval_priority_et_seq(CDDR(node), The_mission.ai_profile->default_form_on_wing_priority);
|
||||
priority = eval_priority_et_seq(-1, 99);
|
||||
goalmode = AI_GOAL_FORM_ON_WING;
|
||||
break;
|
||||
case OP_AI_FLY_TO_SHIP:
|
||||
@@ -1614,7 +1479,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 );
|
||||
}
|
||||
|
||||
@@ -1638,7 +1503,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 );
|
||||
}
|
||||
}
|
||||
@@ -1661,7 +1526,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);
|
||||
|
||||
@@ -1790,7 +1655,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
|
||||
aigp->flags.set(AI::Goal_Flags::Goal_override);
|
||||
return ai_achievability::ACHIEVABLE;
|
||||
}
|
||||
|
||||
@@ -1822,20 +1687,7 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
}
|
||||
return ai_achievability::NOT_KNOWN;
|
||||
}
|
||||
// and similarly for chasing all ships of a certain ship type
|
||||
if (aigp->ai_mode == AI_GOAL_CHASE_SHIP_TYPE) {
|
||||
for (auto so : list_range(&Ship_obj_list)) {
|
||||
auto type_objp = &Objects[so->objnum];
|
||||
if (type_objp->type != OBJ_SHIP || type_objp->flags[Object::Object_Flags::Should_be_dead])
|
||||
continue;
|
||||
int ship_info_idx = Ships[type_objp->instance].ship_info_index;
|
||||
int class_type = Ship_info[ship_info_idx].class_type;
|
||||
if (class_type >= 0 && !strcmp(aigp->target_name, Ship_types[class_type].name)) {
|
||||
return ai_achievability::ACHIEVABLE;
|
||||
}
|
||||
}
|
||||
return ai_achievability::NOT_KNOWN;
|
||||
}
|
||||
|
||||
|
||||
return_val = ai_achievability::SATISFIED;
|
||||
|
||||
@@ -2065,15 +1917,15 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
// Goober5000 - see note at PURGE_GOALS_ALL_SHIPS... this is bizarre
|
||||
if ((status == SHIP_STATUS_ARRIVED) && !(aigp->flags[AI::Goal_Flags::Goals_purged]))
|
||||
{
|
||||
if (causes_invalid_goal_purge_all_ships(aigp->ai_mode)) {
|
||||
if (purge_goals_all_ships(aigp->ai_mode)) {
|
||||
ai_goal_purge_all_invalid_goals(aigp);
|
||||
aigp->flags.set(AI::Goal_Flags::Goals_purged);
|
||||
}
|
||||
else if (causes_invalid_goal_purge_one_ship(aigp->ai_mode)) {
|
||||
else if (purge_goals_one_ship(aigp->ai_mode)) {
|
||||
ai_goal_purge_invalid_goals(aigp, aip->goals, aip, -1);
|
||||
aigp->flags.set(AI::Goal_Flags::Goals_purged);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if we are docking, validate the docking indices on both ships. We might have to change names to indices.
|
||||
// only enter this calculation if the ship we are docking with has arrived. If the ship is gone, then
|
||||
@@ -2373,10 +2225,6 @@ void validate_mission_goals(int objnum, ai_info *aip)
|
||||
continue;
|
||||
}
|
||||
|
||||
// if the status is achievable, and we want to set the override, set it
|
||||
if ( (state == ai_achievability::ACHIEVABLE) && (aigp->flags[AI::Goal_Flags::Want_override]))
|
||||
aigp->flags.set(AI::Goal_Flags::Goal_override);
|
||||
|
||||
// if the status is achievable, and the on_hold flag is set, clear the flagb
|
||||
if ( (state == ai_achievability::ACHIEVABLE) && (aigp->flags[AI::Goal_Flags::Goal_on_hold]) )
|
||||
aigp->flags.remove(AI::Goal_Flags::Goal_on_hold);
|
||||
@@ -2426,7 +2274,7 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
|
||||
object *objp = &Objects[objnum];
|
||||
object *other_obj;
|
||||
ai_goal *current_goal;
|
||||
int wingnum;
|
||||
int wingnum, shipnum;
|
||||
int original_signature;
|
||||
|
||||
/* if (!stricmp(Ships[objp->instance].ship_name, "gtt comet")) {
|
||||
@@ -2501,34 +2349,14 @@ void ai_process_mission_orders( int objnum, ai_info *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;
|
||||
|
||||
if (current_goal->flags[AI::Goal_Flags::Clear_all_goals_first]) {
|
||||
// save the current goal before we wipe it out by clearing everything
|
||||
current_goal_backup.reset(new ai_goal(*current_goal));
|
||||
current_goal = current_goal_backup.get();
|
||||
|
||||
// stay-still, form-on-wing, and play-dead all clear their goals here...
|
||||
//
|
||||
// clear out the object's goals. Seems to me that if a ship is staying still for a purpose
|
||||
// then we need to clear everything out since there is not a real way to get rid of this goal
|
||||
//
|
||||
// for form on wing, we need to clear out all goals for this ship, and then call the form on wing AI code
|
||||
//
|
||||
// if a ship is playing dead, MWA says that it shouldn't try to do anything else.
|
||||
//
|
||||
// clearing out goals is okay here since we are now what mode to set this AI object to.
|
||||
|
||||
ai_clear_ship_goals(aip);
|
||||
}
|
||||
|
||||
switch ( current_goal->ai_mode ) {
|
||||
|
||||
case AI_GOAL_CHASE:
|
||||
if (current_goal->target_name) {
|
||||
Assert(current_goal_target_ship && current_goal_target_ship->has_objp()); // shouldn't get here if this is false!!!!
|
||||
other_obj = current_goal_target_ship->objp();
|
||||
if ( current_goal->target_name ) {
|
||||
shipnum = ship_name_lookup( current_goal->target_name );
|
||||
Assert (shipnum != -1 ); // shouldn't get here if this is false!!!!
|
||||
other_obj = &Objects[Ships[shipnum].objnum];
|
||||
} else
|
||||
other_obj = NULL; // we get this case when we tell ship to engage enemy!
|
||||
|
||||
@@ -2545,8 +2373,9 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
|
||||
break;
|
||||
|
||||
case AI_GOAL_GUARD:
|
||||
Assert(current_goal_target_ship && current_goal_target_ship->has_objp()); // shouldn't get here if this is false!!!!
|
||||
other_obj = current_goal_target_ship->objp();
|
||||
shipnum = ship_name_lookup( current_goal->target_name );
|
||||
Assert (shipnum != -1 ); // shouldn't get here if this is false!!!!
|
||||
other_obj = &Objects[Ships[shipnum].objnum];
|
||||
// shipnum and other_obj are the shipnumber and object pointer of the object that you should
|
||||
// guard.
|
||||
if (objp != other_obj) {
|
||||
@@ -2577,8 +2406,9 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
|
||||
}
|
||||
|
||||
case AI_GOAL_DOCK: {
|
||||
Assert(current_goal_target_ship && current_goal_target_ship->has_objp()); // shouldn't get here if this is false!!!!
|
||||
other_obj = current_goal_target_ship->objp();
|
||||
shipnum = ship_name_lookup( current_goal->target_name );
|
||||
Assert (shipnum != -1 ); // shouldn't get here if this is false!!!!
|
||||
other_obj = &Objects[Ships[shipnum].objnum];
|
||||
|
||||
// be sure that we have indices for docking points here! If we ever had names, they should
|
||||
// get fixed up in goal_achievable so that the points can be checked there for validity
|
||||
@@ -2588,22 +2418,24 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
|
||||
}
|
||||
|
||||
case AI_GOAL_UNDOCK:
|
||||
// try to find the object with which this object is docked. Use that object as the
|
||||
// try to find the object which which this object is docked with. Use that object as the
|
||||
// "other object" for the undocking proceedure. If "other object" isn't found, then the undock
|
||||
// goal cannot continue. Spit out a warning and remove the goal.
|
||||
|
||||
// Goober5000 - do we have a specific ship to undock from?
|
||||
if (current_goal->target_name)
|
||||
if ( current_goal->target_name != NULL )
|
||||
{
|
||||
shipnum = ship_name_lookup( current_goal->target_name );
|
||||
|
||||
// hmm, perhaps he was destroyed
|
||||
if (!current_goal_target_ship || !current_goal_target_ship->has_objp())
|
||||
if (shipnum == -1)
|
||||
{
|
||||
other_obj = NULL;
|
||||
}
|
||||
// he exists... let's undock from him
|
||||
else
|
||||
{
|
||||
other_obj = current_goal_target_ship->objp();
|
||||
other_obj = &Objects[Ships[shipnum].objnum];
|
||||
}
|
||||
}
|
||||
// no specific ship
|
||||
@@ -2656,15 +2488,16 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
|
||||
case AI_GOAL_DISABLE_SHIP_TACTICAL:
|
||||
case AI_GOAL_DISARM_SHIP:
|
||||
case AI_GOAL_DISARM_SHIP_TACTICAL: {
|
||||
Assert(current_goal_target_ship && current_goal_target_ship->has_objp());
|
||||
other_obj = current_goal_target_ship->objp();
|
||||
shipnum = ship_name_lookup( current_goal->target_name );
|
||||
Assert( shipnum >= 0 );
|
||||
other_obj = &Objects[Ships[shipnum].objnum];
|
||||
ai_attack_object( objp, other_obj);
|
||||
ai_set_attack_subsystem( objp, current_goal->ai_submode ); // submode stored the subsystem type
|
||||
|
||||
// don't protect-ship for tactical goals
|
||||
if (current_goal->ai_mode != AI_GOAL_DESTROY_SUBSYSTEM && current_goal->ai_mode != AI_GOAL_DISABLE_SHIP_TACTICAL && current_goal->ai_mode != AI_GOAL_DISARM_SHIP_TACTICAL) {
|
||||
if (aip->target_objnum != -1) {
|
||||
int class_type = Ship_info[current_goal_target_ship->shipp()->ship_info_index].class_type;
|
||||
int class_type = Ship_info[Ships[shipnum].ship_info_index].class_type;
|
||||
// Only protect if _not_ a capital ship. We don't want the Lucifer accidentally getting protected.
|
||||
if (class_type >= 0 && Ship_types[class_type].flags[Ship::Type_Info_Flags::AI_protected_on_cripple])
|
||||
Objects[aip->target_objnum].flags.set(Object::Object_Flags::Protected);
|
||||
@@ -2688,20 +2521,10 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
|
||||
|
||||
// chase-ship-class is chase-any but restricted to a subset of ships
|
||||
case AI_GOAL_CHASE_SHIP_CLASS:
|
||||
{
|
||||
int ship_info_index = ship_info_lookup(current_goal->target_name);
|
||||
Assertion(ship_info_index >= 0, "The target of AI_GOAL_CHASE_SHIP_CLASS must refer to a valid ship class!");
|
||||
ai_attack_object(objp, nullptr, ship_info_index);
|
||||
shipnum = ship_info_lookup( current_goal->target_name );
|
||||
Assertion( shipnum >= 0, "The target of AI_GOAL_CHASE_SHIP_CLASS must refer to a valid ship class!" );
|
||||
ai_attack_object( objp, nullptr, shipnum );
|
||||
break;
|
||||
}
|
||||
// similarly for chase-ship-type
|
||||
case AI_GOAL_CHASE_SHIP_TYPE:
|
||||
{
|
||||
int class_type = ship_type_name_lookup(current_goal->target_name);
|
||||
Assertion(class_type >= 0, "The target of AI_GOAL_CHASE_SHIP_TYPE must refer to a valid ship type!");
|
||||
ai_attack_object(objp, nullptr, -1, class_type);
|
||||
break;
|
||||
}
|
||||
|
||||
case AI_GOAL_WARP: {
|
||||
mission_do_departure( objp, true );
|
||||
@@ -2709,29 +2532,46 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
|
||||
}
|
||||
|
||||
case AI_GOAL_EVADE_SHIP:
|
||||
Assert(current_goal_target_ship && current_goal_target_ship->has_objp()); // shouldn't get here if this is false!!!!
|
||||
other_obj = current_goal_target_ship->objp();
|
||||
shipnum = ship_name_lookup( current_goal->target_name );
|
||||
Assert( shipnum >= 0 );
|
||||
other_obj = &Objects[Ships[shipnum].objnum];
|
||||
ai_evade_object( objp, other_obj);
|
||||
break;
|
||||
|
||||
case AI_GOAL_STAY_STILL:
|
||||
// NOTE: goal clearing moved above this enclosing switch block
|
||||
// for now, ignore any other parameters!!!!
|
||||
// clear out the object's goals. Seems to me that if a ship is staying still for a purpose
|
||||
// then we need to clear everything out since there is not a real way to get rid of this goal
|
||||
// clearing out goals is okay here since we are now what mode to set this AI object to.
|
||||
ai_clear_ship_goals( aip );
|
||||
ai_stay_still( objp, NULL );
|
||||
break;
|
||||
|
||||
case AI_GOAL_PLAY_DEAD:
|
||||
// if a ship is playing dead, MWA says that it shouldn't try to do anything else.
|
||||
// clearing out goals is okay here since we are now what mode to set this AI object to.
|
||||
ai_clear_ship_goals( aip );
|
||||
aip->mode = AIM_PLAY_DEAD;
|
||||
aip->submode = -1;
|
||||
aip->submode_start_time = Missiontime;
|
||||
break;
|
||||
|
||||
case AI_GOAL_PLAY_DEAD_PERSISTENT:
|
||||
// NOTE: goal clearing moved above this enclosing switch block
|
||||
// same as above, but we don't clear out ship goals
|
||||
aip->mode = AIM_PLAY_DEAD;
|
||||
aip->submode = -1;
|
||||
aip->submode_start_time = Missiontime;
|
||||
break;
|
||||
|
||||
case AI_GOAL_FORM_ON_WING:
|
||||
// NOTE: goal clearing moved above this enclosing switch block
|
||||
Assert(current_goal_target_ship && current_goal_target_ship->has_objp()); // shouldn't get here if this is false!!!!
|
||||
other_obj = current_goal_target_ship->objp();
|
||||
// get the ship first, since we're going to wipe it out next
|
||||
shipnum = ship_name_lookup( current_goal->target_name );
|
||||
Assert( shipnum >= 0 );
|
||||
other_obj = &Objects[Ships[shipnum].objnum];
|
||||
// for form on wing, we need to clear out all goals for this ship, and then call the form
|
||||
// on wing AI code
|
||||
// clearing out goals is okay here since we are now what mode to set this AI object to.
|
||||
ai_clear_ship_goals( aip );
|
||||
ai_form_on_wing( objp, other_obj );
|
||||
break;
|
||||
|
||||
@@ -2740,8 +2580,9 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
|
||||
case AI_GOAL_STAY_NEAR_SHIP:
|
||||
case AI_GOAL_FLY_TO_SHIP:
|
||||
{
|
||||
Assert(current_goal_target_ship && current_goal_target_ship->has_objp()); // shouldn't get here if this is false!!!!
|
||||
other_obj = current_goal_target_ship->objp();
|
||||
shipnum = ship_name_lookup( current_goal->target_name );
|
||||
Assert( shipnum >= 0 );
|
||||
other_obj = &Objects[Ships[shipnum].objnum];
|
||||
float dist = current_goal->float_data; // How far away to stay from ship. Should be set in SEXP?
|
||||
int additional_data = current_goal->int_data; // Whether to target a particular point as if escorting
|
||||
ai_do_stay_near(objp, other_obj, dist, additional_data);
|
||||
@@ -2756,8 +2597,9 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
|
||||
break;
|
||||
|
||||
case AI_GOAL_REARM_REPAIR:
|
||||
Assert(current_goal_target_ship && current_goal_target_ship->has_objp()); // shouldn't get here if this is false!!!!
|
||||
other_obj = current_goal_target_ship->objp();
|
||||
shipnum = ship_name_lookup( current_goal->target_name );
|
||||
Assert( shipnum >= 0 );
|
||||
other_obj = &Objects[Ships[shipnum].objnum];
|
||||
ai_rearm_repair( objp, current_goal->docker.index, other_obj, current_goal->dockee.index );
|
||||
break;
|
||||
|
||||
|
||||
+6
-13
@@ -47,9 +47,9 @@ enum class ai_goal_type
|
||||
enum ai_goal_mode : uint8_t
|
||||
{
|
||||
AI_GOAL_NONE = 0,
|
||||
AI_GOAL_SCHROEDINGER, // used for FRED when multiple ships are selected with different orders
|
||||
AI_GOAL_PLACEHOLDER_1,
|
||||
|
||||
AI_GOAL_CHASE,
|
||||
AI_GOAL_CHASE, // per the original #define list, AI_GOAL_CHASE started at 2 (1<<1)
|
||||
AI_GOAL_DOCK, // used for undocking as well
|
||||
AI_GOAL_WAYPOINTS,
|
||||
AI_GOAL_WAYPOINTS_ONCE,
|
||||
@@ -80,8 +80,7 @@ enum ai_goal_mode : uint8_t
|
||||
AI_GOAL_FLY_TO_SHIP,
|
||||
AI_GOAL_IGNORE_NEW,
|
||||
AI_GOAL_CHASE_SHIP_CLASS,
|
||||
AI_GOAL_CHASE_SHIP_TYPE,
|
||||
AI_GOAL_PLAY_DEAD_PERSISTENT, // Disables subsystem rotation/translation among other things but there is a carveout for that in the lab in ship_move_subsystems() and ai_process_subobjects()
|
||||
AI_GOAL_PLAY_DEAD_PERSISTENT,
|
||||
AI_GOAL_LUA,
|
||||
AI_GOAL_DISARM_SHIP_TACTICAL,
|
||||
AI_GOAL_DISABLE_SHIP_TACTICAL,
|
||||
@@ -104,11 +103,7 @@ inline bool ai_goal_is_disable_or_disarm(ai_goal_mode ai_mode)
|
||||
}
|
||||
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;
|
||||
return ai_mode == AI_GOAL_CHASE || ai_mode == AI_GOAL_CHASE_WING || ai_mode == AI_GOAL_CHASE_SHIP_CLASS;
|
||||
}
|
||||
|
||||
enum class ai_achievability { ACHIEVABLE, NOT_ACHIEVABLE, NOT_KNOWN, SATISFIED };
|
||||
@@ -157,8 +152,6 @@ typedef struct ai_goal {
|
||||
|
||||
extern void ai_goal_reset(ai_goal *aigp, bool adding_goal = false, ai_goal_mode ai_mode = AI_GOAL_NONE, int ai_submode = -1, ai_goal_type type = ai_goal_type::INVALID);
|
||||
|
||||
// Reset all path points. Used in the ship lab. Missions clean up path points with the garbage collector in garbage_collect_path_points()
|
||||
extern void reset_ai_path_points();
|
||||
|
||||
typedef flag_def_list_templated<ai_goal_mode> ai_goal_list;
|
||||
|
||||
@@ -192,8 +185,8 @@ extern int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp, bool &remove_more )
|
||||
extern void ai_remove_wing_goal_sexp( int sexp, wing *wingp );
|
||||
|
||||
// adds goals to ships/sings through player orders
|
||||
extern void ai_add_ship_goal_player(ai_goal_type type, ai_goal_mode mode, int submode, const char* shipname, ai_info* aip, int int_data = 0, float float_data = 0.0f, const ai_lua_parameters& lua_target = { object_ship_wing_point_team(), luacpp::LuaValueList{} });
|
||||
extern void ai_add_wing_goal_player(ai_goal_type type, ai_goal_mode mode, int submode, const char* shipname, int wingnum, int int_data = 0, float float_data = 0.0f, const ai_lua_parameters& lua_target = { object_ship_wing_point_team(), luacpp::LuaValueList{} });
|
||||
extern void ai_add_ship_goal_player(ai_goal_type type, ai_goal_mode mode, int submode, const char* shipname, ai_info* aip, const ai_lua_parameters& lua_target = { object_ship_wing_point_team(), luacpp::LuaValueList{} });
|
||||
extern void ai_add_wing_goal_player(ai_goal_type type, ai_goal_mode mode, int submode, const char* shipname, int wingnum, const ai_lua_parameters& lua_target = { object_ship_wing_point_team(), luacpp::LuaValueList{} });
|
||||
|
||||
extern void ai_remove_ship_goal( ai_info *aip, int index );
|
||||
extern void ai_clear_ship_goals( ai_info *aip );
|
||||
|
||||
+103
-61
@@ -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,12 +1089,9 @@ 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;
|
||||
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,
|
||||
// target_objnum));
|
||||
if (iff_matches_mask(Ships[Objects[target_objnum].instance].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, target_objnum));
|
||||
return target_objnum;
|
||||
}
|
||||
}
|
||||
@@ -1580,9 +1559,7 @@ void turret_set_next_fire_timestamp(int weapon_num, const weapon_info *wip, ship
|
||||
float burst_shots_mult = wip->weapon_launch_curves.get_output(weapon_info::WeaponLaunchCurveOutputs::BURST_SHOTS_MULT, launch_curve_data);
|
||||
int burst_shots = MAX(fl2i(i2fl(base_burst_shots) * burst_shots_mult) - 1, 0);
|
||||
|
||||
bool burst = burst_shots > turret->weapons.burst_counter[weapon_num];
|
||||
|
||||
if (burst) {
|
||||
if (burst_shots > turret->weapons.burst_counter[weapon_num]) {
|
||||
wait *= wip->burst_delay;
|
||||
wait *= wip->weapon_launch_curves.get_output(weapon_info::WeaponLaunchCurveOutputs::BURST_DELAY_MULT, launch_curve_data);
|
||||
turret->weapons.burst_counter[weapon_num]++;
|
||||
@@ -1682,7 +1659,7 @@ void turret_set_next_fire_timestamp(int weapon_num, const weapon_info *wip, ship
|
||||
wait *= frand_range(0.9f, 1.1f);
|
||||
}
|
||||
|
||||
if(turret->rof_scaler != 1.0f && !(burst && turret->system_info->flags[Model::Subsystem_Flags::Burst_ignores_RoF_Mult]))
|
||||
if(turret->rof_scaler != 1.0f)
|
||||
wait /= get_adjusted_turret_rof(turret);
|
||||
|
||||
(*fs_dest) = timestamp((int)wait);
|
||||
@@ -1741,7 +1718,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 +1744,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 +1828,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 +1840,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 +1866,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 +1987,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,11 +2038,14 @@ bool turret_fire_weapon(int weapon_num,
|
||||
}
|
||||
//spawn particle effect
|
||||
auto particleSource = particle::ParticleManager::get()->createSource(wip->muzzle_effect);
|
||||
particleSource->setHost(std::make_unique<EffectHostTurret>(&Objects[parent_ship->objnum], turret->system_info->turret_gun_sobj, turret->turret_next_fire_pos, false));
|
||||
particleSource->setHost(make_unique<EffectHostTurret>(&Objects[parent_ship->objnum], turret->system_info->turret_gun_sobj, turret->turret_next_fire_pos));
|
||||
particleSource->setTriggerRadius(objp->radius * radius_mult);
|
||||
particleSource->setTriggerVelocity(vm_vec_mag_quick(&objp->phys_info.vel));
|
||||
particleSource->finishCreation();
|
||||
}
|
||||
else if (wip->muzzle_flash >= 0) {
|
||||
mflash_create(firing_pos, firing_vec, &Objects[parent_ship->objnum].phys_info, wip->muzzle_flash);
|
||||
}
|
||||
|
||||
// in multiplayer (and the master), then send a turret fired packet.
|
||||
if ( MULTIPLAYER_MASTER && (weapon_objnum != -1) ) {
|
||||
@@ -2094,7 +2133,7 @@ void turret_swarm_fire_from_turret(turret_swarm_info *tsi)
|
||||
};
|
||||
|
||||
// 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.
|
||||
@@ -2123,10 +2162,13 @@ void turret_swarm_fire_from_turret(turret_swarm_info *tsi)
|
||||
if (Weapon_info[tsi->weapon_class].muzzle_effect.isValid()) {
|
||||
//spawn particle effect
|
||||
auto particleSource = particle::ParticleManager::get()->createSource(Weapon_info[tsi->weapon_class].muzzle_effect);
|
||||
particleSource->setHost(std::make_unique<EffectHostTurret>(&Objects[tsi->parent_objnum], tsi->turret->system_info->turret_gun_sobj, tsi->turret->turret_next_fire_pos - 1, false));
|
||||
particleSource->setHost(make_unique<EffectHostTurret>(&Objects[tsi->parent_objnum], tsi->turret->system_info->turret_gun_sobj, tsi->turret->turret_next_fire_pos - 1));
|
||||
particleSource->setTriggerRadius(Objects[weapon_objnum].radius);
|
||||
particleSource->finishCreation();
|
||||
}
|
||||
else if (Weapon_info[tsi->weapon_class].muzzle_flash >= 0) {
|
||||
mflash_create(&turret_pos, &turret_fvec, &Objects[tsi->parent_objnum].phys_info, Weapon_info[tsi->weapon_class].muzzle_flash);
|
||||
}
|
||||
|
||||
// maybe sound
|
||||
if ( Weapon_info[tsi->weapon_class].launch_snd.isValid() ) {
|
||||
|
||||
+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;
|
||||
}
|
||||
|
||||
+79
-157
@@ -32,9 +32,8 @@
|
||||
#include "object/objcollide.h"
|
||||
#include "object/object.h"
|
||||
#include "parse/parselo.h"
|
||||
#include "particle/ParticleEffect.h"
|
||||
#include "scripting/global_hooks.h"
|
||||
#include "particle/hosts/EffectHostVector.h"
|
||||
#include "particle/particle.h"
|
||||
#include "render/3d.h"
|
||||
#include "ship/ship.h"
|
||||
#include "ship/shipfx.h"
|
||||
@@ -64,7 +63,8 @@ asteroid Asteroids[MAX_ASTEROIDS];
|
||||
asteroid_field Asteroid_field;
|
||||
|
||||
|
||||
static particle::ParticleEffectHandle Asteroid_impact_explosion_ani;
|
||||
static int Asteroid_impact_explosion_ani;
|
||||
static float Asteroid_impact_explosion_radius;
|
||||
char Asteroid_icon_closeup_model[NAME_LENGTH];
|
||||
vec3d Asteroid_icon_closeup_position;
|
||||
float Asteroid_icon_closeup_zoom;
|
||||
@@ -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);
|
||||
@@ -830,7 +824,18 @@ void asteroid_create_debris_field(int num_asteroids, int asteroid_speed, SCP_vec
|
||||
*/
|
||||
void asteroid_level_init()
|
||||
{
|
||||
Asteroid_field = {};
|
||||
Asteroid_field.num_initial_asteroids = 0; // disable asteroid field by default.
|
||||
Asteroid_field.speed = 0.0f;
|
||||
vm_vec_make(&Asteroid_field.min_bound, -1000.0f, -1000.0f, -1000.0f);
|
||||
vm_vec_make(&Asteroid_field.max_bound, 1000.0f, 1000.0f, 1000.0f);
|
||||
vm_vec_make(&Asteroid_field.inner_min_bound, -500.0f, -500.0f, -500.0f);
|
||||
vm_vec_make(&Asteroid_field.inner_max_bound, 500.0f, 500.0f, 500.0f);
|
||||
Asteroid_field.has_inner_bound = false;
|
||||
Asteroid_field.field_type = FT_ACTIVE;
|
||||
Asteroid_field.debris_genre = DG_ASTEROID;
|
||||
Asteroid_field.field_debris_type.clear();
|
||||
Asteroid_field.field_asteroid_type.clear();
|
||||
Asteroid_field.target_names.clear();
|
||||
|
||||
if (!Fred_running)
|
||||
{
|
||||
@@ -1083,10 +1088,8 @@ void asteroid_delete( object * obj )
|
||||
|
||||
asp = &Asteroids[num];
|
||||
|
||||
if (asp->model_instance_num >= 0) {
|
||||
if (asp->model_instance_num >= 0)
|
||||
model_delete_instance(asp->model_instance_num);
|
||||
asp->model_instance_num = -1;
|
||||
}
|
||||
|
||||
if (asp->target_objnum >= 0) {
|
||||
for (asteroid_target& target : Asteroid_targets) {
|
||||
@@ -1323,9 +1326,9 @@ int asteroid_check_collision(object *pasteroid, object *other_obj, vec3d *hitpos
|
||||
model_get_moving_submodel_list(submodel_vector, heavy_obj);
|
||||
|
||||
// turn off all moving submodels, collide against only 1 at a time.
|
||||
mc.collision_checked.assign(pm->n_models, 0);
|
||||
// turn off collision detection for all moving submodels
|
||||
for (auto submodel: submodel_vector) {
|
||||
mc.collision_checked[submodel] = true;
|
||||
pmi->submodel[submodel].collision_checked = true;
|
||||
}
|
||||
|
||||
// Only check single submodel now, since children of moving submodels are handled as moving as well
|
||||
@@ -1333,8 +1336,10 @@ int asteroid_check_collision(object *pasteroid, object *other_obj, vec3d *hitpos
|
||||
|
||||
// check each submodel in turn
|
||||
for (auto submodel: submodel_vector) {
|
||||
auto smi = &pmi->submodel[submodel];
|
||||
|
||||
// turn on just one submodel for collision test
|
||||
mc.collision_checked[submodel] = false;
|
||||
smi->collision_checked = false;
|
||||
|
||||
// find the start and end positions of the sphere in submodel RF
|
||||
model_instance_global_to_local_point(&p0, &light_obj->last_pos, pm, pmi, submodel, &heavy_obj->last_orient, &heavy_obj->last_pos, true);
|
||||
@@ -1366,12 +1371,9 @@ int asteroid_check_collision(object *pasteroid, object *other_obj, vec3d *hitpos
|
||||
}
|
||||
}
|
||||
// Don't look at this submodel again
|
||||
mc.collision_checked[submodel] = true;
|
||||
smi->collision_checked = true;
|
||||
}
|
||||
|
||||
// Clear collision_checked before base model pass so it auto-inits fresh
|
||||
mc.collision_checked.clear();
|
||||
|
||||
}
|
||||
|
||||
// Now complete base model collision checks that do not take into account rotating submodels.
|
||||
@@ -1616,13 +1618,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 {
|
||||
@@ -1708,57 +1705,37 @@ static void asteroid_do_area_effect(object *asteroid_objp)
|
||||
*/
|
||||
void asteroid_hit( object * pasteroid_obj, object * other_obj, vec3d * hitpos, float damage, vec3d* force )
|
||||
{
|
||||
asteroid *asp = &Asteroids[pasteroid_obj->instance];
|
||||
asteroid_info *asip = &Asteroid_info[Asteroids[pasteroid_obj->instance].asteroid_type];
|
||||
|
||||
float explosion_life;
|
||||
asteroid *asp;
|
||||
|
||||
asp = &Asteroids[pasteroid_obj->instance];
|
||||
|
||||
if (pasteroid_obj->flags[Object::Object_Flags::Should_be_dead]){
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if ( MULTIPLAYER_MASTER ){
|
||||
send_asteroid_hit( pasteroid_obj, other_obj, hitpos, damage, force );
|
||||
}
|
||||
|
||||
|
||||
if (hitpos && force && The_mission.ai_profile->flags[AI::Profile_Flags::Whackable_asteroids]) {
|
||||
vec3d rel_hit_pos = *hitpos - pasteroid_obj->pos;
|
||||
physics_calculate_and_apply_whack(force, &rel_hit_pos, &pasteroid_obj->phys_info, &pasteroid_obj->orient, &pasteroid_obj->phys_info.I_body_inv);
|
||||
pasteroid_obj->phys_info.desired_vel = pasteroid_obj->phys_info.vel;
|
||||
}
|
||||
|
||||
|
||||
pasteroid_obj->hull_strength -= damage;
|
||||
|
||||
|
||||
if (pasteroid_obj->hull_strength < 0.0f) {
|
||||
if ( !asp->final_death_time.isValid() ) {
|
||||
int play_loud_collision = 0;
|
||||
|
||||
float explosion_life = 1.f;
|
||||
int breakup_timestamp;
|
||||
|
||||
Assertion(!asip->end_particles.isValid() || asip->breakup_delay.has_value(), "Asteroid %s has end particles but no breakup delay. Parsing should not have allowed this!", asip->name);
|
||||
|
||||
if (asip->end_particles.isValid()) {
|
||||
auto source = particle::ParticleManager::get()->createSource(asip->end_particles);
|
||||
|
||||
// Use the position since the asteroid is going to be invalid soon
|
||||
auto host = std::make_unique<EffectHostVector>(pasteroid_obj->pos, pasteroid_obj->orient, pasteroid_obj->phys_info.vel);
|
||||
host->setRadius(pasteroid_obj->radius);
|
||||
source->setHost(std::move(host));
|
||||
source->setNormal(pasteroid_obj->orient.vec.uvec);
|
||||
source->finishCreation();
|
||||
} else {
|
||||
explosion_life = asteroid_create_explosion(pasteroid_obj);
|
||||
}
|
||||
|
||||
if (asip->breakup_delay.has_value()) {
|
||||
breakup_timestamp = fl2i(*asip->breakup_delay * MILLISECONDS_PER_SECOND);
|
||||
} else {
|
||||
breakup_timestamp = fl2i((explosion_life * MILLISECONDS_PER_SECOND) / 5.f);
|
||||
}
|
||||
explosion_life = asteroid_create_explosion(pasteroid_obj);
|
||||
|
||||
asteroid_explode_sound(pasteroid_obj, asp->asteroid_type, play_loud_collision);
|
||||
asteroid_do_area_effect(pasteroid_obj);
|
||||
|
||||
asp->final_death_time = _timestamp( breakup_timestamp ); // Wait till 20% of vclip time before breaking the asteroid up, or use the specified delay
|
||||
asp->final_death_time = _timestamp( fl2i(explosion_life*MILLISECONDS_PER_SECOND)/5 ); // Wait till 30% of vclip time before breaking the asteroid up.
|
||||
if ( hitpos ) {
|
||||
asp->death_hit_pos = *hitpos;
|
||||
} else {
|
||||
@@ -1774,10 +1751,8 @@ void asteroid_hit( object * pasteroid_obj, object * other_obj, vec3d * hitpos, f
|
||||
weapon_info *wip;
|
||||
wip = &Weapon_info[Weapons[other_obj->instance].weapon_info_index];
|
||||
// If the weapon didn't play any impact animation, play custom asteroid impact animation
|
||||
if (!wip->impact_weapon_expl_effect.isValid() && Asteroid_impact_explosion_ani.isValid()) {
|
||||
auto source = particle::ParticleManager::get()->createSource(Asteroid_impact_explosion_ani);
|
||||
source->setHost(std::make_unique<EffectHostVector>(*hitpos, vmd_identity_matrix, vmd_zero_vector));
|
||||
source->finishCreation();
|
||||
if (!wip->impact_weapon_expl_effect.isValid()) {
|
||||
particle::create( hitpos, &vmd_zero_vector, 0.0f, Asteroid_impact_explosion_radius, Asteroid_impact_explosion_ani );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2234,7 +2209,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,13 +2307,13 @@ 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (optional_string("$Detail distance:")) {
|
||||
asteroid_p->num_detail_levels = sz2i(stuff_int_list(asteroid_p->detail_distance, MAX_ASTEROID_DETAIL_LEVELS, ParseLookupType::RAW_INTEGER_TYPE));
|
||||
asteroid_p->num_detail_levels = (int)stuff_int_list(asteroid_p->detail_distance, MAX_ASTEROID_DETAIL_LEVELS, RAW_INTEGER_TYPE);
|
||||
}
|
||||
|
||||
if (optional_string("$Max Speed:")) {
|
||||
@@ -2355,25 +2330,13 @@ static void asteroid_parse_section()
|
||||
asteroid_p->damage_type_idx_sav = damage_type_add(buf);
|
||||
asteroid_p->damage_type_idx = asteroid_p->damage_type_idx_sav;
|
||||
}
|
||||
|
||||
if (optional_string("$Explosion Effect:")) {
|
||||
asteroid_p->end_particles = particle::util::parseEffect(asteroid_p->name);
|
||||
} else {
|
||||
if(optional_string("$Explosion Animations:")){
|
||||
stuff_fireball_index_list(asteroid_p->explosion_bitmap_anims, asteroid_p->name);
|
||||
}
|
||||
|
||||
if (optional_string("$Explosion Radius Mult:")) {
|
||||
stuff_float(&asteroid_p->fireball_radius_multiplier);
|
||||
}
|
||||
|
||||
if(optional_string("$Explosion Animations:")){
|
||||
stuff_fireball_index_list(asteroid_p->explosion_bitmap_anims, asteroid_p->name);
|
||||
}
|
||||
|
||||
if (optional_string("$Breakup Delay:")) {
|
||||
stuff_float(&asteroid_p->breakup_delay.emplace());
|
||||
}
|
||||
|
||||
if (asteroid_p->end_particles.isValid() && !asteroid_p->breakup_delay.has_value()) {
|
||||
error_display(0, "Asteroid %s has an explosion effect but no breakup delay!", asteroid_p->name);
|
||||
if (optional_string("$Explosion Radius Mult:")) {
|
||||
stuff_float(&asteroid_p->fireball_radius_multiplier);
|
||||
}
|
||||
|
||||
if (optional_string("$Expl inner rad:")){
|
||||
@@ -2498,52 +2461,18 @@ static void asteroid_parse_tbl(const char* filename)
|
||||
|
||||
required_string("#End");
|
||||
|
||||
if (optional_string("$Impact Explosion Effect:")) {
|
||||
Asteroid_impact_explosion_ani = particle::util::parseEffect();
|
||||
if (optional_string("$Impact Explosion:")) {
|
||||
char impact_ani_file[MAX_FILENAME_LEN];
|
||||
stuff_string(impact_ani_file, F_NAME, MAX_FILENAME_LEN);
|
||||
|
||||
if (VALID_FNAME(impact_ani_file)) {
|
||||
int num_frames;
|
||||
Asteroid_impact_explosion_ani = bm_load_animation(impact_ani_file, &num_frames, nullptr, nullptr, nullptr, true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
char impact_ani_file[MAX_FILENAME_LEN] = {0};
|
||||
float Asteroid_impact_explosion_radius = 0.0f;
|
||||
int num_frames;
|
||||
|
||||
if (optional_string("$Impact Explosion:")) {
|
||||
stuff_string(impact_ani_file, F_NAME, MAX_FILENAME_LEN);
|
||||
}
|
||||
if (optional_string("$Impact Explosion Radius:")) {
|
||||
stuff_float(&Asteroid_impact_explosion_radius);
|
||||
}
|
||||
|
||||
if(VALID_FNAME(impact_ani_file)) {
|
||||
Asteroid_impact_explosion_ani = particle::ParticleManager::get()->addEffect(particle::ParticleEffect(
|
||||
"", //Name
|
||||
::util::UniformFloatRange(1.f), //Particle num
|
||||
particle::ParticleEffect::Duration::ONETIME, //Single Particle Emission
|
||||
::util::UniformFloatRange(), //No duration
|
||||
::util::UniformFloatRange(-1.f), //Single particle only
|
||||
particle::ParticleEffect::ShapeDirection::ALIGNED, //Particle direction
|
||||
::util::UniformFloatRange(), //Velocity Inherit
|
||||
false, //Velocity Inherit absolute?
|
||||
nullptr, //Velocity volume
|
||||
::util::UniformFloatRange(), //Velocity volume multiplier
|
||||
particle::ParticleEffect::VelocityScaling::NONE, //Velocity directional scaling
|
||||
std::nullopt, //Orientation-based velocity
|
||||
std::nullopt, //Position-based velocity
|
||||
nullptr, //Position volume
|
||||
particle::ParticleEffectHandle::invalid(), //Trail
|
||||
1.f, //Chance
|
||||
false, //Affected by detail
|
||||
-1.f, //Culling range multiplier
|
||||
false, //Disregard Animation Length. Must be true for everything using particle::Anim_bitmap_X
|
||||
false, //Don't reverse animation
|
||||
false, //parent local
|
||||
false, //ignore velocity inherit if parented
|
||||
false, //position velocity inherit absolute?
|
||||
std::nullopt, //Local velocity offset
|
||||
std::nullopt, //Local offset
|
||||
::util::UniformFloatRange(-1.f), //Lifetime
|
||||
::util::UniformFloatRange(Asteroid_impact_explosion_radius), //Radius
|
||||
bm_load_animation(impact_ani_file, &num_frames, nullptr, nullptr, nullptr, true))); //Bitmap
|
||||
}
|
||||
if (optional_string("$Impact Explosion Radius:")) {
|
||||
stuff_float(&Asteroid_impact_explosion_radius);
|
||||
}
|
||||
|
||||
if (optional_string("$Briefing Icon Closeup Model:")) {
|
||||
@@ -2578,21 +2507,24 @@ int get_asteroid_index(const char* asteroid_name)
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Returns the list of unique asteroid subtype names.
|
||||
// List is cached after the first call since Asteroid_info cannot change during an engine instance.
|
||||
const SCP_vector<SCP_string>& get_list_valid_asteroid_subtypes()
|
||||
// For FRED. Gets a list of unique asteroid subtype names
|
||||
SCP_vector<SCP_string> get_list_valid_asteroid_subtypes()
|
||||
{
|
||||
static SCP_vector<SCP_string> list;
|
||||
SCP_vector<SCP_string> list;
|
||||
|
||||
if (list.empty()) {
|
||||
for (const auto& this_asteroid : Asteroid_info) {
|
||||
if (this_asteroid.type != ASTEROID_TYPE_DEBRIS) {
|
||||
for (const auto& subtype : this_asteroid.subtypes) {
|
||||
// Only add unique names
|
||||
if (std::find(list.begin(), list.end(), subtype.type_name) == list.end()) {
|
||||
list.push_back(subtype.type_name);
|
||||
for (const auto& this_asteroid : Asteroid_info) {
|
||||
if (this_asteroid.type != ASTEROID_TYPE_DEBRIS) {
|
||||
for (const auto& subtype : this_asteroid.subtypes) {
|
||||
bool exists = false;
|
||||
for (const auto& entry : list) {
|
||||
if (subtype.type_name == entry) {
|
||||
exists = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!exists) {
|
||||
list.push_back(subtype.type_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2600,7 +2532,6 @@ const SCP_vector<SCP_string>& get_list_valid_asteroid_subtypes()
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
static void verify_asteroid_splits()
|
||||
{
|
||||
|
||||
@@ -2621,7 +2552,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 +2580,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;
|
||||
@@ -2696,7 +2622,8 @@ static void verify_asteroid_list()
|
||||
*/
|
||||
void asteroid_init()
|
||||
{
|
||||
Asteroid_impact_explosion_ani = particle::ParticleEffectHandle::invalid();
|
||||
Asteroid_impact_explosion_ani = -1;
|
||||
Asteroid_impact_explosion_radius = 20.0; // retail value
|
||||
Asteroid_icon_closeup_model[0] = '\0';
|
||||
vm_vec_make(&Asteroid_icon_closeup_position, 0.0f, 0.0f, -334.0f); // magic numbers from retail
|
||||
Asteroid_icon_closeup_zoom = 0.5f; // magic number from retail
|
||||
@@ -2708,10 +2635,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();
|
||||
@@ -2719,11 +2644,8 @@ void asteroid_init()
|
||||
// now that Asteroid_info is filled in we can verify the asteroid splits and set their indecies
|
||||
verify_asteroid_splits();
|
||||
|
||||
if (!Asteroid_impact_explosion_ani.isValid()) {
|
||||
// this will always be missing on a standalone
|
||||
if ( !Is_standalone ) {
|
||||
Error(LOCATION, "Missing valid asteroid impact explosion definition in asteroid.tbl!");
|
||||
}
|
||||
if (Asteroid_impact_explosion_ani == -1) {
|
||||
Error(LOCATION, "Missing valid asteroid impact explosion definition in asteroid.tbl!");
|
||||
}
|
||||
|
||||
if (Asteroid_icon_closeup_model[0] == '\0')
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
#include "globalincs/pstypes.h"
|
||||
#include "object/object_flags.h"
|
||||
#include "io/timer.h"
|
||||
#include "particle/ParticleSource.h"
|
||||
#include "math/vecmat.h"
|
||||
|
||||
class object;
|
||||
class polymodel;
|
||||
@@ -81,9 +79,7 @@ public:
|
||||
float initial_asteroid_strength; // starting strength of asteroid
|
||||
SCP_vector< asteroid_split_info > split_info;
|
||||
SCP_vector<int> explosion_bitmap_anims;
|
||||
float fireball_radius_multiplier; // the model radius is multiplied by this to determine the fireball size
|
||||
particle::ParticleEffectHandle end_particles;
|
||||
std::optional<float> breakup_delay;
|
||||
float fireball_radius_multiplier; // the model radius is multiplied by this to determine the fireball size
|
||||
SCP_string display_name; // only used for hud targeting display and for debris
|
||||
float spawn_weight; // debris only, relative proportion to spawn compared to other types in its asteroid field
|
||||
float gravity_const; // multiplier for mission gravity
|
||||
@@ -94,7 +90,7 @@ public:
|
||||
rotational_vel_multiplier(1), damage_type_idx(0),
|
||||
damage_type_idx_sav( -1 ), inner_rad( 0 ), outer_rad( 0 ),
|
||||
damage( 0 ), blast( 0 ), initial_asteroid_strength( 0 ),
|
||||
fireball_radius_multiplier( -1 ), end_particles( particle::ParticleEffectHandle::invalid() ), breakup_delay( std::nullopt ), spawn_weight( 1 ), gravity_const( 0 )
|
||||
fireball_radius_multiplier( -1 ), spawn_weight( 1 ), gravity_const( 0 )
|
||||
{
|
||||
name[ 0 ] = 0;
|
||||
display_name = "";
|
||||
@@ -134,7 +130,7 @@ typedef enum {
|
||||
FT_PASSIVE
|
||||
} field_type_t;
|
||||
|
||||
struct asteroid_field {
|
||||
typedef struct asteroid_field {
|
||||
vec3d min_bound; // Minimum range of field.
|
||||
vec3d max_bound; // Maximum range of field.
|
||||
float bound_rad;
|
||||
@@ -151,24 +147,7 @@ struct asteroid_field {
|
||||
bool enhanced_visibility_checks; // if true then range checks are overridden for spawning and wrapping asteroids in the field
|
||||
|
||||
SCP_vector<SCP_string> target_names; // default retail behavior is to just throw at the first big ship in the field
|
||||
|
||||
asteroid_field()
|
||||
{
|
||||
num_initial_asteroids = 0; // disable the field by default
|
||||
speed = 0.0f;
|
||||
vm_vec_make(&min_bound, -1000.0f, -1000.0f, -1000.0f);
|
||||
vm_vec_make(&max_bound, 1000.0f, 1000.0f, 1000.0f);
|
||||
vm_vec_make(&inner_min_bound, -500.0f, -500.0f, -500.0f);
|
||||
vm_vec_make(&inner_max_bound, 500.0f, 500.0f, 500.0f);
|
||||
has_inner_bound = false;
|
||||
field_type = FT_ACTIVE;
|
||||
debris_genre = DG_ASTEROID;
|
||||
enhanced_visibility_checks = false;
|
||||
bound_rad = 0.0f;
|
||||
vel = ZERO_VECTOR;
|
||||
// the vectors default-construct to empty
|
||||
}
|
||||
};
|
||||
} asteroid_field;
|
||||
|
||||
extern SCP_vector< asteroid_info > Asteroid_info;
|
||||
extern asteroid Asteroids[MAX_ASTEROIDS];
|
||||
@@ -200,8 +179,7 @@ void asteroid_show_brackets();
|
||||
void asteroid_target_closest_danger();
|
||||
void asteroid_add_target(object* objp);
|
||||
int get_asteroid_index(const char* asteroid_name);
|
||||
const SCP_vector<SCP_string>& get_list_valid_asteroid_subtypes();
|
||||
int get_asteroid_subtype_index_by_name(const SCP_string& name, int asteroid_idx);
|
||||
SCP_vector<SCP_string> get_list_valid_asteroid_subtypes();
|
||||
|
||||
// extern for the lab
|
||||
void asteroid_load(int asteroid_info_index, int asteroid_subtype);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
+30
-150
@@ -32,7 +32,6 @@
|
||||
#include "tgautils/tgautils.h"
|
||||
#include "tracing/Monitor.h"
|
||||
#include "tracing/tracing.h"
|
||||
#include "ktxutils/ktxutils.h"
|
||||
|
||||
#include <cctype>
|
||||
#include <climits>
|
||||
@@ -60,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 };
|
||||
@@ -83,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.
|
||||
@@ -149,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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,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));
|
||||
|
||||
@@ -209,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();
|
||||
}
|
||||
@@ -217,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
|
||||
@@ -651,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
|
||||
@@ -913,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;
|
||||
@@ -1067,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;
|
||||
}
|
||||
@@ -1178,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);
|
||||
@@ -1401,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;
|
||||
@@ -1432,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;
|
||||
@@ -1524,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;
|
||||
@@ -1987,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!");
|
||||
@@ -2084,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;
|
||||
@@ -2210,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);
|
||||
@@ -2260,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;
|
||||
@@ -2324,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;
|
||||
@@ -2371,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];
|
||||
@@ -2416,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;
|
||||
@@ -2461,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];
|
||||
@@ -2520,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
|
||||
@@ -2813,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;
|
||||
}
|
||||
@@ -2873,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;
|
||||
}
|
||||
@@ -3508,47 +3432,3 @@ SDL_Surface* bm_to_sdl_surface(int handle) {
|
||||
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
-20
@@ -34,7 +34,6 @@
|
||||
|
||||
// Flag positions for bitmap.flags
|
||||
// ***** NOTE: bitmap.flags is an 8-bit value, no more BMP_TEX_* flags can be added unless the type is changed!! ******
|
||||
// Update: bitmap.flags type changed to 16-bit
|
||||
#define BMP_AABITMAP (1<<0) //!< antialiased bitmap
|
||||
#define BMP_TEX_XPARENT (1<<1) //!< transparent texture
|
||||
#define BMP_TEX_OTHER (1<<2) //!< so we can identify all "normal" textures
|
||||
@@ -44,14 +43,9 @@
|
||||
#define BMP_TEX_BC7 (1<<6) //!< BC7 compressed 8r8g8b8a (32bit)
|
||||
#define BMP_TEX_CUBEMAP (1<<7) //!< a texture made for cubic environment map
|
||||
#define BMP_MASK_BITMAP (1<<8) //!< a bitmap that will be used for masking mouse interaction. Typically not used in render operations
|
||||
#define BMP_TEX_ETC2_RGB8 (1 << 9) //!< ETC2 RGB compressed (24bit, no alpha)
|
||||
#define BMP_TEX_ETC2_RGBA1 (1 << 10) //!< ETC2 RGBA1 compressed (24bit, 1 alpha)
|
||||
#define BMP_TEX_ETC2_RGBA8 (1 << 11) //!< ETC2 RGBA8 compressed (32bit, 8 alpha)
|
||||
|
||||
|
||||
// Combined flags
|
||||
#define BMP_TEX_COMP ( BMP_TEX_DXT1 | BMP_TEX_DXT3 | BMP_TEX_DXT5 | BMP_TEX_BC7 | BMP_TEX_ETC2_RGB8 |\
|
||||
BMP_TEX_ETC2_RGBA1 | BMP_TEX_ETC2_RGBA8 ) //!< Compressed textures
|
||||
#define BMP_TEX_COMP ( BMP_TEX_DXT1 | BMP_TEX_DXT3 | BMP_TEX_DXT5 | BMP_TEX_BC7 ) //!< Compressed textures
|
||||
#define BMP_TEX_NONCOMP ( BMP_TEX_XPARENT | BMP_TEX_OTHER ) //!< Non-compressed textures
|
||||
#define BMP_TEX_ANY ( BMP_TEX_COMP | BMP_TEX_NONCOMP ) //!< Any texture
|
||||
|
||||
@@ -87,15 +81,7 @@ enum BM_TYPE
|
||||
BM_TYPE_CUBEMAP_DXT3, //!< 32-bit cubemap (compressed cubemap surface)
|
||||
BM_TYPE_CUBEMAP_DXT5, //!< 32-bit cubemap (compressed cubemap surface)
|
||||
|
||||
BM_TYPE_3D, //!< 3D in-memory
|
||||
|
||||
BM_TYPE_KTX, //!< generic identifier for KTX1
|
||||
BM_TYPE_ETC2_RGB, //!< 24 bit, no alpha
|
||||
BM_TYPE_ETC2_SRGB, //!< 24 bit, no alpha, signed
|
||||
BM_TYPE_ETC2_RGBA1, //!< 24 bit, 1 bit alpha
|
||||
BM_TYPE_ETC2_SRGBA1, //!< 24 bit, 1 bit alpha, signed
|
||||
BM_TYPE_ETC2_RGBA_EAC, //!< 32 bit, 8 bit alpha
|
||||
BM_TYPE_ETC2_SRGBA_EAC //!< 32 bit, 8 bit alpha, signed
|
||||
BM_TYPE_3D //!< 3D in-memory
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -110,7 +96,7 @@ struct bitmap
|
||||
short rowsize; //!< What you need to add to go to next row
|
||||
int bpp; //!< Requested bitdepth of each pixel. ( 7, 8, 15, 16, 24, 32)
|
||||
int true_bpp; //!< The image's actual bitdepth
|
||||
uint flags; //!< Various texture type flags. @see BMPMAN_CONSTANTS
|
||||
ushort flags; //!< Various texture type flags. @see BMPMAN_CONSTANTS
|
||||
ptr_u data; //!< Pointer to data, or maybe offset into VRAM.
|
||||
ubyte *palette; /**< @brief Pointer to this bitmap's palette (if it has one).
|
||||
* @details If BMP_NO_PALETTE_MAP flag is cleared, this palette just points to the screen palette. (gr_palette)
|
||||
@@ -149,7 +135,6 @@ void bm_close();
|
||||
#define BMP_FLAG_RENDER_TARGET_DYNAMIC (1<<1)
|
||||
#define BMP_FLAG_CUBEMAP (1<<2)
|
||||
#define BMP_FLAG_RENDER_TARGET_MIPMAP (1<<3)
|
||||
#define BMP_FLAG_RENDER_TARGET_DEPTH_ATTACHMENT (1<<4)
|
||||
|
||||
/**
|
||||
* @brief Allocates memory for the given handle.
|
||||
@@ -359,7 +344,7 @@ int bm_load_either(const char *filename, int *nframes = NULL, int *fps = NULL, i
|
||||
* @returns A pointer to the bitmap that's valid until bm_unlock is called if successful, or
|
||||
* @returns NULL if unsuccessful
|
||||
*/
|
||||
bitmap* bm_lock(int handle, int bpp, uint flags, bool nodebug = false);
|
||||
bitmap* bm_lock(int handle, int bpp, ushort flags, bool nodebug = false);
|
||||
|
||||
/**
|
||||
* @brief Returns the image type of the given bitmap handle
|
||||
@@ -402,7 +387,7 @@ int bm_is_valid(int handle);
|
||||
* @returns The handle to the first frame on success, or
|
||||
* @returns -1 on failure
|
||||
*/
|
||||
int bm_get_info(int handle, int *w = nullptr, int * h = nullptr, uint* flags = nullptr, int *nframes = nullptr, int *fps = nullptr);
|
||||
int bm_get_info(int handle, int *w = nullptr, int * h = nullptr, ushort* flags = nullptr, int *nframes = nullptr, int *fps = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Gets 3D info on the bitmap indexed by handle.
|
||||
|
||||
+19
-45
@@ -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,7 +89,24 @@ 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})
|
||||
@@ -124,28 +121,9 @@ auto CockpitFovOption = options::OptionBuilder<float>("Graphics.CockpitFOV",
|
||||
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;})
|
||||
.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)
|
||||
.parser(parse_cockpit_fov_toggle_func)
|
||||
.finish();
|
||||
|
||||
//*************************CLASS: camera*************************
|
||||
@@ -754,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();
|
||||
}
|
||||
|
||||
@@ -1317,9 +1294,6 @@ float cam_get_bbox_dist(const object* viewer_obj, float preferred_distance, cons
|
||||
return preferred_distance;
|
||||
|
||||
polymodel* pm = object_get_model(viewer_obj);
|
||||
if (pm == nullptr)
|
||||
return preferred_distance;
|
||||
|
||||
vec3d adjusted_bbox;
|
||||
const vec3d* cam_vec = &cam_orient->vec.fvec;
|
||||
|
||||
|
||||
@@ -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);
|
||||
+11
-12
@@ -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 .qch .css .png .jpg", CF_TYPE_DATA }
|
||||
{ CF_TYPE_FREDDOCS, "data" DIR_SEPARATOR_STR "freddocs", ".html", CF_TYPE_DATA }
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
@@ -186,7 +186,6 @@ int cfile_init(const char *exe_dir, const char *cdrom_dir)
|
||||
char buf[CFILE_ROOT_DIRECTORY_LEN];
|
||||
|
||||
strncpy(buf, exe_dir, CFILE_ROOT_DIRECTORY_LEN - 1);
|
||||
|
||||
buf[CFILE_ROOT_DIRECTORY_LEN - 1] = '\0';
|
||||
|
||||
// are we in a root directory?
|
||||
@@ -903,7 +902,7 @@ static CFILE *cf_open_fill_cfblock(const char* source, int line, const char* ori
|
||||
cfp->source_file = source;
|
||||
cfp->line_num = line;
|
||||
|
||||
auto pos = ftell(fp);
|
||||
int pos = ftell(fp);
|
||||
if(pos == -1L)
|
||||
pos = 0;
|
||||
cf_init_lowlevel_read_code(cfp,0,filelength(fileno(fp)), 0 );
|
||||
|
||||
@@ -143,7 +143,7 @@ void lz41_load_offsets(CFILE* cf)
|
||||
int* offsets_ptr = cf->compression_info.offsets;
|
||||
|
||||
/* Seek to the first offset position, remember to consider the trailing ints */
|
||||
fso_fseek(cf, static_cast<int>( ( sizeof(int) * cf->compression_info.num_offsets ) * -1 ) - (sizeof(int)*3 ), SEEK_END);
|
||||
fso_fseek(cf, ( ( sizeof(int) * cf->compression_info.num_offsets ) * -1 ) - (sizeof(int)*3 ), SEEK_END);
|
||||
for (block = 0; block < cf->compression_info.num_offsets; ++block)
|
||||
{
|
||||
auto bytes_read = fread(offsets_ptr++, sizeof(int), 1, cf->fp);
|
||||
|
||||
@@ -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)) { }
|
||||
|
||||
|
||||
@@ -534,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 multithreading("-threads", nullptr, AT_INT);
|
||||
|
||||
char *Cmdline_start_mission = NULL;
|
||||
int Cmdline_dis_collisions = 0;
|
||||
@@ -573,7 +572,6 @@ bool Cmdline_lua_devmode = false;
|
||||
bool Cmdline_override_data = false;
|
||||
bool Cmdline_show_imgui_debug = false;
|
||||
bool Cmdline_vulkan = false;
|
||||
int Cmdline_multithreading = 1;
|
||||
|
||||
// Other
|
||||
cmdline_parm get_flags_arg(GET_FLAGS_STRING, "Output the launcher flags file", AT_STRING);
|
||||
@@ -1322,7 +1320,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
|
||||
@@ -1414,7 +1412,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);
|
||||
@@ -2409,10 +2407,6 @@ bool SetCmdlineParams()
|
||||
}
|
||||
}
|
||||
|
||||
if (multithreading.found()) {
|
||||
Cmdline_multithreading = abs(multithreading.get_int());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -159,7 +159,6 @@ extern bool Cmdline_lua_devmode;
|
||||
extern bool Cmdline_override_data;
|
||||
extern bool Cmdline_show_imgui_debug;
|
||||
extern bool Cmdline_vulkan;
|
||||
extern int Cmdline_multithreading;
|
||||
|
||||
enum class WeaponSpewType { NONE = 0, STANDARD, ALL };
|
||||
extern WeaponSpewType Cmdline_spew_weapon_stats;
|
||||
|
||||
+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();
|
||||
@@ -1304,8 +1298,7 @@ bool control_config_accept(bool API_Access)
|
||||
cstr = popup_input(flags,
|
||||
XSTR( "Confirm new custom preset name.\n\nThe name must not be empty or a default preset.\n\n Press [Enter] to accept, [Esc] to abort to config menu.", 1867),
|
||||
32 - 6,
|
||||
default_string.c_str(),
|
||||
"-_");
|
||||
default_string.c_str());
|
||||
if (cstr == nullptr) {
|
||||
// Abort
|
||||
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
|
||||
@@ -2091,6 +2084,7 @@ int control_config_bind_key_on_frame(int ctrl, selItem item, bool API_Access)
|
||||
|
||||
if (!done && bind) {
|
||||
if (!Axis_override.empty()) {
|
||||
control_config_bind(ctrl, Axis_override, item, API_Access);
|
||||
control_config_bind(ctrl, Axis_override, item, API_Access);
|
||||
done = true;
|
||||
strcpy_s(bound_string, Axis_override.textify().c_str());
|
||||
@@ -2724,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) {
|
||||
@@ -2807,22 +2802,8 @@ void control_check_indicate()
|
||||
Control_check_count = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if a control is being used by the player this frame by checking the bound control input bindings.
|
||||
*
|
||||
* @param[in] id The IoActionId of the control to check
|
||||
* @param[in] key DO NOT USE. Key combination acquired from game_poll(), or -1 to check against a previous poll
|
||||
*
|
||||
* @returns 0 If the control was disabled by a mod, or
|
||||
* @returns 0 If locked by a script, or
|
||||
* @returns 0 If controls need to be ignored for multiplayer, or
|
||||
* @returns 0 If the control wasn't used, or
|
||||
* @returns 1 If the control was used
|
||||
*/
|
||||
int check_control_used(int id, int key)
|
||||
{
|
||||
// Make sure mouse_down() is only called once during any logic path,
|
||||
// or the mousewheel may be decayed multiple times!!
|
||||
int mask;
|
||||
static int last_key = 0;
|
||||
auto & item = Control_config[id];
|
||||
@@ -2842,19 +2823,12 @@ 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) {
|
||||
|
||||
// this is awful, need to make a reverse lookup table to do
|
||||
// button -> control instead of this control -> button nonsense.
|
||||
// this is awful, need to make a reverse lookup table to do button -> control instead of this control -> button
|
||||
// nonsense.
|
||||
if ((joy_down(item.first) || joy_down_count(item.first, 1)) ||
|
||||
(joy_down(item.second) || joy_down_count(item.second, 1))) {
|
||||
// Joy button bound to this control was pressed, control activated
|
||||
@@ -2864,7 +2838,7 @@ int check_control_used(int id, int key)
|
||||
|
||||
if ((mouse_down(item.first) || mouse_down_count(item.first, 1)) ||
|
||||
(mouse_down(item.second) || mouse_down_count(item.second, 1))) {
|
||||
// Mouse button bound to this control was pressed, control activated
|
||||
// Joy button bound to this control was pressed, control activated
|
||||
control_used(id);
|
||||
return 1;
|
||||
}
|
||||
@@ -2910,15 +2884,6 @@ int check_control_used(int id, int key)
|
||||
return 1;
|
||||
}
|
||||
|
||||
// special case to allow actual mouse wheel to work with trigger controls --wookieejedi
|
||||
if (item.type == CC_TYPE_TRIGGER) {
|
||||
if ( mouse_down(item.first, true) || mouse_down(item.second, true) ) {
|
||||
// Mouse wheel bound to this trigger control was pressed, control activated
|
||||
control_used(id);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -297,24 +297,10 @@ enum IoActionId : int {
|
||||
JOY_ABS_THROTTLE_AXIS = 127,
|
||||
JOY_REL_THROTTLE_AXIS = 128,
|
||||
|
||||
//!< @n
|
||||
//! Communication menu controls
|
||||
//! ----------------------------
|
||||
COMMS_MENU_MOVE_UP,
|
||||
COMMS_MENU_MOVE_DOWN,
|
||||
COMMS_MENU_SELECT,
|
||||
|
||||
TOGGLE_HUD_SHADOWS,
|
||||
|
||||
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
|
||||
*/
|
||||
@@ -592,10 +578,6 @@ public:
|
||||
* 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
|
||||
@@ -604,7 +586,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
|
||||
|
||||
@@ -677,7 +658,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
|
||||
@@ -956,12 +937,8 @@ float check_control_timef(int id);
|
||||
* @brief Wrapper for check_control_used. Allows the game to ignore the key if told to do so by the ignore-key SEXP.
|
||||
*
|
||||
* @param[in] id The IoActionId of the control to check
|
||||
* @param[in] key DO NOT USE OUTSIDE OF THE MAIN LOOP. Key combination acquired from game_poll(), or -1 to check against a previous poll
|
||||
* @param[in] key The key combo to check against the control. If -1, re-check the last key passed to this function
|
||||
*
|
||||
* @returns 0 If the control was disabled by a mod, or
|
||||
* @returns 0 If locked by a script, or
|
||||
* @returns 0 If controls need to be ignored for multiplayer, or
|
||||
* @returns 0 If a script is handling the control execution, or
|
||||
* @returns 0 If the control wasn't used, or
|
||||
* @returns 1 If the control was used
|
||||
*
|
||||
|
||||
@@ -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)
|
||||
@@ -280,13 +272,6 @@ void control_config_common_init_bindings() {
|
||||
(CUSTOM_CONTROL_3, KEY_ALTED | KEY_SHIFTED | KEY_3, -1, COMPUTER_TAB, 1786, "Custom Control 3", CC_TYPE_TRIGGER, true)
|
||||
(CUSTOM_CONTROL_4, KEY_ALTED | KEY_SHIFTED | KEY_4, -1, COMPUTER_TAB, 1787, "Custom Control 4", CC_TYPE_TRIGGER, true)
|
||||
(CUSTOM_CONTROL_5, KEY_ALTED | KEY_SHIFTED | KEY_5, -1, COMPUTER_TAB, 1788, "Custom Control 5", CC_TYPE_TRIGGER, true)
|
||||
|
||||
|
||||
//Comms Controls
|
||||
(COMMS_MENU_MOVE_UP, -1, -1, COMPUTER_TAB, 1883, "Communication Menu Move Up", CC_TYPE_TRIGGER)
|
||||
(COMMS_MENU_MOVE_DOWN, -1, -1, COMPUTER_TAB, 1884, "Communication Menu Move Down", CC_TYPE_TRIGGER)
|
||||
(COMMS_MENU_SELECT, -1, -1, COMPUTER_TAB, 1885, "Communication Menu Select", CC_TYPE_TRIGGER)
|
||||
|
||||
.end(); // Builder
|
||||
|
||||
// init default preset
|
||||
@@ -440,12 +425,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},
|
||||
|
||||
@@ -459,9 +438,6 @@ SCP_unordered_map<SCP_string, IoActionId> old_text = {
|
||||
{"Custom Control 3", CUSTOM_CONTROL_3},
|
||||
{"Custom Control 4", CUSTOM_CONTROL_4},
|
||||
{"Custom Control 5", CUSTOM_CONTROL_5},
|
||||
{"Communication Menu Move Up", COMMS_MENU_MOVE_UP},
|
||||
{"Communication Menu Move Down", COMMS_MENU_MOVE_DOWN},
|
||||
{"Communication Menu Select", COMMS_MENU_SELECT},
|
||||
};
|
||||
|
||||
// Localization strings for hat positions. Back[0], Forward[1], Left[2], Right[3]
|
||||
@@ -1165,12 +1141,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)
|
||||
|
||||
@@ -1194,10 +1164,6 @@ void LoadEnumsIntoActionMap() {
|
||||
ADD_ENUM_TO_ACTION_MAP(JOY_ABS_THROTTLE_AXIS)
|
||||
ADD_ENUM_TO_ACTION_MAP(JOY_REL_THROTTLE_AXIS)
|
||||
|
||||
ADD_ENUM_TO_ACTION_MAP(COMMS_MENU_MOVE_UP)
|
||||
ADD_ENUM_TO_ACTION_MAP(COMMS_MENU_MOVE_DOWN)
|
||||
ADD_ENUM_TO_ACTION_MAP(COMMS_MENU_SELECT)
|
||||
|
||||
|
||||
#undef ADD_ENUM_TO_ACTION_MAP
|
||||
|
||||
@@ -2838,7 +2804,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;
|
||||
};
|
||||
@@ -2921,7 +2886,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];
|
||||
|
||||
@@ -2959,9 +2924,6 @@ 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,10 +12,9 @@ DecoderStatus::~DecoderStatus() {
|
||||
videoCodec = nullptr;
|
||||
|
||||
if (videoCodecCtx != nullptr) {
|
||||
avcodec_close(videoCodecCtx);
|
||||
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
|
||||
avcodec_free_context(&videoCodecCtx);
|
||||
#else
|
||||
avcodec_close(videoCodecCtx);
|
||||
#endif
|
||||
videoCodecCtx = nullptr;
|
||||
}
|
||||
@@ -25,10 +24,9 @@ DecoderStatus::~DecoderStatus() {
|
||||
audioCodec = nullptr;
|
||||
|
||||
if (audioCodecCtx != nullptr) {
|
||||
avcodec_close(audioCodecCtx);
|
||||
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
|
||||
avcodec_free_context(&audioCodecCtx);
|
||||
#else
|
||||
avcodec_close(audioCodecCtx);
|
||||
#endif
|
||||
audioCodecCtx = nullptr;
|
||||
}
|
||||
@@ -38,10 +36,9 @@ DecoderStatus::~DecoderStatus() {
|
||||
subtitleCodec = nullptr;
|
||||
|
||||
if (subtitleCodecCtx != nullptr) {
|
||||
avcodec_close(subtitleCodecCtx);
|
||||
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
|
||||
avcodec_free_context(&subtitleCodecCtx);
|
||||
#else
|
||||
avcodec_close(subtitleCodecCtx);
|
||||
#endif
|
||||
subtitleCodecCtx = nullptr;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
+30
-190
@@ -1,4 +1,4 @@
|
||||
/* bcdec.h - v0.97
|
||||
/* bcdec.h - v0.96
|
||||
provides functions to decompress blocks of BC compressed images
|
||||
written by Sergii "iOrange" Kudlai in 2022
|
||||
|
||||
@@ -23,10 +23,6 @@
|
||||
|
||||
For more info, issues and suggestions please visit https://github.com/iOrange/bcdec
|
||||
|
||||
Configuration:
|
||||
#define BCDEC_BC4BC5_PRECISE:
|
||||
enables more precise but slower BC4/BC5 decoding + signed/unsigned mode
|
||||
|
||||
CREDITS:
|
||||
Aras Pranckevicius (@aras-p) - BC1/BC3 decoders optimizations (up to 3x the speed)
|
||||
- BC6H/BC7 bits pulling routines optimizations
|
||||
@@ -34,11 +30,6 @@
|
||||
- Split BC6H decompression function into 'half' and
|
||||
'float' variants
|
||||
|
||||
Michael Schmidt (@RunDevelopment) - Found better "magic" coefficients for integer interpolation
|
||||
of reference colors in BC1 color block, that match with
|
||||
the floating point interpolation. This also made it faster
|
||||
than integer division by 3!
|
||||
|
||||
bugfixes:
|
||||
@linkmauve
|
||||
|
||||
@@ -48,9 +39,6 @@
|
||||
#ifndef BCDEC_HEADER_INCLUDED
|
||||
#define BCDEC_HEADER_INCLUDED
|
||||
|
||||
#define BCDEC_VERSION_MAJOR 0
|
||||
#define BCDEC_VERSION_MINOR 98
|
||||
|
||||
/* if BCDEC_STATIC causes problems, try defining BCDECDEF to 'inline' or 'static inline' */
|
||||
#ifndef BCDECDEF
|
||||
#ifdef BCDEC_STATIC
|
||||
@@ -102,20 +90,12 @@
|
||||
BCDECDEF void bcdec_bc1(const void* compressedBlock, void* decompressedBlock, int destinationPitch);
|
||||
BCDECDEF void bcdec_bc2(const void* compressedBlock, void* decompressedBlock, int destinationPitch);
|
||||
BCDECDEF void bcdec_bc3(const void* compressedBlock, void* decompressedBlock, int destinationPitch);
|
||||
#ifndef BCDEC_BC4BC5_PRECISE
|
||||
BCDECDEF void bcdec_bc4(const void* compressedBlock, void* decompressedBlock, int destinationPitch);
|
||||
BCDECDEF void bcdec_bc5(const void* compressedBlock, void* decompressedBlock, int destinationPitch);
|
||||
#else
|
||||
BCDECDEF void bcdec_bc4(const void* compressedBlock, void* decompressedBlock, int destinationPitch, int isSigned);
|
||||
BCDECDEF void bcdec_bc5(const void* compressedBlock, void* decompressedBlock, int destinationPitch, int isSigned);
|
||||
BCDECDEF void bcdec_bc4_float(const void* compressedBlock, void* decompressedBlock, int destinationPitch, int isSigned);
|
||||
BCDECDEF void bcdec_bc5_float(const void* compressedBlock, void* decompressedBlock, int destinationPitch, int isSigned);
|
||||
#endif
|
||||
BCDECDEF void bcdec_bc6h_float(const void* compressedBlock, void* decompressedBlock, int destinationPitch, int isSigned);
|
||||
BCDECDEF void bcdec_bc6h_half(const void* compressedBlock, void* decompressedBlock, int destinationPitch, int isSigned);
|
||||
BCDECDEF void bcdec_bc7(const void* compressedBlock, void* decompressedBlock, int destinationPitch);
|
||||
|
||||
#endif /* BCDEC_HEADER_INCLUDED */
|
||||
|
||||
#ifdef BCDEC_IMPLEMENTATION
|
||||
|
||||
@@ -130,44 +110,35 @@ static void bcdec__color_block(const void* compressedBlock, void* decompressedBl
|
||||
c0 = ((unsigned short*)compressedBlock)[0];
|
||||
c1 = ((unsigned short*)compressedBlock)[1];
|
||||
|
||||
/* Unpack 565 ref colors */
|
||||
r0 = (c0 >> 11) & 0x1F;
|
||||
g0 = (c0 >> 5) & 0x3F;
|
||||
b0 = c0 & 0x1F;
|
||||
|
||||
r1 = (c1 >> 11) & 0x1F;
|
||||
g1 = (c1 >> 5) & 0x3F;
|
||||
b1 = c1 & 0x1F;
|
||||
|
||||
/* Expand 565 ref colors to 888 */
|
||||
r = (r0 * 527 + 23) >> 6;
|
||||
g = (g0 * 259 + 33) >> 6;
|
||||
b = (b0 * 527 + 23) >> 6;
|
||||
refColors[0] = 0xFF000000 | (b << 16) | (g << 8) | r;
|
||||
r0 = (((c0 >> 11) & 0x1F) * 527 + 23) >> 6;
|
||||
g0 = (((c0 >> 5) & 0x3F) * 259 + 33) >> 6;
|
||||
b0 = ((c0 & 0x1F) * 527 + 23) >> 6;
|
||||
refColors[0] = 0xFF000000 | (b0 << 16) | (g0 << 8) | r0;
|
||||
|
||||
r = (r1 * 527 + 23) >> 6;
|
||||
g = (g1 * 259 + 33) >> 6;
|
||||
b = (b1 * 527 + 23) >> 6;
|
||||
refColors[1] = 0xFF000000 | (b << 16) | (g << 8) | r;
|
||||
r1 = (((c1 >> 11) & 0x1F) * 527 + 23) >> 6;
|
||||
g1 = (((c1 >> 5) & 0x3F) * 259 + 33) >> 6;
|
||||
b1 = ((c1 & 0x1F) * 527 + 23) >> 6;
|
||||
refColors[1] = 0xFF000000 | (b1 << 16) | (g1 << 8) | r1;
|
||||
|
||||
if (c0 > c1 || onlyOpaqueMode) { /* Standard BC1 mode (also BC3 color block uses ONLY this mode) */
|
||||
/* color_2 = 2/3*color_0 + 1/3*color_1
|
||||
color_3 = 1/3*color_0 + 2/3*color_1 */
|
||||
r = ((2 * r0 + r1) * 351 + 61) >> 7;
|
||||
g = ((2 * g0 + g1) * 2763 + 1039) >> 11;
|
||||
b = ((2 * b0 + b1) * 351 + 61) >> 7;
|
||||
r = (2 * r0 + r1 + 1) / 3;
|
||||
g = (2 * g0 + g1 + 1) / 3;
|
||||
b = (2 * b0 + b1 + 1) / 3;
|
||||
refColors[2] = 0xFF000000 | (b << 16) | (g << 8) | r;
|
||||
|
||||
r = ((r0 + r1 * 2) * 351 + 61) >> 7;
|
||||
g = ((g0 + g1 * 2) * 2763 + 1039) >> 11;
|
||||
b = ((b0 + b1 * 2) * 351 + 61) >> 7;
|
||||
r = (r0 + 2 * r1 + 1) / 3;
|
||||
g = (g0 + 2 * g1 + 1) / 3;
|
||||
b = (b0 + 2 * b1 + 1) / 3;
|
||||
refColors[3] = 0xFF000000 | (b << 16) | (g << 8) | r;
|
||||
} else { /* Quite rare BC1A mode */
|
||||
/* color_2 = 1/2*color_0 + 1/2*color_1;
|
||||
color_3 = 0; */
|
||||
r = ((r0 + r1) * 1053 + 125) >> 8;
|
||||
g = ((g0 + g1) * 4145 + 1019) >> 11;
|
||||
b = ((b0 + b1) * 1053 + 125) >> 8;
|
||||
r = (r0 + r1 + 1) >> 1;
|
||||
g = (g0 + g1 + 1) >> 1;
|
||||
b = (b0 + b1 + 1) >> 1;
|
||||
refColors[2] = 0xFF000000 | (b << 16) | (g << 8) | r;
|
||||
|
||||
refColors[3] = 0x00000000;
|
||||
@@ -219,19 +190,19 @@ static void bcdec__smooth_alpha_block(const void* compressedBlock, void* decompr
|
||||
|
||||
if (alpha[0] > alpha[1]) {
|
||||
/* 6 interpolated alpha values. */
|
||||
alpha[2] = (6 * alpha[0] + alpha[1]) / 7; /* 6/7*alpha_0 + 1/7*alpha_1 */
|
||||
alpha[3] = (5 * alpha[0] + 2 * alpha[1]) / 7; /* 5/7*alpha_0 + 2/7*alpha_1 */
|
||||
alpha[4] = (4 * alpha[0] + 3 * alpha[1]) / 7; /* 4/7*alpha_0 + 3/7*alpha_1 */
|
||||
alpha[5] = (3 * alpha[0] + 4 * alpha[1]) / 7; /* 3/7*alpha_0 + 4/7*alpha_1 */
|
||||
alpha[6] = (2 * alpha[0] + 5 * alpha[1]) / 7; /* 2/7*alpha_0 + 5/7*alpha_1 */
|
||||
alpha[7] = ( alpha[0] + 6 * alpha[1]) / 7; /* 1/7*alpha_0 + 6/7*alpha_1 */
|
||||
alpha[2] = (6 * alpha[0] + alpha[1] + 1) / 7; /* 6/7*alpha_0 + 1/7*alpha_1 */
|
||||
alpha[3] = (5 * alpha[0] + 2 * alpha[1] + 1) / 7; /* 5/7*alpha_0 + 2/7*alpha_1 */
|
||||
alpha[4] = (4 * alpha[0] + 3 * alpha[1] + 1) / 7; /* 4/7*alpha_0 + 3/7*alpha_1 */
|
||||
alpha[5] = (3 * alpha[0] + 4 * alpha[1] + 1) / 7; /* 3/7*alpha_0 + 4/7*alpha_1 */
|
||||
alpha[6] = (2 * alpha[0] + 5 * alpha[1] + 1) / 7; /* 2/7*alpha_0 + 5/7*alpha_1 */
|
||||
alpha[7] = ( alpha[0] + 6 * alpha[1] + 1) / 7; /* 1/7*alpha_0 + 6/7*alpha_1 */
|
||||
}
|
||||
else {
|
||||
/* 4 interpolated alpha values. */
|
||||
alpha[2] = (4 * alpha[0] + alpha[1]) / 5; /* 4/5*alpha_0 + 1/5*alpha_1 */
|
||||
alpha[3] = (3 * alpha[0] + 2 * alpha[1]) / 5; /* 3/5*alpha_0 + 2/5*alpha_1 */
|
||||
alpha[4] = (2 * alpha[0] + 3 * alpha[1]) / 5; /* 2/5*alpha_0 + 3/5*alpha_1 */
|
||||
alpha[5] = ( alpha[0] + 4 * alpha[1]) / 5; /* 1/5*alpha_0 + 4/5*alpha_1 */
|
||||
alpha[2] = (4 * alpha[0] + alpha[1] + 1) / 5; /* 4/5*alpha_0 + 1/5*alpha_1 */
|
||||
alpha[3] = (3 * alpha[0] + 2 * alpha[1] + 1) / 5; /* 3/5*alpha_0 + 2/5*alpha_1 */
|
||||
alpha[4] = (2 * alpha[0] + 3 * alpha[1] + 1) / 5; /* 2/5*alpha_0 + 3/5*alpha_1 */
|
||||
alpha[5] = ( alpha[0] + 4 * alpha[1] + 1) / 5; /* 1/5*alpha_0 + 4/5*alpha_1 */
|
||||
alpha[6] = 0x00;
|
||||
alpha[7] = 0xFF;
|
||||
}
|
||||
@@ -247,117 +218,6 @@ static void bcdec__smooth_alpha_block(const void* compressedBlock, void* decompr
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef BCDEC_BC4BC5_PRECISE
|
||||
static void bcdec__bc4_block(const void* compressedBlock, void* decompressedBlock, int destinationPitch, int pixelSize, int isSigned) {
|
||||
signed char* sblock;
|
||||
unsigned char* ublock;
|
||||
int alpha[8];
|
||||
int i, j;
|
||||
unsigned long long block, indices;
|
||||
|
||||
static int aWeights4[4] = { 13107, 26215, 39321, 52429 };
|
||||
static int aWeights6[6] = { 9363, 18724, 28086, 37450, 46812, 56173 };
|
||||
|
||||
block = *(unsigned long long*)compressedBlock;
|
||||
|
||||
if (isSigned) {
|
||||
alpha[0] = (char)(block & 0xFF);
|
||||
alpha[1] = (char)((block >> 8) & 0xFF);
|
||||
if (alpha[0] < -127) alpha[0] = -127; /* -128 clamps to -127 */
|
||||
if (alpha[1] < -127) alpha[1] = -127; /* -128 clamps to -127 */
|
||||
} else {
|
||||
alpha[0] = block & 0xFF;
|
||||
alpha[1] = (block >> 8) & 0xFF;
|
||||
}
|
||||
|
||||
if (alpha[0] > alpha[1]) {
|
||||
/* 6 interpolated alpha values. */
|
||||
alpha[2] = (aWeights6[5] * alpha[0] + aWeights6[0] * alpha[1] + 32768) >> 16; /* 6/7*alpha_0 + 1/7*alpha_1 */
|
||||
alpha[3] = (aWeights6[4] * alpha[0] + aWeights6[1] * alpha[1] + 32768) >> 16; /* 5/7*alpha_0 + 2/7*alpha_1 */
|
||||
alpha[4] = (aWeights6[3] * alpha[0] + aWeights6[2] * alpha[1] + 32768) >> 16; /* 4/7*alpha_0 + 3/7*alpha_1 */
|
||||
alpha[5] = (aWeights6[2] * alpha[0] + aWeights6[3] * alpha[1] + 32768) >> 16; /* 3/7*alpha_0 + 4/7*alpha_1 */
|
||||
alpha[6] = (aWeights6[1] * alpha[0] + aWeights6[4] * alpha[1] + 32768) >> 16; /* 2/7*alpha_0 + 5/7*alpha_1 */
|
||||
alpha[7] = (aWeights6[0] * alpha[0] + aWeights6[5] * alpha[1] + 32768) >> 16; /* 1/7*alpha_0 + 6/7*alpha_1 */
|
||||
} else {
|
||||
/* 4 interpolated alpha values. */
|
||||
alpha[2] = (aWeights4[3] * alpha[0] + aWeights4[0] * alpha[1] + 32768) >> 16; /* 4/5*alpha_0 + 1/5*alpha_1 */
|
||||
alpha[3] = (aWeights4[2] * alpha[0] + aWeights4[1] * alpha[1] + 32768) >> 16; /* 3/5*alpha_0 + 2/5*alpha_1 */
|
||||
alpha[4] = (aWeights4[1] * alpha[0] + aWeights4[2] * alpha[1] + 32768) >> 16; /* 2/5*alpha_0 + 3/5*alpha_1 */
|
||||
alpha[5] = (aWeights4[0] * alpha[0] + aWeights4[3] * alpha[1] + 32768) >> 16; /* 1/5*alpha_0 + 4/5*alpha_1 */
|
||||
alpha[6] = isSigned ? -127 : 0;
|
||||
alpha[7] = isSigned ? 127 : 255;
|
||||
}
|
||||
|
||||
indices = block >> 16;
|
||||
if (isSigned) {
|
||||
sblock = (char*)decompressedBlock;
|
||||
for (i = 0; i < 4; ++i) {
|
||||
for (j = 0; j < 4; ++j) {
|
||||
sblock[j * pixelSize] = (char)alpha[indices & 0x07];
|
||||
indices >>= 3;
|
||||
}
|
||||
sblock += destinationPitch;
|
||||
}
|
||||
} else {
|
||||
ublock = (unsigned char*)decompressedBlock;
|
||||
for (i = 0; i < 4; ++i) {
|
||||
for (j = 0; j < 4; ++j) {
|
||||
ublock[j * pixelSize] = (unsigned char)alpha[indices & 0x07];
|
||||
indices >>= 3;
|
||||
}
|
||||
ublock += destinationPitch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void bcdec__bc4_block_float(const void* compressedBlock, void* decompressedBlock, int destinationPitch, int pixelSize, int isSigned) {
|
||||
float* decompressed;
|
||||
float alpha[8];
|
||||
int i, j;
|
||||
unsigned long long block, indices;
|
||||
|
||||
block = *(unsigned long long*)compressedBlock;
|
||||
decompressed = (float*)decompressedBlock;
|
||||
|
||||
if (isSigned) {
|
||||
alpha[0] = (float)((char)(block & 0xFF)) / 127.0f;
|
||||
alpha[1] = (float)((char)((block >> 8) & 0xFF)) / 127.0f;
|
||||
if (alpha[0] < -1.0f) alpha[0] = -1.0f; /* -128 clamps to -127 */
|
||||
if (alpha[1] < -1.0f) alpha[1] = -1.0f; /* -128 clamps to -127 */
|
||||
} else {
|
||||
alpha[0] = (float)(block & 0xFF) / 255.0f;
|
||||
alpha[1] = (float)((block >> 8) & 0xFF) / 255.0f;
|
||||
}
|
||||
|
||||
if (alpha[0] > alpha[1]) {
|
||||
/* 6 interpolated alpha values. */
|
||||
alpha[2] = (6.0f * alpha[0] + alpha[1]) / 7.0f; /* 6/7*alpha_0 + 1/7*alpha_1 */
|
||||
alpha[3] = (5.0f * alpha[0] + 2.0f * alpha[1]) / 7.0f; /* 5/7*alpha_0 + 2/7*alpha_1 */
|
||||
alpha[4] = (4.0f * alpha[0] + 3.0f * alpha[1]) / 7.0f; /* 4/7*alpha_0 + 3/7*alpha_1 */
|
||||
alpha[5] = (3.0f * alpha[0] + 4.0f * alpha[1]) / 7.0f; /* 3/7*alpha_0 + 4/7*alpha_1 */
|
||||
alpha[6] = (2.0f * alpha[0] + 5.0f * alpha[1]) / 7.0f; /* 2/7*alpha_0 + 5/7*alpha_1 */
|
||||
alpha[7] = ( alpha[0] + 6.0f * alpha[1]) / 7.0f; /* 1/7*alpha_0 + 6/7*alpha_1 */
|
||||
} else {
|
||||
/* 4 interpolated alpha values. */
|
||||
alpha[2] = (4.0f * alpha[0] + alpha[1]) / 5.0f; /* 4/5*alpha_0 + 1/5*alpha_1 */
|
||||
alpha[3] = (3.0f * alpha[0] + 2.0f * alpha[1]) / 5.0f; /* 3/5*alpha_0 + 2/5*alpha_1 */
|
||||
alpha[4] = (2.0f * alpha[0] + 3.0f * alpha[1]) / 5.0f; /* 2/5*alpha_0 + 3/5*alpha_1 */
|
||||
alpha[5] = ( alpha[0] + 4.0f * alpha[1]) / 5.0f; /* 1/5*alpha_0 + 4/5*alpha_1 */
|
||||
alpha[6] = isSigned ? -1.0f : 0.0f;
|
||||
alpha[7] = 1.0f;
|
||||
}
|
||||
|
||||
indices = block >> 16;
|
||||
for (i = 0; i < 4; ++i) {
|
||||
for (j = 0; j < 4; ++j) {
|
||||
decompressed[j * pixelSize] = alpha[indices & 0x07];
|
||||
indices >>= 3;
|
||||
}
|
||||
decompressed += destinationPitch;
|
||||
}
|
||||
}
|
||||
#endif /* BCDEC_BC4BC5_PRECISE */
|
||||
|
||||
typedef struct bcdec__bitstream {
|
||||
unsigned long long low;
|
||||
unsigned long long high;
|
||||
@@ -410,37 +270,15 @@ BCDECDEF void bcdec_bc3(const void* compressedBlock, void* decompressedBlock, in
|
||||
bcdec__smooth_alpha_block(compressedBlock, ((char*)decompressedBlock) + 3, destinationPitch, 4);
|
||||
}
|
||||
|
||||
#ifndef BCDEC_BC4BC5_PRECISE
|
||||
BCDECDEF void bcdec_bc4(const void* compressedBlock, void* decompressedBlock, int destinationPitch) {
|
||||
bcdec__smooth_alpha_block(compressedBlock, decompressedBlock, destinationPitch, 1);
|
||||
#else
|
||||
BCDECDEF void bcdec_bc4(const void* compressedBlock, void* decompressedBlock, int destinationPitch, int isSigned) {
|
||||
bcdec__bc4_block(compressedBlock, decompressedBlock, destinationPitch, 1, isSigned);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef BCDEC_BC4BC5_PRECISE
|
||||
BCDECDEF void bcdec_bc5(const void* compressedBlock, void* decompressedBlock, int destinationPitch) {
|
||||
bcdec__smooth_alpha_block(compressedBlock, decompressedBlock, destinationPitch, 2);
|
||||
bcdec__smooth_alpha_block(((char*)compressedBlock) + 8, ((char*)decompressedBlock) + 1, destinationPitch, 2);
|
||||
#else
|
||||
BCDECDEF void bcdec_bc5(const void* compressedBlock, void* decompressedBlock, int destinationPitch, int isSigned) {
|
||||
bcdec__bc4_block(compressedBlock, decompressedBlock, destinationPitch, 2, isSigned);
|
||||
bcdec__bc4_block(((char*)compressedBlock) + 8, ((char*)decompressedBlock) + 1, destinationPitch, 2, isSigned);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef BCDEC_BC4BC5_PRECISE
|
||||
BCDECDEF void bcdec_bc4_float(const void* compressedBlock, void* decompressedBlock, int destinationPitch, int isSigned) {
|
||||
bcdec__bc4_block_float(compressedBlock, decompressedBlock, destinationPitch, 1, isSigned);
|
||||
}
|
||||
|
||||
BCDECDEF void bcdec_bc5_float(const void* compressedBlock, void* decompressedBlock, int destinationPitch, int isSigned) {
|
||||
bcdec__bc4_block_float(compressedBlock, decompressedBlock, destinationPitch, 2, isSigned);
|
||||
bcdec__bc4_block_float(((char*)compressedBlock) + 8, ((float*)decompressedBlock) + 1, destinationPitch, 2, isSigned);
|
||||
}
|
||||
#endif /* BCDEC_BC4BC5_PRECISE */
|
||||
|
||||
/* http://graphics.stanford.edu/~seander/bithacks.html#VariableSignExtend */
|
||||
static int bcdec__extend_sign(int val, int bits) {
|
||||
return (val << (32 - bits)) >> (32 - bits);
|
||||
@@ -1431,6 +1269,8 @@ BCDECDEF void bcdec_bc7(const void* compressedBlock, void* decompressedBlock, in
|
||||
|
||||
#endif /* BCDEC_IMPLEMENTATION */
|
||||
|
||||
#endif /* BCDEC_HEADER_INCLUDED */
|
||||
|
||||
/* LICENSE:
|
||||
|
||||
This software is available under 2 licenses -- choose whichever you prefer.
|
||||
|
||||
+20
-59
@@ -2,9 +2,6 @@
|
||||
#include "ddsutils/ddsutils.h"
|
||||
#include "cfile/cfile.h"
|
||||
#include "osapi/osregistry.h"
|
||||
#ifdef USE_OPENGL_ES
|
||||
#include "graphics/opengl/es_compatibility.h"
|
||||
#endif
|
||||
|
||||
#ifdef WITH_OPENGL
|
||||
#include <glad/glad.h>
|
||||
@@ -99,11 +96,6 @@ static uint conversion_resize(DDS_HEADER &dds_header)
|
||||
// drop levels until we get to an appropriate size, but make sure we have
|
||||
// at least 1 mipmap level remaining at the end (in case there's not a full chain)
|
||||
while (((width > MAX_SIZE) || (height > MAX_SIZE)) && (offset < dds_header.dwMipMapCount-1)) {
|
||||
// this shouldn't happen, but catch the obscure case (like 8192x4)
|
||||
if ((width <= 4) || (height <= 4)) {
|
||||
break;
|
||||
}
|
||||
|
||||
width >>= 1;
|
||||
height >>= 1;
|
||||
depth >>= 1;
|
||||
@@ -202,10 +194,9 @@ static int _dds_read_header(CFILE *ddsfile, DDS_HEADER &dds_header, DDS_HEADER_D
|
||||
return DDS_ERROR_NONE;
|
||||
}
|
||||
|
||||
static size_t compute_dds_size(const DDS_HEADER &dds_header, bool converting = false)
|
||||
static size_t compute_dds_size(const DDS_HEADER &dds_header)
|
||||
{
|
||||
const uint block_sz = 4;
|
||||
uint d_width = 0, d_height = 0, d_depth = 0;
|
||||
uint d_width, d_height, d_depth;
|
||||
size_t d_size = 0;
|
||||
|
||||
for (uint i = 0; i < dds_header.dwMipMapCount; i++) {
|
||||
@@ -213,17 +204,6 @@ static size_t compute_dds_size(const DDS_HEADER &dds_header, bool converting = f
|
||||
d_height = std::max(1U, dds_header.dwHeight >> i);
|
||||
d_depth = std::max(1U, dds_header.dwDepth >> i);
|
||||
|
||||
// When converting we need to pad a bit to compensate for the decompression
|
||||
// size on smaller mipmap levels. We need to ensure there is always enough
|
||||
// room to decode an entire 4x4 block in rgba space
|
||||
if (converting) {
|
||||
auto sz = std::min(d_width, d_height);
|
||||
|
||||
if (sz < block_sz) {
|
||||
d_size += ((block_sz * block_sz) - (sz * sz)) * d_depth * 4;
|
||||
}
|
||||
}
|
||||
|
||||
if (dds_header.ddspf.dwFlags & DDPF_FOURCC) {
|
||||
// size of data block (4x4)
|
||||
d_size += ((d_width + 3) / 4) * ((d_height + 3) / 4) * d_depth * ((dds_header.ddspf.dwFourCC == FOURCC_DXT1) ? 8 : 16);
|
||||
@@ -267,7 +247,6 @@ int dds_read_header(const char *filename, CFILE *img_cfp, int *width, int *heigh
|
||||
int retval = DDS_ERROR_NONE;
|
||||
int ct = DDS_UNCOMPRESSED;
|
||||
int is_cubemap = 0;
|
||||
bool convert = false;
|
||||
|
||||
|
||||
if (img_cfp == NULL) {
|
||||
@@ -358,9 +337,7 @@ int dds_read_header(const char *filename, CFILE *img_cfp, int *width, int *heigh
|
||||
}
|
||||
|
||||
// maybe do conversion if format not supported
|
||||
convert = conversion_needed(dds_header);
|
||||
|
||||
if (convert) {
|
||||
if (conversion_needed(dds_header)) {
|
||||
// switch to uncompressed format and reset vars
|
||||
dds_header.ddspf.dwFlags &= ~DDPF_FOURCC;
|
||||
dds_header.ddspf.dwFlags |= DDPF_RGB;
|
||||
@@ -382,7 +359,7 @@ int dds_read_header(const char *filename, CFILE *img_cfp, int *width, int *heigh
|
||||
|
||||
// stuff important info
|
||||
if (size)
|
||||
*size = compute_dds_size(dds_header, convert);
|
||||
*size = compute_dds_size(dds_header);
|
||||
|
||||
if (bpp)
|
||||
*bpp = get_bit_count(dds_header);
|
||||
@@ -409,9 +386,6 @@ Done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void (*decompress_dds)(const void *in, void *out, int pitch) = nullptr;
|
||||
static uint32_t BLOCK_SIZE = 0;
|
||||
|
||||
//reads pixel info from a dds file
|
||||
int dds_read_bitmap(const char *filename, ubyte *data, ubyte *bpp, int cf_type)
|
||||
{
|
||||
@@ -449,7 +423,7 @@ int dds_read_bitmap(const char *filename, ubyte *data, ubyte *bpp, int cf_type)
|
||||
|
||||
cfseek(cfp, (dds_header.ddspf.dwFourCC == FOURCC_DX10) ? DX10_OFFSET : DDS_OFFSET, CF_SEEK_SET);
|
||||
|
||||
size = compute_dds_size(dds_header); // don't add padding on this one!!
|
||||
size = compute_dds_size(dds_header);
|
||||
|
||||
// read in the data
|
||||
if ( !conversion_needed(dds_header) ) {
|
||||
@@ -473,28 +447,6 @@ int dds_read_bitmap(const char *filename, ubyte *data, ubyte *bpp, int cf_type)
|
||||
const int num_faces = (dds_header.dwCaps2 & DDSCAPS2_CUBEMAP) ? 6 : 1;
|
||||
const bool has_depth = (dds_header.dwFlags & DDSD_DEPTH) == DDSD_DEPTH;
|
||||
|
||||
switch (dds_header.ddspf.dwFourCC) {
|
||||
case FOURCC_DX10:
|
||||
decompress_dds = bcdec_bc7;
|
||||
BLOCK_SIZE = BCDEC_BC7_BLOCK_SIZE;
|
||||
break;
|
||||
case FOURCC_DXT5:
|
||||
decompress_dds = bcdec_bc3;
|
||||
BLOCK_SIZE = BCDEC_BC3_BLOCK_SIZE;
|
||||
break;
|
||||
case FOURCC_DXT1:
|
||||
decompress_dds = bcdec_bc1;
|
||||
BLOCK_SIZE = BCDEC_BC1_BLOCK_SIZE;
|
||||
break;
|
||||
case FOURCC_DXT3:
|
||||
decompress_dds = bcdec_bc2;
|
||||
BLOCK_SIZE = BCDEC_BC2_BLOCK_SIZE;
|
||||
break;
|
||||
default:
|
||||
Error(LOCATION, "Invalid FourCC (%d) for DDS decompression!", dds_header.ddspf.dwFourCC);
|
||||
break;
|
||||
}
|
||||
|
||||
for (int f = 0; f < num_faces; ++f) {
|
||||
// if we resized then skip over all of that data (altering values to match pre-resize)
|
||||
for (uint x = 0; x < mipmap_offset; ++x) {
|
||||
@@ -502,7 +454,7 @@ int dds_read_bitmap(const char *filename, ubyte *data, ubyte *bpp, int cf_type)
|
||||
d_height = std::max(1U, dds_header.dwHeight << (mipmap_offset - x));
|
||||
d_depth = has_depth ? std::max(1U, dds_header.dwDepth << (mipmap_offset - x)) : 1U;
|
||||
|
||||
src += ((d_width + 3) / 4) * ((d_height + 3) / 4) * d_depth * BLOCK_SIZE;
|
||||
src += (d_width * d_height * d_depth);
|
||||
}
|
||||
|
||||
for (uint m = mipmap_offset; m < dds_header.dwMipMapCount; ++m) {
|
||||
@@ -512,14 +464,23 @@ int dds_read_bitmap(const char *filename, ubyte *data, ubyte *bpp, int cf_type)
|
||||
d_depth = std::max(1U, dds_header.dwDepth >> (m - mipmap_offset));
|
||||
|
||||
for (uint d = 0; d < d_depth; ++d) {
|
||||
auto depth_offset = d * d_width * d_height * 4;
|
||||
|
||||
for (uint i = 0; i < d_height; i += 4) {
|
||||
for (uint j = 0; j < d_width; j += 4) {
|
||||
dst = data + data_offset + depth_offset + ((i * d_width + j) * 4);
|
||||
dst = data + data_offset + ((i * d_width + j) * 4);
|
||||
|
||||
decompress_dds(src, dst, d_width * 4);
|
||||
src += BLOCK_SIZE;
|
||||
if (dds_header.ddspf.dwFourCC == FOURCC_DX10) {
|
||||
bcdec_bc7(src, dst, d_width * 4);
|
||||
src += BCDEC_BC7_BLOCK_SIZE;
|
||||
} else if (dds_header.ddspf.dwFourCC == FOURCC_DXT5) {
|
||||
bcdec_bc3(src, dst, d_width * 4);
|
||||
src += BCDEC_BC3_BLOCK_SIZE;
|
||||
} else if (dds_header.ddspf.dwFourCC == FOURCC_DXT1) {
|
||||
bcdec_bc1(src, dst, d_width * 4);
|
||||
src += BCDEC_BC1_BLOCK_SIZE;
|
||||
} else if (dds_header.ddspf.dwFourCC == FOURCC_DXT3) {
|
||||
bcdec_bc2(src, dst, d_width * 4);
|
||||
src += BCDEC_BC2_BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+78
-172
@@ -37,6 +37,7 @@
|
||||
#include "utils/Random.h"
|
||||
#include "weapon/weapon.h"
|
||||
|
||||
constexpr int MIN_RADIUS_FOR_PERSISTENT_DEBRIS = 50; // ship radius at which debris from it becomes persistant
|
||||
constexpr int DEBRIS_SOUND_DELAY = 2000; // time to start debris sound after created
|
||||
|
||||
int Num_hull_pieces; // number of hull pieces in existence
|
||||
@@ -56,57 +57,32 @@ int Debris_num_submodels = 0;
|
||||
|
||||
particle::ParticleEffectHandle Debris_hit_particle;
|
||||
|
||||
#define DEBRIS_INDEX(dp) (static_cast<int>((dp)-Debris.data()))
|
||||
#define DEBRIS_INDEX(dp) (int)(dp-Debris.data())
|
||||
|
||||
// Find the first available arc slot. If none is available, and no_create is false, add one.
|
||||
debris_electrical_arc *debris_find_or_create_electrical_arc_slot(debris *db, bool no_create);
|
||||
|
||||
/**
|
||||
* Start the sequence of a piece of debris writhing in unholy agony!!!
|
||||
*/
|
||||
static void debris_start_death_roll(object *debris_obj, debris *debris_p, vec3d *hitpos = nullptr)
|
||||
{
|
||||
auto sip = &Ship_info[debris_p->ship_info_index];
|
||||
if (debris_p->is_hull) {
|
||||
// tell everyone else to blow up the piece of debris
|
||||
if( MULTIPLAYER_MASTER )
|
||||
send_debris_update_packet(debris_obj,DEBRIS_UPDATE_NUKE);
|
||||
|
||||
if (sip->debris_end_particles.isValid()) {
|
||||
auto source = particle::ParticleManager::get()->createSource(sip->debris_end_particles);
|
||||
|
||||
// Use the position since the object is going to be invalid soon
|
||||
auto host = std::make_unique<EffectHostVector>(debris_obj->pos, debris_obj->orient, debris_obj->phys_info.vel);
|
||||
host->setRadius(debris_obj->radius);
|
||||
source->setHost(std::move(host));
|
||||
source->setNormal(debris_obj->orient.vec.uvec);
|
||||
source->finishCreation();
|
||||
} else {
|
||||
int fireball_type = fireball_ship_explosion_type(sip);
|
||||
if(fireball_type < 0) {
|
||||
fireball_type = FIREBALL_EXPLOSION_LARGE1 + Random::next(FIREBALL_NUM_LARGE_EXPLOSIONS);
|
||||
}
|
||||
fireball_create( &debris_obj->pos, fireball_type, FIREBALL_LARGE_EXPLOSION, OBJ_INDEX(debris_obj), debris_obj->radius*1.75f);
|
||||
int fireball_type = fireball_ship_explosion_type(&Ship_info[debris_p->ship_info_index]);
|
||||
if(fireball_type < 0) {
|
||||
fireball_type = FIREBALL_EXPLOSION_LARGE1 + Random::next(FIREBALL_NUM_LARGE_EXPLOSIONS);
|
||||
}
|
||||
fireball_create( &debris_obj->pos, fireball_type, FIREBALL_LARGE_EXPLOSION, OBJ_INDEX(debris_obj), debris_obj->radius*1.75f);
|
||||
|
||||
// only play debris destroy sound if hull piece and it has been around for at least 2 seconds
|
||||
if ( Missiontime > debris_p->time_started + 2*F1_0 ) {
|
||||
auto snd_id = sip->debris_explosion_sound;
|
||||
auto snd_id = Ship_info[debris_p->ship_info_index].debris_explosion_sound;
|
||||
if (snd_id.isValid()) {
|
||||
snd_play_3d( gamesnd_get_game_sound(snd_id), &debris_obj->pos, &View_position, debris_obj->radius );
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (sip->shrapnel_end_particles.isValid()) {
|
||||
auto source = particle::ParticleManager::get()->createSource(sip->shrapnel_end_particles);
|
||||
|
||||
// Use the position since the object is going to be invalid soon
|
||||
auto host = std::make_unique<EffectHostVector>(debris_obj->pos, debris_obj->orient, debris_obj->phys_info.vel);
|
||||
host->setRadius(debris_obj->radius);
|
||||
source->setHost(std::move(host));
|
||||
source->setNormal(debris_obj->orient.vec.uvec);
|
||||
source->finishCreation();
|
||||
}
|
||||
}
|
||||
|
||||
if (scripting::hooks::OnDebrisDeath->isActive()) {
|
||||
@@ -143,13 +119,10 @@ void debris_init()
|
||||
Debris_hit_particle = particle::ParticleManager::get()->addEffect(particle::ParticleEffect(
|
||||
"", //Name
|
||||
::util::UniformFloatRange(10.f), //Particle num
|
||||
particle::ParticleEffect::Duration::ONETIME, //Single Particle Emission
|
||||
::util::UniformFloatRange(), //No duration
|
||||
::util::UniformFloatRange (-1.f), //Single particle only
|
||||
particle::ParticleEffect::ShapeDirection::ALIGNED, //Particle direction
|
||||
::util::UniformFloatRange(1.f), //Velocity Inherit
|
||||
false, //Velocity Inherit absolute?
|
||||
std::make_unique<particle::LegacyAACuboidVolume>(0.3f, 1.f, true), //Velocity volume
|
||||
make_unique<particle::LegacyAACuboidVolume>(0.3f, 1.f, true), //Velocity volume
|
||||
::util::UniformFloatRange(0.f, 10.f), //Velocity volume multiplier
|
||||
particle::ParticleEffect::VelocityScaling::NONE, //Velocity directional scaling
|
||||
std::nullopt, //Orientation-based velocity
|
||||
@@ -160,12 +133,6 @@ void debris_init()
|
||||
true, //Affected by detail
|
||||
1.f, //Culling range multiplier
|
||||
true, //Disregard Animation Length. Must be true for everything using particle::Anim_bitmap_X
|
||||
false, //Don't reverse animation
|
||||
false, //parent local
|
||||
false, //ignore velocity inherit if parented
|
||||
false, //position velocity inherit absolute?
|
||||
std::nullopt, //Local velocity offset
|
||||
std::nullopt, //Local offset
|
||||
::util::UniformFloatRange(0.25f, 0.75f), //Lifetime
|
||||
::util::UniformFloatRange(0.2f, 0.4f), //Radius
|
||||
particle::Anim_bitmap_id_fire)); //Bitmap
|
||||
@@ -248,7 +215,6 @@ void debris_delete( object * obj )
|
||||
|
||||
if (db->model_instance_num >= 0) {
|
||||
model_delete_instance(db->model_instance_num);
|
||||
db->model_instance_num = -1;
|
||||
}
|
||||
|
||||
if ( db->is_hull ) {
|
||||
@@ -300,48 +266,56 @@ void debris_process_post(object * obj, float frame_time)
|
||||
return; // If arc_frequency <= 0, this piece has no arcs on it
|
||||
}
|
||||
|
||||
if ( !timestamp_elapsed(db->arc_timeout) && timestamp_elapsed(db->arc_next_time)) {
|
||||
if ( !timestamp_elapsed(db->fire_timeout) && timestamp_elapsed(db->next_fireball)) {
|
||||
|
||||
db->arc_next_time = _timestamp_rand(db->arc_frequency,db->arc_frequency*2 );
|
||||
db->next_fireball = _timestamp_rand(db->arc_frequency,db->arc_frequency*2 );
|
||||
db->arc_frequency += 100;
|
||||
|
||||
if (db->is_hull) {
|
||||
|
||||
int n_arcs = Random::next(1, 3); // Create 1-3 sparks
|
||||
int n, n_arcs = Random::next(1, 3); // Create 1-3 sparks
|
||||
|
||||
vec3d v1 = submodel_get_random_point(db->model_num, db->submodel_num);
|
||||
vec3d v2 = submodel_get_random_point(db->model_num, db->submodel_num);
|
||||
vec3d v3 = submodel_get_random_point(db->model_num, db->submodel_num);
|
||||
vec3d v4 = submodel_get_random_point(db->model_num, db->submodel_num);
|
||||
|
||||
n = 0;
|
||||
|
||||
int lifetime = Random::next(100, 1000);
|
||||
|
||||
// Create the spark effects
|
||||
for (int n = 0; n < n_arcs; n++) {
|
||||
auto arc = debris_find_or_create_electrical_arc_slot(db, db->electrical_arcs.size() >= MAX_DEBRIS_ARCS);
|
||||
if (arc) {
|
||||
arc->timestamp = _timestamp(lifetime); // live up to a second
|
||||
for (int i=0; i<MAX_DEBRIS_ARCS; ++i) {
|
||||
if ( !db->arc_timestamp[i].isValid() ) {
|
||||
|
||||
db->arc_timestamp[i] = _timestamp(lifetime); // live up to a second
|
||||
|
||||
switch( n ) {
|
||||
case 0:
|
||||
arc->endpoint_1 = v1;
|
||||
arc->endpoint_2 = v2;
|
||||
db->arc_pts[i][0] = v1;
|
||||
db->arc_pts[i][1] = v2;
|
||||
break;
|
||||
case 1:
|
||||
arc->endpoint_1 = v2;
|
||||
arc->endpoint_2 = v3;
|
||||
db->arc_pts[i][0] = v2;
|
||||
db->arc_pts[i][1] = v3;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
arc->endpoint_1 = v2;
|
||||
arc->endpoint_2 = v4;
|
||||
db->arc_pts[i][0] = v2;
|
||||
db->arc_pts[i][1] = v4;
|
||||
break;
|
||||
|
||||
default:
|
||||
UNREACHABLE("Unhandled case %d for electrical arc creation in debris_process_post()!", n);
|
||||
Int3();
|
||||
}
|
||||
|
||||
n++;
|
||||
if ( n == n_arcs )
|
||||
break; // Don't need to create anymore
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// rotate v2 out of local coordinates into world.
|
||||
// Use v2 since it is used in every bolt. See above switch().
|
||||
vec3d snd_pos;
|
||||
@@ -368,20 +342,16 @@ void debris_process_post(object * obj, float frame_time)
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &arc: db->electrical_arcs) {
|
||||
if (arc.timestamp.isValid()) {
|
||||
if (timestamp_elapsed(arc.timestamp)) {
|
||||
for (int i=0; i<MAX_DEBRIS_ARCS; ++i) {
|
||||
if ( db->arc_timestamp[i].isValid() ) {
|
||||
if ( timestamp_elapsed( db->arc_timestamp[i] ) ) {
|
||||
// Kill off the spark
|
||||
arc.timestamp = TIMESTAMP::invalid();
|
||||
db->arc_timestamp[i] = TIMESTAMP::invalid();
|
||||
} else {
|
||||
// Maybe move a vertex.... 20% of the time maybe?
|
||||
int mr = Random::next();
|
||||
if ( mr < Random::MAX_VALUE/5 ) {
|
||||
auto pt = submodel_get_random_point(db->model_num, db->submodel_num);
|
||||
if (mr % 2 == 0)
|
||||
arc.endpoint_1 = pt;
|
||||
else
|
||||
arc.endpoint_2 = pt;
|
||||
db->arc_pts[i][mr % 2] = submodel_get_random_point(db->model_num, db->submodel_num);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -450,32 +420,6 @@ object *debris_create(object *source_obj, int model_num, int submodel_num, const
|
||||
{
|
||||
debris_create_set_velocity(&Debris[obj->instance], shipp, exp_center, exp_force, source_subsys);
|
||||
debris_create_fire_hook(obj, source_obj);
|
||||
const auto& sip = Ship_info[Ships[source_obj->instance].ship_info_index];
|
||||
particle::ParticleEffectHandle flame_effect;
|
||||
if (source_subsys != nullptr) {
|
||||
if (hull_flag) {
|
||||
if (source_subsys->system_info->debris_flame_particles.isValid()) {
|
||||
flame_effect = source_subsys->system_info->debris_flame_particles;
|
||||
} else {
|
||||
flame_effect = sip.default_subsys_debris_flame_particles;
|
||||
}
|
||||
} else {
|
||||
if (source_subsys->system_info->shrapnel_flame_particles.isValid()) {
|
||||
flame_effect = source_subsys->system_info->shrapnel_flame_particles;
|
||||
} else {
|
||||
flame_effect = sip.default_subsys_shrapnel_flame_particles;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
flame_effect = hull_flag ? sip.debris_flame_particles : sip.shrapnel_flame_particles;
|
||||
}
|
||||
if (flame_effect.isValid()) {
|
||||
auto source = particle::ParticleManager::get()->createSource(flame_effect);
|
||||
source->setHost(std::make_unique<EffectHostObject>(obj, vmd_zero_vector));
|
||||
source->setTriggerRadius(source_obj->radius);
|
||||
source->setTriggerVelocity(vm_vec_mag_quick(&source_obj->phys_info.vel));
|
||||
source->finishCreation();
|
||||
}
|
||||
}
|
||||
|
||||
return obj;
|
||||
@@ -608,10 +552,22 @@ object *debris_create_only(int parent_objnum, int parent_ship_class, int alt_typ
|
||||
}
|
||||
|
||||
// Create Debris piece n!
|
||||
if ( hull_flag ) {
|
||||
if (Random::next() < (Random::MAX_VALUE/6)) // Make some pieces blow up shortly after explosion.
|
||||
db->lifeleft = 2.0f * (frand()) + 0.5f;
|
||||
else {
|
||||
db->flags.set(Debris_Flags::DoNotExpire);
|
||||
db->lifeleft = -1.0f; // large hull pieces stay around forever
|
||||
}
|
||||
} else {
|
||||
// small non-hull pieces should stick around longer the larger they are
|
||||
// sqrtf should make sure its never too crazy long
|
||||
db->lifeleft = (frand() * 2.0f + 0.1f) * sqrtf(radius);
|
||||
}
|
||||
|
||||
//WMC - Oh noes, we may need to change lifeleft
|
||||
if(hull_flag)
|
||||
{
|
||||
// set lifeleft based on tabled entries if they are not negative
|
||||
// coded originally by WMC then clean-up added by wookieejedi
|
||||
if(sip->debris_min_lifetime >= 0.0f && sip->debris_max_lifetime >= 0.0f)
|
||||
{
|
||||
db->lifeleft = (( sip->debris_max_lifetime - sip->debris_min_lifetime ) * frand()) + sip->debris_min_lifetime;
|
||||
@@ -626,22 +582,6 @@ object *debris_create_only(int parent_objnum, int parent_ship_class, int alt_typ
|
||||
if(db->lifeleft > sip->debris_max_lifetime)
|
||||
db->lifeleft = sip->debris_max_lifetime;
|
||||
}
|
||||
// By default, make some pieces blow up shortly after explosion.
|
||||
else if (Random::next() < (Random::MAX_VALUE / 6))
|
||||
{
|
||||
db->lifeleft = 2.0f * (frand()) + 0.5f;
|
||||
}
|
||||
else
|
||||
{
|
||||
db->flags.set(Debris_Flags::DoNotExpire);
|
||||
db->lifeleft = -1.0f; // large hull pieces stay around forever
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// small non-hull pieces should stick around longer the larger they are
|
||||
// sqrtf should make sure its never too crazy long
|
||||
db->lifeleft = (frand() * 2.0f + 0.1f) * sqrtf(radius);
|
||||
}
|
||||
|
||||
// increase lifetime for vaporized debris
|
||||
@@ -655,13 +595,15 @@ object *debris_create_only(int parent_objnum, int parent_ship_class, int alt_typ
|
||||
db->ship_info_index = parent_ship_class;
|
||||
db->team = team;
|
||||
db->ambient_sound = (sip == nullptr) ? gamesnd_id(-1) : sip->debris_ambient_sound;
|
||||
db->arc_timeout = TIMESTAMP::never(); // if not changed, timestamp_elapsed() will return false
|
||||
db->fire_timeout = TIMESTAMP::never(); // if not changed, timestamp_elapsed() will return false
|
||||
db->time_started = Missiontime;
|
||||
db->species = (sip == nullptr) ? -1 : sip->species;
|
||||
db->parent_alt_name = alt_type_index;
|
||||
db->damage_mult = 1.0f;
|
||||
|
||||
db->electrical_arcs.clear();
|
||||
for (int i=0; i<MAX_DEBRIS_ARCS; ++i) { // NOLINT
|
||||
db->arc_timestamp[i] = TIMESTAMP::invalid();
|
||||
}
|
||||
|
||||
if ( db->is_hull ) {
|
||||
// Percent of debris pieces with arcs controlled via table (default 50%)
|
||||
@@ -674,7 +616,7 @@ object *debris_create_only(int parent_objnum, int parent_ship_class, int alt_typ
|
||||
db->arc_frequency = 0;
|
||||
}
|
||||
|
||||
db->arc_next_time = _timestamp_rand(500,2000); //start one 1/2 - 2 secs later
|
||||
db->next_fireball = _timestamp_rand(500,2000); //start one 1/2 - 2 secs later
|
||||
|
||||
flagset<Object::Object_Flags> default_flags;
|
||||
default_flags.set(Object::Object_Flags::Renders);
|
||||
@@ -708,25 +650,19 @@ object *debris_create_only(int parent_objnum, int parent_ship_class, int alt_typ
|
||||
obj->hull_strength = hull_strength;
|
||||
|
||||
if (hull_flag) {
|
||||
float min_hp = sip->debris_min_hitpoints;
|
||||
float max_hp = sip->debris_max_hitpoints;
|
||||
if (sip->debris_hitpoints_radius_multi >= 0.0f) {
|
||||
min_hp *= sip->debris_hitpoints_radius_multi * radius;
|
||||
max_hp *= sip->debris_hitpoints_radius_multi * radius;
|
||||
}
|
||||
if (min_hp >= 0.0f && max_hp >= 0.0f)
|
||||
if(sip->debris_min_hitpoints >= 0.0f && sip->debris_max_hitpoints >= 0.0f)
|
||||
{
|
||||
obj->hull_strength = ((max_hp - min_hp) * frand()) + min_hp;
|
||||
obj->hull_strength = (( sip->debris_max_hitpoints - sip->debris_min_hitpoints ) * frand()) + sip->debris_min_hitpoints;
|
||||
}
|
||||
else if(min_hp >= 0.0f)
|
||||
else if(sip->debris_min_hitpoints >= 0.0f)
|
||||
{
|
||||
if (obj->hull_strength < min_hp)
|
||||
obj->hull_strength = min_hp;
|
||||
if(obj->hull_strength < sip->debris_min_hitpoints)
|
||||
obj->hull_strength = sip->debris_min_hitpoints;
|
||||
}
|
||||
else if(max_hp >= 0.0f)
|
||||
else if(sip->debris_max_hitpoints >= 0.0f)
|
||||
{
|
||||
if (obj->hull_strength > max_hp)
|
||||
obj->hull_strength = max_hp;
|
||||
if(obj->hull_strength > sip->debris_max_hitpoints)
|
||||
obj->hull_strength = sip->debris_max_hitpoints;
|
||||
}
|
||||
db->damage_mult = sip->debris_damage_mult;
|
||||
|
||||
@@ -735,23 +671,21 @@ object *debris_create_only(int parent_objnum, int parent_ship_class, int alt_typ
|
||||
// limit the amount of time that fireballs appear
|
||||
// let fireball length be linked to radius of ship. Range is .33 radius => 3.33 radius seconds.
|
||||
if (spark_timeout >= 0) {
|
||||
db->arc_timeout = _timestamp(spark_timeout);
|
||||
db->fire_timeout = _timestamp(spark_timeout);
|
||||
} else if (parent_objnum >= 0) {
|
||||
float t = 1000*Objects[parent_objnum].radius/3 + (fl2i(1000*3*Objects[parent_objnum].radius) == 0 ? 0 : Random::next(fl2i(1000*3*Objects[parent_objnum].radius)));
|
||||
db->arc_timeout = _timestamp(fl2i(t)); // fireballs last from 5 - 30 seconds
|
||||
db->fire_timeout = _timestamp(fl2i(t)); // fireballs last from 5 - 30 seconds
|
||||
} else {
|
||||
db->arc_timeout = TIMESTAMP::immediate();
|
||||
db->fire_timeout = TIMESTAMP::immediate();
|
||||
}
|
||||
|
||||
if (parent_objnum >= 0 && Objects[parent_objnum].radius >= Min_radius_for_persistent_debris) {
|
||||
if (parent_objnum >= 0 && Objects[parent_objnum].radius >= MIN_RADIUS_FOR_PERSISTENT_DEBRIS) {
|
||||
db->flags.set(Debris_Flags::DoNotExpire);
|
||||
} else {
|
||||
debris_add_to_hull_list(db);
|
||||
}
|
||||
}
|
||||
|
||||
db->max_hull = obj->hull_strength;
|
||||
|
||||
if (hull_flag) {
|
||||
MONITOR_INC(NumHullDebris,1);
|
||||
} else {
|
||||
@@ -1031,9 +965,9 @@ int debris_check_collision(object *pdebris, object *other_obj, vec3d *hitpos, co
|
||||
model_get_moving_submodel_list(submodel_vector, heavy_obj);
|
||||
|
||||
// turn off all moving submodels, collide against only 1 at a time.
|
||||
mc.collision_checked.assign(pm->n_models, 0);
|
||||
// turn off collision detection for all moving submodels
|
||||
for (auto submodel : submodel_vector) {
|
||||
mc.collision_checked[submodel] = true;
|
||||
pmi->submodel[submodel].collision_checked = true;
|
||||
}
|
||||
|
||||
// Only check single submodel now, since children of moving submodels are handled as moving as well
|
||||
@@ -1045,8 +979,10 @@ int debris_check_collision(object *pdebris, object *other_obj, vec3d *hitpos, co
|
||||
|
||||
// check each submodel in turn
|
||||
for (auto submodel: submodel_vector) {
|
||||
auto smi = &pmi->submodel[submodel];
|
||||
|
||||
// turn on just one submodel for collision test
|
||||
mc.collision_checked[submodel] = false;
|
||||
smi->collision_checked = false;
|
||||
|
||||
// find the start and end positions of the sphere in submodel RF
|
||||
model_instance_global_to_local_point(&p0, &light_obj->last_pos, pm, pmi, submodel, &heavy_obj->last_orient, &heavy_obj->last_pos, true);
|
||||
@@ -1080,11 +1016,8 @@ int debris_check_collision(object *pdebris, object *other_obj, vec3d *hitpos, co
|
||||
}
|
||||
|
||||
// Don't look at this submodel again
|
||||
mc.collision_checked[submodel] = true;
|
||||
smi->collision_checked = true;
|
||||
}
|
||||
|
||||
// Clear collision_checked before base model pass so it auto-inits fresh
|
||||
mc.collision_checked.clear();
|
||||
}
|
||||
|
||||
// Now complete base model collision checks that do not take into account rotating submodels.
|
||||
@@ -1229,7 +1162,7 @@ void calc_debris_physics_properties( physics_info *pi, vec3d *mins, vec3d *maxs,
|
||||
*/
|
||||
void debris_render(object * obj, model_draw_list *scene)
|
||||
{
|
||||
int num, swapped;
|
||||
int i, num, swapped;
|
||||
debris *db;
|
||||
|
||||
swapped = -1;
|
||||
@@ -1264,9 +1197,9 @@ void debris_render(object * obj, model_draw_list *scene)
|
||||
|
||||
// Only render electrical arcs if within 500m of the eye (for a 10m piece)
|
||||
if ( vm_vec_dist_quick( &obj->pos, &Eye_position ) < obj->radius*50.0f ) {
|
||||
for (auto &arc: db->electrical_arcs) {
|
||||
if ( arc.timestamp.isValid() ) {
|
||||
model_instance_add_arc( pm, pmi, db->submodel_num, &arc.endpoint_1, &arc.endpoint_2, nullptr, MARC_TYPE_DAMAGED );
|
||||
for (i=0; i<MAX_DEBRIS_ARCS; i++ ) {
|
||||
if ( db->arc_timestamp[i].isValid() ) {
|
||||
model_instance_add_arc( pm, pmi, db->submodel_num, &db->arc_pts[i][0], &db->arc_pts[i][1], MARC_TYPE_DAMAGED );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1307,40 +1240,13 @@ void create_generic_debris(object* ship_objp, const vec3d* pos, float min_num_de
|
||||
if (ship_objp->type != OBJ_SHIP)
|
||||
return;
|
||||
|
||||
// determine if using custom or non-custom generic debris
|
||||
int model_num = use_ship_debris ? Ship_info[Ships[ship_objp->instance].ship_info_index].generic_debris_model_num : -1;
|
||||
|
||||
// if using non-custom generic debris, then bail early if that kind of debris is not allowed --wookeejedi
|
||||
if ( (model_num < 0) && (Disable_all_noncustom_generic_debris) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
float num_debris = frand_range(min_num_debris, max_num_debris);
|
||||
|
||||
num_debris *= (Detail.num_small_debris + 0.5f) / 4.5f;
|
||||
|
||||
vec3d create_pos = *pos;
|
||||
for (int i = 0; i < num_debris; i++) {
|
||||
debris_create(ship_objp, model_num, -1, &create_pos, pos, false, speed_mult);
|
||||
int model_num = use_ship_debris ? Ship_info[Ships[ship_objp->instance].ship_info_index].generic_debris_model_num : -1;
|
||||
debris_create(ship_objp, model_num, -1, &create_pos, pos, 0, speed_mult);
|
||||
}
|
||||
}
|
||||
|
||||
debris_electrical_arc *debris_find_or_create_electrical_arc_slot(debris *db, bool no_create)
|
||||
{
|
||||
size_t i = 0;
|
||||
for (auto& ii : db->electrical_arcs)
|
||||
{
|
||||
if (!ii.timestamp.isValid())
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i == db->electrical_arcs.size())
|
||||
{
|
||||
if (no_create)
|
||||
return nullptr;
|
||||
db->electrical_arcs.emplace_back();
|
||||
}
|
||||
|
||||
return &db->electrical_arcs[i];
|
||||
}
|
||||
+5
-11
@@ -20,7 +20,7 @@ class object;
|
||||
struct CFILE;
|
||||
class model_draw_list;
|
||||
|
||||
#define MAX_DEBRIS_ARCS 8
|
||||
#define MAX_DEBRIS_ARCS 8 // Must be less than MAX_ARC_EFFECTS in model.h
|
||||
|
||||
FLAG_LIST(Debris_Flags) {
|
||||
Used,
|
||||
@@ -30,12 +30,6 @@ FLAG_LIST(Debris_Flags) {
|
||||
NUM_VALUES
|
||||
};
|
||||
|
||||
struct debris_electrical_arc
|
||||
{
|
||||
vec3d endpoint_1;
|
||||
vec3d endpoint_2;
|
||||
TIMESTAMP timestamp; // When this times out, the spark goes away. Invalid is not used
|
||||
};
|
||||
|
||||
typedef struct debris {
|
||||
flagset<Debris_Flags> flags; // See DEBRIS_??? defines
|
||||
@@ -49,15 +43,15 @@ typedef struct debris {
|
||||
int model_num; // What model this uses
|
||||
int model_instance_num; // What model instance this uses - needed for arcs
|
||||
int submodel_num; // What submodel this uses
|
||||
TIMESTAMP arc_next_time; // When the next damage/emp arc will be created.
|
||||
TIMESTAMP next_fireball; // When to start a fireball
|
||||
bool is_hull; // indicates whether this is a collideable, destructable piece of debris from the model, or just a generic debris fragment
|
||||
float max_hull;
|
||||
int species; // What species this is from. -1 if don't care.
|
||||
TIMESTAMP arc_timeout; // timestamp that holds time for arcs to stop appearing
|
||||
TIMESTAMP fire_timeout; // timestamp that holds time for fireballs to stop appearing
|
||||
TIMESTAMP sound_delay; // timestamp to signal when sound should start
|
||||
fix time_started; // time when debris was created
|
||||
|
||||
SCP_vector<debris_electrical_arc> electrical_arcs;
|
||||
vec3d arc_pts[MAX_DEBRIS_ARCS][2]; // The endpoints of each arc
|
||||
TIMESTAMP arc_timestamp[MAX_DEBRIS_ARCS]; // When this times out, the spark goes away. Invalid is not used
|
||||
int arc_frequency; // Starts at 1000, gets bigger
|
||||
|
||||
int parent_alt_name;
|
||||
|
||||
@@ -467,7 +467,7 @@ void dc_putc(char c)
|
||||
*/
|
||||
temp_str = line_str->substr(lastwhite);
|
||||
line_str->resize(lastwhite);
|
||||
dc_buffer.push_back(std::move(temp_str));
|
||||
dc_buffer.push_back(temp_str);
|
||||
line_str = &dc_buffer.back();
|
||||
|
||||
if ((dc_buffer.size() > DROWS) && (dc_scroll_y < SCROLL_Y_MAX)) {
|
||||
|
||||
@@ -1083,7 +1083,7 @@ void dc_stuff_int(int *i)
|
||||
value_l = dc_parse_long(token.c_str(), DCT_INT);
|
||||
|
||||
if ((value_l < INT_MAX) && (value_l > INT_MIN)) {
|
||||
*i = static_cast<int>(value_l);
|
||||
*i = value_l;
|
||||
|
||||
} else {
|
||||
throw errParse(token.c_str(), DCT_INT);
|
||||
@@ -1101,7 +1101,7 @@ void dc_stuff_uint(uint *i)
|
||||
value_l = dc_parse_long(Cp, DCT_INT);
|
||||
|
||||
if (value_l < UINT_MAX) {
|
||||
*i = static_cast<uint>(value_l);
|
||||
*i = value_l;
|
||||
|
||||
} else {
|
||||
throw errParse(token.c_str(), DCT_INT);
|
||||
|
||||
+90
-123
@@ -181,61 +181,66 @@ void parse_decals_table(const char* filename) {
|
||||
}
|
||||
}
|
||||
|
||||
Decal::Decal() {
|
||||
vm_vec_make(&scale, 1.f, 1.f, 1.f);
|
||||
}
|
||||
struct Decal {
|
||||
int definition_handle = -1;
|
||||
object_h object;
|
||||
int orig_obj_type = OBJ_NONE;
|
||||
int submodel = -1;
|
||||
|
||||
void Decal::markForDeletion() {
|
||||
orig_obj_type = OBJ_NONE;
|
||||
}
|
||||
float creation_time = -1.0f; //!< The mission time at which this decal was created
|
||||
float lifetime = -1.0f; //!< The time this decal is active. When negative it never expires
|
||||
|
||||
bool Decal::isValid() const {
|
||||
if (!object.isValid()) {
|
||||
return false;
|
||||
}
|
||||
if (object.objp()->flags[Object::Object_Flags::Should_be_dead]) {
|
||||
return false;
|
||||
vec3d position = vmd_zero_vector;
|
||||
vec3d scale;
|
||||
matrix orientation = vmd_identity_matrix;
|
||||
|
||||
Decal() {
|
||||
vm_vec_make(&scale, 1.f, 1.f, 1.f);
|
||||
}
|
||||
|
||||
if (orig_obj_type == OBJ_NONE) {
|
||||
//Decal should be cleared
|
||||
return false;
|
||||
}
|
||||
|
||||
if (orig_obj_type != object.objp()->type) {
|
||||
mprintf(("Decal object type for object %d has changed from %s to %s. Please let m!m know about this\n",
|
||||
object.objnum, Object_type_names[orig_obj_type], Object_type_names[object.objp()->type]));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lifetime > 0.0f) {
|
||||
if (f2fl(Missiontime) >= creation_time + lifetime) {
|
||||
// Decal has expired
|
||||
bool isValid() const {
|
||||
if (!object.isValid()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
auto objp = object.objp();
|
||||
if (objp->type == OBJ_SHIP) {
|
||||
auto shipp = &Ships[objp->instance];
|
||||
auto model_instance = model_get_instance(shipp->model_instance_num);
|
||||
|
||||
Assertion(submodel >= 0 && submodel < object_get_model(objp)->n_models,
|
||||
"Invalid submodel number detected!");
|
||||
auto smi = &model_instance->submodel[submodel];
|
||||
|
||||
if (smi->blown_off) {
|
||||
if (object.objp()->flags[Object::Object_Flags::Should_be_dead]) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
Assertion(false, "Only ships are currently supported for decals!");
|
||||
return false;
|
||||
|
||||
if (orig_obj_type != object.objp()->type) {
|
||||
mprintf(("Decal object type for object %d has changed from %s to %s. Please let m!m know about this\n",
|
||||
object.objnum, Object_type_names[orig_obj_type], Object_type_names[object.objp()->type]));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lifetime > 0.0f) {
|
||||
if (f2fl(Missiontime) >= creation_time + lifetime) {
|
||||
// Decal has expired
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
auto objp = object.objp();
|
||||
if (objp->type == OBJ_SHIP) {
|
||||
auto shipp = &Ships[objp->instance];
|
||||
auto model_instance = model_get_instance(shipp->model_instance_num);
|
||||
|
||||
Assertion(submodel >= 0 && submodel < object_get_model(objp)->n_models,
|
||||
"Invalid submodel number detected!");
|
||||
auto smi = &model_instance->submodel[submodel];
|
||||
|
||||
if (smi->blown_off) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
Assertion(false, "Only ships are currently supported for decals!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
SCP_vector<Decal> active_decals, active_single_frame_decals;
|
||||
SCP_vector<Decal> active_decals;
|
||||
|
||||
bool required_string_if_new(const char* token, bool new_entry) {
|
||||
if (!new_entry) {
|
||||
@@ -365,11 +370,7 @@ void initializeMission() {
|
||||
active_decals.clear();
|
||||
}
|
||||
|
||||
// Discard any fragments where the angle to the direction to greater than 45°
|
||||
const float DECAL_ANGLE_CUTOFF = fl_radians(45.f);
|
||||
const float DECAL_ANGLE_FADE_START = fl_radians(30.f);
|
||||
|
||||
static matrix4 getDecalTransform(const Decal& decal, float alpha) {
|
||||
matrix4 getDecalTransform(Decal& decal) {
|
||||
Assertion(decal.object.objp()->type == OBJ_SHIP, "Only ships are currently supported for decals!");
|
||||
|
||||
auto objp = decal.object.objp();
|
||||
@@ -404,62 +405,11 @@ static matrix4 getDecalTransform(const Decal& decal, float alpha) {
|
||||
matrix4 mat4;
|
||||
vm_matrix4_set_transform(&mat4, &worldOrient, &worldPos);
|
||||
|
||||
// This is currently a constant but in the future this may be configurable by the decals table
|
||||
mat4.a2d[0][3] = DECAL_ANGLE_CUTOFF;
|
||||
mat4.a2d[1][3] = DECAL_ANGLE_FADE_START;
|
||||
|
||||
mat4.a2d[2][3] = alpha;
|
||||
|
||||
return mat4;
|
||||
}
|
||||
|
||||
inline static void renderDecal(graphics::decal_draw_list& draw_list, const Decal& decal) {
|
||||
auto mission_time = f2fl(Missiontime);
|
||||
|
||||
int diffuse_bm = -1;
|
||||
int glow_bm = -1;
|
||||
int normal_bm = -1;
|
||||
|
||||
auto decal_time = mission_time - decal.creation_time;
|
||||
auto progress = decal_time / decal.lifetime;
|
||||
|
||||
float alpha = 1.0f;
|
||||
if (progress > 0.8) {
|
||||
// Fade the decal out for the last 20% of its lifetime
|
||||
alpha = 1.0f - smoothstep(0.8f, 1.0f, progress);
|
||||
}
|
||||
|
||||
if (std::holds_alternative<int>(decal.definition_handle)) {
|
||||
int definition_handle = std::get<int>(decal.definition_handle);
|
||||
Assertion(definition_handle >= 0 && definition_handle < (int) DecalDefinitions.size(),
|
||||
"Invalid decal handle detected!");
|
||||
auto &decalDef = DecalDefinitions[definition_handle];
|
||||
|
||||
if (decalDef.getDiffuseBitmap() >= 0) {
|
||||
diffuse_bm = decalDef.getDiffuseBitmap()
|
||||
+
|
||||
bm_get_anim_frame(decalDef.getDiffuseBitmap(), decal_time, 0.0f, decalDef.isDiffuseLooping());
|
||||
}
|
||||
|
||||
if (decalDef.getGlowBitmap() >= 0) {
|
||||
glow_bm = decalDef.getGlowBitmap()
|
||||
+ bm_get_anim_frame(decalDef.getGlowBitmap(), decal_time, 0.0f, decalDef.isGlowLooping());
|
||||
}
|
||||
|
||||
if (decalDef.getNormalBitmap() >= 0) {
|
||||
normal_bm = decalDef.getNormalBitmap()
|
||||
+ bm_get_anim_frame(decalDef.getNormalBitmap(), decal_time, 0.0f, decalDef.isNormalLooping());
|
||||
}
|
||||
}
|
||||
else {
|
||||
std::tie(diffuse_bm, glow_bm, normal_bm) = std::get<std::tuple<int, int, int>>(decal.definition_handle);
|
||||
}
|
||||
|
||||
draw_list.add_decal(diffuse_bm, glow_bm, normal_bm, decal_time, getDecalTransform(decal, alpha));
|
||||
}
|
||||
|
||||
void renderAll() {
|
||||
if (!Decal_system_active || !Decal_option_active || !gr_is_capable(gr_capability::CAPABILITY_INSTANCED_RENDERING)) {
|
||||
if (!Decal_system_active || !Decal_option_active) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -482,21 +432,51 @@ void renderAll() {
|
||||
++iter;
|
||||
}
|
||||
|
||||
if (active_decals.empty() && active_single_frame_decals.empty()) {
|
||||
if (active_decals.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto mission_time = f2fl(Missiontime);
|
||||
|
||||
graphics::decal_draw_list draw_list(active_decals.size());
|
||||
for (auto& decal : active_decals) {
|
||||
|
||||
graphics::decal_draw_list draw_list;
|
||||
for (auto& decal : active_decals)
|
||||
renderDecal(draw_list, decal);
|
||||
for (auto& decal : active_single_frame_decals)
|
||||
renderDecal(draw_list, decal);
|
||||
Assertion(decal.definition_handle >= 0 && decal.definition_handle < (int)DecalDefinitions.size(),
|
||||
"Invalid decal handle detected!");
|
||||
auto& decalDef = DecalDefinitions[decal.definition_handle];
|
||||
|
||||
int diffuse_bm = -1;
|
||||
int glow_bm = -1;
|
||||
int normal_bm = -1;
|
||||
|
||||
auto decal_time = mission_time - decal.creation_time;
|
||||
auto progress = decal_time / decal.lifetime;
|
||||
|
||||
float alpha = 1.0f;
|
||||
if (progress > 0.8) {
|
||||
// Fade the decal out for the last 20% of its lifetime
|
||||
alpha = 1.0f - smoothstep(0.8f, 1.0f, progress);
|
||||
}
|
||||
|
||||
if (decalDef.getDiffuseBitmap() >= 0) {
|
||||
diffuse_bm = decalDef.getDiffuseBitmap()
|
||||
+ bm_get_anim_frame(decalDef.getDiffuseBitmap(), decal_time, 0.0f, decalDef.isDiffuseLooping());
|
||||
}
|
||||
|
||||
if (decalDef.getGlowBitmap() >= 0) {
|
||||
glow_bm = decalDef.getGlowBitmap()
|
||||
+ bm_get_anim_frame(decalDef.getGlowBitmap(), decal_time, 0.0f, decalDef.isGlowLooping());
|
||||
}
|
||||
|
||||
if (decalDef.getNormalBitmap() >= 0) {
|
||||
normal_bm = decalDef.getNormalBitmap()
|
||||
+ bm_get_anim_frame(decalDef.getNormalBitmap(), decal_time, 0.0f, decalDef.isNormalLooping());
|
||||
}
|
||||
|
||||
draw_list.add_decal(diffuse_bm, glow_bm, normal_bm, decal_time, getDecalTransform(decal), alpha);
|
||||
}
|
||||
|
||||
draw_list.render();
|
||||
|
||||
active_single_frame_decals.clear();
|
||||
}
|
||||
|
||||
void addDecal(creation_info& info, const object* host, int submodel, const vec3d& local_pos, const matrix& local_orient) {
|
||||
@@ -541,17 +521,4 @@ void addDecal(creation_info& info, const object* host, int submodel, const vec3d
|
||||
active_decals.push_back(newDecal);
|
||||
}
|
||||
|
||||
void addSingleFrameDecal(Decal&& info) {
|
||||
active_single_frame_decals.push_back(info);
|
||||
}
|
||||
|
||||
void invalidateForShip(const ship* shipp) {
|
||||
int objnum = shipp->objnum;
|
||||
for (Decal& decal : active_decals) {
|
||||
if (decal.object.objnum == objnum) {
|
||||
decal.markForDeletion();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -50,27 +50,6 @@ class DecalDefinition {
|
||||
bool isNormalLooping() const;
|
||||
};
|
||||
|
||||
struct Decal {
|
||||
//DecalDefinition idx vs immediate diffuse/glow/normal
|
||||
std::variant<int, std::tuple<int, int, int>> definition_handle = -1;
|
||||
object_h object;
|
||||
int orig_obj_type = OBJ_NONE;
|
||||
int submodel = -1;
|
||||
|
||||
float creation_time = -1.0f; //!< The mission time at which this decal was created
|
||||
float lifetime = -1.0f; //!< The time this decal is active. When negative it never expires
|
||||
|
||||
vec3d position = vmd_zero_vector;
|
||||
vec3d scale;
|
||||
matrix orientation = vmd_identity_matrix;
|
||||
|
||||
Decal();
|
||||
|
||||
void markForDeletion();
|
||||
|
||||
bool isValid() const;
|
||||
};
|
||||
|
||||
extern SCP_vector<DecalDefinition> DecalDefinitions;
|
||||
extern bool Decal_system_active;
|
||||
extern bool Decal_option_active;
|
||||
@@ -160,8 +139,4 @@ void addDecal(creation_info& info,
|
||||
const vec3d& local_pos,
|
||||
const matrix& local_orient);
|
||||
|
||||
void addSingleFrameDecal(Decal&& info);
|
||||
|
||||
void invalidateForShip(const ship* shipp);
|
||||
|
||||
}
|
||||
@@ -65,7 +65,7 @@ $Max Player Attackers: 2, 3, 4, 5, 99
|
||||
|
||||
;; maximum number of active (i.e. 'thrown') asteroids that can be
|
||||
;; heading toward a friendly ship at any given time
|
||||
$Max Incoming Asteroids: 3, 4, 5, 7, 10
|
||||
$Max Incoming Asteroids: 3, 4, 5, 7, 10
|
||||
|
||||
;; factor applied to damage suffered by the player
|
||||
$Player Damage Factor: 0.25, 0.5, 0.65, 0.85, 1
|
||||
@@ -181,8 +181,9 @@ $Player Autoaim FOV: 0, 0, 0, 0, 0
|
||||
$Detail Distance Multiplier: 0.125, 0.25, 1.0, 4.0, 8.0
|
||||
|
||||
;; General AI-related flags. These were previously all lumped together
|
||||
;; under the New AI mission flag.
|
||||
|
||||
;; under the New AI mission flag.
|
||||
|
||||
|
||||
;; if set, big ships can attack a beam turret that's firing on them
|
||||
;; from a ship that they don't currently have targeted.
|
||||
$big ships can attack beam turrets on untargeted ships: NO
|
||||
@@ -353,10 +354,6 @@ $no warp camera: NO
|
||||
|
||||
;; If set, this flag overrides the retail behavior whereby a ship
|
||||
;; assigned to guard a ship in a wing will instead guard the entire wing
|
||||
$ai guards specific ship in wing: NO
|
||||
|
||||
;; maximum number of allies allowed to be rearming at the same time
|
||||
;; before the AI will hold off on requesting support
|
||||
$max allies rearming threshold: 2
|
||||
$ai guards specific ship in wing: NO
|
||||
|
||||
#End
|
||||
@@ -10,12 +10,6 @@ out vec4 fragOut0; // Diffuse buffer
|
||||
out vec4 fragOut1; // Normal buffer
|
||||
out vec4 fragOut2; // Emissive buffer
|
||||
|
||||
flat in mat4 invModelMatrix;
|
||||
flat in vec3 decalDirection;
|
||||
flat in float normal_angle_cutoff;
|
||||
flat in float angle_fade_start;
|
||||
flat in float alpha_scale;
|
||||
|
||||
uniform sampler2D gDepthBuffer;
|
||||
uniform sampler2D gNormalBuffer;
|
||||
|
||||
@@ -29,15 +23,24 @@ layout (std140) uniform decalGlobalData {
|
||||
mat4 invViewMatrix;
|
||||
mat4 invProjMatrix;
|
||||
|
||||
vec3 ambientLight;
|
||||
|
||||
vec2 viewportSize;
|
||||
};
|
||||
|
||||
layout (std140) uniform decalInfoData {
|
||||
mat4 model_matrix;
|
||||
mat4 inv_model_matrix;
|
||||
|
||||
vec3 decal_direction;
|
||||
float normal_angle_cutoff;
|
||||
|
||||
int diffuse_index;
|
||||
int glow_index;
|
||||
int normal_index;
|
||||
int diffuse_blend_mode;
|
||||
float angle_fade_start;
|
||||
|
||||
float alpha_scale;
|
||||
int diffuse_blend_mode;
|
||||
int glow_blend_mode;
|
||||
};
|
||||
|
||||
@@ -74,7 +77,7 @@ vec3 getPixelNormal(vec3 frag_position, vec2 tex_coord, inout float alpha, out v
|
||||
#endif
|
||||
|
||||
//Calculate angle between surface normal and decal direction
|
||||
float angle = acos(dot(normal, decalDirection));
|
||||
float angle = acos(dot(normal, decal_direction));
|
||||
|
||||
if (angle > normal_angle_cutoff) {
|
||||
// The angle between surface normal and decal direction is too big
|
||||
@@ -88,7 +91,7 @@ vec3 getPixelNormal(vec3 frag_position, vec2 tex_coord, inout float alpha, out v
|
||||
}
|
||||
|
||||
vec2 getDecalTexCoord(vec3 view_pos, inout float alpha) {
|
||||
vec4 object_pos = invModelMatrix * invViewMatrix * vec4(view_pos, 1.0);
|
||||
vec4 object_pos = inv_model_matrix * invViewMatrix * vec4(view_pos, 1.0);
|
||||
|
||||
bvec3 invalidComponents = greaterThan(abs(object_pos.xyz), vec3(0.5));
|
||||
bvec4 nanComponents = isnan(object_pos); // nan can happen some times if we have an infinite depth value
|
||||
@@ -108,7 +111,6 @@ void main() {
|
||||
vec3 frag_position = computeViewPosition(gl_FragCoord.xy);
|
||||
|
||||
float alpha = alpha_scale;
|
||||
|
||||
vec2 tex_coord = getDecalTexCoord(frag_position, alpha);
|
||||
|
||||
vec3 binormal;
|
||||
@@ -132,6 +134,16 @@ void main() {
|
||||
// Additive blending
|
||||
diffuse_out = vec4(color.rgb * alpha, 1.0);
|
||||
}
|
||||
|
||||
// The main model shader applies ambient lighting by drawing the ambient part of the texture into the emissive
|
||||
// texture. We do the same here to make sure the decal material is applied correctly
|
||||
if (glow_blend_mode == 0) {
|
||||
// Normal alpha blending
|
||||
emissive_out = vec4(color.rgb * ambientLight, color.a * alpha);
|
||||
} else {
|
||||
// Additive blending
|
||||
emissive_out = vec4(alpha * color.rgb * ambientLight, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
if (glow_index >= 0) {
|
||||
|
||||
@@ -1,12 +1,5 @@
|
||||
|
||||
in vec4 vertPosition;
|
||||
in mat4 vertModelMatrix;
|
||||
|
||||
flat out mat4 invModelMatrix;
|
||||
flat out vec3 decalDirection;
|
||||
flat out float normal_angle_cutoff;
|
||||
flat out float angle_fade_start;
|
||||
flat out float alpha_scale;
|
||||
|
||||
layout (std140) uniform decalGlobalData {
|
||||
mat4 viewMatrix;
|
||||
@@ -14,29 +7,27 @@ layout (std140) uniform decalGlobalData {
|
||||
mat4 invViewMatrix;
|
||||
mat4 invProjMatrix;
|
||||
|
||||
vec3 ambientLight;
|
||||
|
||||
vec2 viewportSize;
|
||||
};
|
||||
|
||||
layout (std140) uniform decalInfoData {
|
||||
mat4 model_matrix;
|
||||
mat4 inv_model_matrix;
|
||||
|
||||
vec3 decal_direction;
|
||||
float normal_angle_cutoff;
|
||||
|
||||
int diffuse_index;
|
||||
int glow_index;
|
||||
int normal_index;
|
||||
int diffuse_blend_mode;
|
||||
float angle_fade_start;
|
||||
|
||||
float alpha_scale;
|
||||
int diffuse_blend_mode;
|
||||
int glow_blend_mode;
|
||||
};
|
||||
|
||||
void main() {
|
||||
normal_angle_cutoff = vertModelMatrix[0][3];
|
||||
angle_fade_start = vertModelMatrix[1][3];
|
||||
alpha_scale = vertModelMatrix[2][3];
|
||||
|
||||
mat4 modelMatrix = vertModelMatrix;
|
||||
modelMatrix[0][3] = 0.0;
|
||||
modelMatrix[1][3] = 0.0;
|
||||
modelMatrix[2][3] = 0.0;
|
||||
|
||||
invModelMatrix = inverse(modelMatrix);
|
||||
decalDirection = mat3(viewMatrix) * modelMatrix[2].xyz;
|
||||
gl_Position = projMatrix * viewMatrix * modelMatrix * vertPosition;
|
||||
gl_Position = projMatrix * viewMatrix * model_matrix * vertPosition;
|
||||
}
|
||||
@@ -7,7 +7,7 @@ out vec4 fragOut5;
|
||||
void main()
|
||||
{
|
||||
fragOut0 = vec4(0.0, 0.0, 0.0, 1.0); // color
|
||||
fragOut1 = vec4(0.0, 0.0, -1000000.0, 0.0); // position
|
||||
fragOut1 = vec4(0.0, 0.0, -1000000.0, 1.0); // position
|
||||
fragOut2 = vec4(0.0, 0.0, 0.0, 1.0); // normal
|
||||
fragOut3 = vec4(0.0, 0.0, 0.0, 0.0); // specular
|
||||
fragOut4 = vec4(0.0, 0.0, 0.0, 1.0); // emissive
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
//? #version 150
|
||||
#include "lighting.sdr" //! #include "lighting.sdr"
|
||||
#include "gamma.sdr" //! #include "gamma.sdr"
|
||||
|
||||
#include "shadows.sdr" //! #include "shadows.sdr"
|
||||
#include "z-compress.sdr" //! #include "z-compress.sdr"
|
||||
|
||||
out vec4 fragOut0;
|
||||
|
||||
@@ -12,11 +11,6 @@ uniform sampler2D PositionBuffer;
|
||||
uniform sampler2D SpecBuffer;
|
||||
uniform sampler2DArray shadow_map;
|
||||
|
||||
#ifdef ENV_MAP
|
||||
uniform samplerCube sEnvmap;
|
||||
uniform samplerCube sIrrmap;
|
||||
#endif
|
||||
|
||||
layout (std140) uniform globalDeferredData {
|
||||
mat4 shadow_mv_matrix;
|
||||
mat4 shadow_proj_matrix[4];
|
||||
@@ -103,7 +97,7 @@ void GetLightInfo(vec3 position, in float alpha, in vec3 reflectDir, out vec3 li
|
||||
discard;
|
||||
}
|
||||
attenuation = 1.0 - clamp(sqrt(dist / lightRadius), 0.0, 1.0);
|
||||
}
|
||||
}
|
||||
else if (lightType == LT_TUBE) { // Tube light
|
||||
vec3 beamVec = vec3(modelViewMatrix * vec4(0.0, 0.0, -scale.z, 0.0));
|
||||
vec3 beamDir = normalize(beamVec);
|
||||
@@ -144,7 +138,7 @@ void GetLightInfo(vec3 position, in float alpha, in vec3 reflectDir, out vec3 li
|
||||
discard;
|
||||
}
|
||||
attenuation = 1.0 - clamp(sqrt(dist / lightRadius), 0.0, 1.0);
|
||||
}
|
||||
}
|
||||
else if (lightType == LT_CONE) {
|
||||
lightDirOut = lightPosition - position.xyz;
|
||||
float coneDot = dot(normalize(-lightDirOut), coneDir);
|
||||
@@ -171,108 +165,46 @@ void GetLightInfo(vec3 position, in float alpha, in vec3 reflectDir, out vec3 li
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ENV_MAP
|
||||
void ComputeEnvLight(float alpha, float ao, vec3 light_dir, vec3 eyeDir, vec3 normal, vec4 baseColor, vec4 specColor, out vec3 envLight) {
|
||||
// Bit of a hack here, pretend we're doing blinn-phong shading and use a (modified version of) the derivation from
|
||||
// Plausible Blinn-Phong Reflection of Standard Cube MIP-Maps - McGuire et al.
|
||||
// to determine the mip bias.
|
||||
// We use the specular term listed at http://graphicrants.blogspot.com/2013/08/specular-brdf-reference.html
|
||||
// 1/(pi*alpha^2) * NdotM^((2/alpha^2)-2)
|
||||
// so let s = (2/alpha^2 - 2)
|
||||
// 1/2 log(s + 1) = 1/2 log(2/alpha^2 -1)
|
||||
|
||||
const float ENV_REZ = 512; // Ideally this would be #define'd and shader recompiled with envmap rez changes
|
||||
const float REZ_BIAS = log2(ENV_REZ * sqrt(3));
|
||||
|
||||
float alphaSqr = alpha * alpha;
|
||||
float rough_bias = 0.5 * log2(2/alphaSqr - 1);
|
||||
float mip_bias = REZ_BIAS - rough_bias;
|
||||
|
||||
// Sample light, using mip bias to blur it.
|
||||
vec3 env_light_dir = vec3(modelViewMatrix * vec4(light_dir, 0.0));
|
||||
vec4 specEnvColour = srgb_to_linear(textureLod(sEnvmap, env_light_dir, mip_bias));
|
||||
|
||||
vec3 halfVec = normal;
|
||||
|
||||
// Lots of hacks here to get things to look right. We aren't loading a BRDF split-sum integral texture
|
||||
// or properly calculating IBL levels.
|
||||
// Fresnel calculation as with standard lights.
|
||||
|
||||
vec3 fresnel = mix(specColor.rgb, FresnelSchlick(halfVec, eyeDir, specColor.rgb), specColor.a);
|
||||
|
||||
// Pseudo-IBL, so use k_IBL
|
||||
float k = alpha * alpha/ 2.0f;
|
||||
|
||||
float NdotL = max(dot(light_dir, normal),0);
|
||||
|
||||
float g1vNL = GeometrySchlickGGX(NdotL, k);
|
||||
vec3 specEnvLighting = specEnvColour.rgb * fresnel * g1vNL;
|
||||
|
||||
vec3 kD = vec3(1.0)-fresnel;
|
||||
kD *= (vec3(1.0) - specColor.rgb);
|
||||
vec3 diffEnvColor = srgb_to_linear(texture(sIrrmap, vec3(modelViewMatrix * vec4(normal, 0.0))).rgb);
|
||||
vec3 diffEnvLighting = kD * baseColor.rgb * diffEnvColor * ao;
|
||||
envLight = (specEnvLighting + diffEnvLighting) * baseColor.a;
|
||||
}
|
||||
#endif
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 screenPos = gl_FragCoord.xy * vec2(invScreenWidth, invScreenHeight);
|
||||
vec4 position_buffer = texture(PositionBuffer, screenPos);
|
||||
vec3 position = vec3(position_buffer.xy, uncompress_depth_value(position_buffer.z));
|
||||
vec3 position = texture(PositionBuffer, screenPos).xyz;
|
||||
|
||||
if(abs(dot(position, position)) < nearPlane * nearPlane)
|
||||
discard;
|
||||
|
||||
vec4 diffuse = texture(ColorBuffer, screenPos);
|
||||
vec3 diffColor = diffuse.rgb;
|
||||
vec3 diffColor = texture(ColorBuffer, screenPos).rgb;
|
||||
vec4 normalData = texture(NormalBuffer, screenPos);
|
||||
vec4 specColor = texture(SpecBuffer, screenPos);
|
||||
// The vector in the normal buffer could be longer than the unit vector since decal rendering only adds to the normal buffer
|
||||
vec3 normal = normalize(normalData.xyz);
|
||||
float gloss = normalData.a;
|
||||
float roughness = clamp(1.0f - gloss, 0.0f, 1.0f);
|
||||
float alpha = roughness * roughness;
|
||||
float fresnel = specColor.a;
|
||||
vec3 eyeDir = normalize(-position);
|
||||
|
||||
vec3 lightDir;
|
||||
float attenuation;
|
||||
float area_normalisation;
|
||||
vec3 reflectDir = reflect(-eyeDir, normal);
|
||||
vec4 specColor = texture(SpecBuffer, screenPos);
|
||||
GetLightInfo(position, alpha, reflectDir, lightDir, attenuation, area_normalisation);
|
||||
|
||||
if (enable_shadows) {
|
||||
vec4 fragShadowPos = shadow_mv_matrix * inv_view_matrix * vec4(position, 1.0);
|
||||
vec4 fragShadowUV[4];
|
||||
fragShadowUV[0] = transformToShadowMap(shadow_proj_matrix[0], 0, fragShadowPos);
|
||||
fragShadowUV[1] = transformToShadowMap(shadow_proj_matrix[1], 1, fragShadowPos);
|
||||
fragShadowUV[2] = transformToShadowMap(shadow_proj_matrix[2], 2, fragShadowPos);
|
||||
fragShadowUV[3] = transformToShadowMap(shadow_proj_matrix[3], 3, fragShadowPos);
|
||||
|
||||
attenuation *= getShadowValue(shadow_map, -position.z, fragShadowPos.z, fragShadowUV, fardist, middist,
|
||||
neardist, veryneardist);
|
||||
}
|
||||
|
||||
vec3 halfVec = normalize(lightDir + eyeDir);
|
||||
float NdotL = clamp(dot(normal, lightDir), 0.0, 1.0);
|
||||
vec4 fragmentColor = vec4(1.0);
|
||||
|
||||
if (lightType == LT_AMBIENT) {
|
||||
float ao = position_buffer.w;
|
||||
fragmentColor.rgb = diffuseLightColor * diffColor * ao;
|
||||
|
||||
#ifdef ENV_MAP
|
||||
vec3 envLight;
|
||||
ComputeEnvLight(alpha, ao, reflectDir, eyeDir, normal, diffuse, specColor, envLight);
|
||||
fragmentColor.rgb += envLight;
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
float fresnel = specColor.a;
|
||||
|
||||
vec3 lightDir;
|
||||
float attenuation;
|
||||
float area_normalisation;
|
||||
GetLightInfo(position, alpha, reflectDir, lightDir, attenuation, area_normalisation);
|
||||
|
||||
if (enable_shadows) {
|
||||
vec4 fragShadowPos = shadow_mv_matrix * inv_view_matrix * vec4(position, 1.0);
|
||||
vec4 fragShadowUV[4];
|
||||
fragShadowUV[0] = transformToShadowMap(shadow_proj_matrix[0], 0, fragShadowPos);
|
||||
fragShadowUV[1] = transformToShadowMap(shadow_proj_matrix[1], 1, fragShadowPos);
|
||||
fragShadowUV[2] = transformToShadowMap(shadow_proj_matrix[2], 2, fragShadowPos);
|
||||
fragShadowUV[3] = transformToShadowMap(shadow_proj_matrix[3], 3, fragShadowPos);
|
||||
|
||||
attenuation *= getShadowValue(shadow_map, -position.z, fragShadowPos.z, fragShadowUV, fardist, middist,
|
||||
neardist, veryneardist);
|
||||
}
|
||||
|
||||
vec3 halfVec = normalize(lightDir + eyeDir);
|
||||
float NdotL = clamp(dot(normal, lightDir), 0.0, 1.0);
|
||||
fragmentColor.rgb = computeLighting(specColor.rgb, diffColor, lightDir, normal.xyz, halfVec, eyeDir, roughness, fresnel, NdotL).rgb * diffuseLightColor * attenuation * area_normalisation;
|
||||
}
|
||||
|
||||
fragmentColor.rgb = computeLighting(specColor.rgb, diffColor, lightDir, normal.xyz, halfVec, eyeDir, roughness, fresnel, NdotL).rgb * diffuseLightColor * attenuation * area_normalisation;
|
||||
fragOut0 = max(fragmentColor, vec4(0.0));
|
||||
}
|
||||
@@ -29,7 +29,7 @@ layout (std140) uniform lightData {
|
||||
|
||||
void main()
|
||||
{
|
||||
if (lightType == LT_DIRECTIONAL || lightType == LT_AMBIENT) {
|
||||
if (lightType == LT_DIRECTIONAL) {
|
||||
gl_Position = vec4(vertPosition.xyz, 1.0);
|
||||
} else {
|
||||
gl_Position = projMatrix * modelViewMatrix * vec4(vertPosition.xyz * scale, 1.0);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
|
||||
#include "gamma.sdr"
|
||||
#include "z-compress.sdr"
|
||||
|
||||
in float fragRadius;
|
||||
in vec4 fragPosition;
|
||||
@@ -39,7 +38,7 @@ void main()
|
||||
float sceneDepthLinear;
|
||||
float fragDepthLinear;
|
||||
if ( linear_depth == 1 ) {
|
||||
sceneDepthLinear = -uncompress_depth_value(sceneDepth.z);
|
||||
sceneDepthLinear = -sceneDepth.z;
|
||||
fragDepthLinear = -fragPosition.z;
|
||||
} else {
|
||||
sceneDepthLinear = ( 2.0 * farZ * nearZ ) / ( farZ + nearZ - sceneDepth.x * (farZ-nearZ) );
|
||||
|
||||
@@ -15,9 +15,6 @@ layout (std140) uniform genericData {
|
||||
float fog_density;
|
||||
float zNear;
|
||||
float zFar;
|
||||
|
||||
float clip_inf_dist;
|
||||
float clip_dist;
|
||||
};
|
||||
|
||||
void main()
|
||||
@@ -31,9 +28,6 @@ void main()
|
||||
// Now we compute the depth value in projection space using the clipping plane information
|
||||
float view_depth = 2.0 * zNear * zFar / (zFar + zNear - depth_normalized * (zFar - zNear));
|
||||
|
||||
float skybox_compat_fake = step(1.0, depth_val);
|
||||
view_depth = clamp(view_depth, 0.0, mix(clip_dist, clip_inf_dist, skybox_compat_fake));
|
||||
|
||||
if (isinf(view_depth)) {
|
||||
fragOut0.rgb = color_in.rgb;
|
||||
} else {
|
||||
|
||||
@@ -3,7 +3,6 @@ const int LT_DIRECTIONAL = 0; // A light like a sun
|
||||
const int LT_POINT = 1; // A point light, like an explosion
|
||||
const int LT_TUBE = 2; // A tube light, like a fluorescent light
|
||||
const int LT_CONE = 3; // A cone light, like a flood light
|
||||
const int LT_AMBIENT = 4; // Directionless ambient light
|
||||
|
||||
const float SPEC_FACTOR_NO_SPEC_MAP = 0.1;
|
||||
const float GLOW_MAP_INTENSITY = 1.5;
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#include "shadows.sdr" //! #include "shadows.sdr"
|
||||
#include "lighting.sdr" //! #include "lighting.sdr"
|
||||
#include "gamma.sdr" //! #include "gamma.sdr"
|
||||
#include "z-compress.sdr" //! #include "z-compress.sdr"
|
||||
|
||||
#conditional_include +"LARGE_SHADER" "main_large.sdr"
|
||||
#conditional_include -"LARGE_SHADER" "main_small.sdr"
|
||||
@@ -33,14 +32,15 @@ layout (std140) uniform modelData {
|
||||
mat4 textureMatrix;
|
||||
mat4 shadow_mv_matrix;
|
||||
mat4 shadow_proj_matrix[4];
|
||||
mat4 envMatrix;
|
||||
|
||||
vec4 color;
|
||||
|
||||
model_light lights[MAX_LIGHTS];
|
||||
|
||||
float outlineWidth;
|
||||
float fogNear;
|
||||
float fogDensity;
|
||||
float fogStart;
|
||||
float fogScale;
|
||||
int buffer_matrix_offset;
|
||||
|
||||
vec4 clip_equation;
|
||||
@@ -50,7 +50,6 @@ layout (std140) uniform modelData {
|
||||
int n_lights;
|
||||
float defaultGloss;
|
||||
|
||||
//EXCLUSIVELY used for non-deferred rendering
|
||||
vec3 ambientFactor;
|
||||
int desaturate;
|
||||
|
||||
@@ -86,16 +85,22 @@ layout (std140) uniform modelData {
|
||||
float fardist;
|
||||
|
||||
int sGlowmapIndex;
|
||||
|
||||
int sSpecmapIndex;
|
||||
int sNormalmapIndex;
|
||||
int sAmbientmapIndex;
|
||||
|
||||
int sMiscmapIndex;
|
||||
|
||||
float alphaMult;
|
||||
|
||||
int flags;
|
||||
};
|
||||
|
||||
in VertexOutput {
|
||||
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_ENV
|
||||
vec3 envReflect;
|
||||
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_ENV
|
||||
|
||||
mat3 tangentMatrix;
|
||||
|
||||
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_FOG
|
||||
@@ -121,6 +126,10 @@ uniform sampler2DArray sGlowmap;
|
||||
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_SPEC
|
||||
uniform sampler2DArray sSpecmap;
|
||||
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_SPEC
|
||||
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_ENV
|
||||
uniform samplerCube sEnvmap;
|
||||
uniform samplerCube sIrrmap;
|
||||
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_ENV
|
||||
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_NORMAL
|
||||
uniform sampler2DArray sNormalmap;
|
||||
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_NORMAL
|
||||
@@ -178,7 +187,7 @@ void GetLightInfo(int i, out vec3 lightDir, out float attenuation)
|
||||
vec3 CalculateLighting(vec3 normal, vec3 diffuseMaterial, vec3 specularMaterial, float gloss, float fresnel, float shadow, float aoFactor)
|
||||
{
|
||||
vec3 eyeDir = vec3(normalize(-vertIn.position).xyz);
|
||||
vec3 lightAmbient = ambientFactor * aoFactor;
|
||||
vec3 lightAmbient = (emissionFactor + ambientFactor * ambientFactor) * aoFactor; // ambientFactor^2 due to legacy OpenGL compatibility behavior
|
||||
vec3 lightDiffuse = vec3(0.0, 0.0, 0.0);
|
||||
vec3 lightSpecular = vec3(0.0, 0.0, 0.0);
|
||||
#pragma optionNV unroll all
|
||||
@@ -333,7 +342,19 @@ void main()
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_MISC
|
||||
|
||||
// Lights aren't applied when we are rendering to the G-buffers since that gets handled later
|
||||
#prereplace IF_NOT_FLAG MODEL_SDR_FLAG_DEFERRED
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_DEFERRED
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_LIGHT
|
||||
// Ambient lighting still needs to be done since that counts as an "emissive" color
|
||||
vec3 lightAmbient = (emissionFactor + ambientFactor * ambientFactor) * aoFactors.x; // ambientFactor^2 due to legacy OpenGL compatibility behavior
|
||||
emissiveColor.rgb += baseColor.rgb * lightAmbient;
|
||||
#prereplace ELSE_FLAG //MODEL_SDR_FLAG_LIGHT
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_SPEC
|
||||
baseColor.rgb += pow(1.0 - clamp(dot(eyeDir, normal), 0.0, 1.0), 5.0 * clamp(glossData, 0.01, 1.0)) * specColor.rgb;
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_SPEC
|
||||
// If there is no lighting then we copy the color data so far into the
|
||||
emissiveColor.rgb += baseColor.rgb;
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_LIGHT
|
||||
#prereplace ELSE_FLAG //MODEL_SDR_FLAG_DEFERRED
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_LIGHT
|
||||
float shadow = 1.0;
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_SHADOWS
|
||||
@@ -347,6 +368,54 @@ void main()
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_LIGHT
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_DEFERRED
|
||||
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_ENV
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_LIGHT
|
||||
// Bit of a hack here, pretend we're doing blinn-phong shading and use a (modified version of) the derivation from
|
||||
// Plausible Blinn-Phong Reflection of Standard Cube MIP-Maps - McGuire et al.
|
||||
// to determine the mip bias.
|
||||
// We use the specular term listed at http://graphicrants.blogspot.com/2013/08/specular-brdf-reference.html
|
||||
// 1/(pi*alpha^2) * NdotM^((2/alpha^2)-2)
|
||||
// so let s = (2/alpha^2 - 2)
|
||||
// 1/2 log(s + 1) = 1/2 log(2/alpha^2 -1)
|
||||
|
||||
const float ENV_REZ = 512; // Ideally this would be #define'd and shader recompiled with envmap rez changes
|
||||
const float REZ_BIAS = log2(ENV_REZ * sqrt(3));
|
||||
|
||||
float roughness = clamp(1.0f - glossData, 0.0f, 1.0f);
|
||||
float alpha = roughness * roughness;
|
||||
float alphaSqr = alpha * alpha;
|
||||
float rough_bias = 0.5 * log2(2/alphaSqr - 1);
|
||||
float mip_bias = REZ_BIAS - rough_bias;
|
||||
|
||||
// Sample light, using mip bias to blur it.
|
||||
vec3 light_dir = reflect(-eyeDir, normal);
|
||||
vec3 env_light_dir = vec3(envMatrix * vec4(light_dir, 0.0));
|
||||
vec4 specEnvColour = srgb_to_linear(textureLod(sEnvmap, env_light_dir, mip_bias));
|
||||
|
||||
vec3 halfVec = normal;
|
||||
|
||||
// Lots of hacks here to get things to look right. We aren't loading a BRDF split-sum integral texture
|
||||
// or properly calculating IBL levels.
|
||||
// Fresnel calculation as with standard lights.
|
||||
|
||||
vec3 fresnel = mix(specColor.rgb, FresnelSchlick(halfVec, eyeDir, specColor.rgb), specColor.a);
|
||||
|
||||
// Pseudo-IBL, so use k_IBL
|
||||
float k = alpha * alpha/ 2.0f;
|
||||
|
||||
float NdotL = max(dot(light_dir, normal),0);
|
||||
|
||||
float g1vNL = GeometrySchlickGGX(NdotL, k);
|
||||
vec3 specEnvLighting = specEnvColour.rgb * fresnel * g1vNL;
|
||||
|
||||
vec3 kD = vec3(1.0)-fresnel;
|
||||
kD *= (vec3(1.0) - specColor.rgb);
|
||||
vec3 diffEnvColor = srgb_to_linear(texture(sIrrmap, vec3(envMatrix * vec4(normal, 0.0))).rgb);
|
||||
vec3 diffEnvLighting = kD * baseColor.rgb * diffEnvColor * aoFactors.x;
|
||||
emissiveColor.rgb += (specEnvLighting + diffEnvLighting) * baseColor.a;
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_LIGHT
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_ENV
|
||||
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_GLOW
|
||||
vec3 glowColor = texture(sGlowmap, vec3(texCoord, float(sGlowmapIndex))).rgb;
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_MISC
|
||||
@@ -376,10 +445,9 @@ void main()
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_DIFFUSE
|
||||
// This code will only be used by the forward renderer so we apply the fog effect to both the emissive and the base
|
||||
// color.
|
||||
float fogDensityFinal = clamp(1 - pow(fogDensity, vertIn.fogDist) , 0.0, 1.0);
|
||||
baseColor.rgb = mix(emissiveColor.rgb + baseColor.rgb, finalFogColor, fogDensityFinal);
|
||||
baseColor.rgb = mix(emissiveColor.rgb + baseColor.rgb, finalFogColor, vertIn.fogDist);
|
||||
emissiveColor.rgb = vec3(0.0); // Zero the emissive color since it has already been added by the previous line
|
||||
specColor.rgb *= fogDensityFinal;
|
||||
specColor.rgb *= vertIn.fogDist;
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_FOG
|
||||
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_DIFFUSE
|
||||
@@ -415,22 +483,10 @@ void main()
|
||||
baseColor.rgb += emissiveColor.rgb;
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_DEFERRED
|
||||
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_DEFERRED
|
||||
#prereplace IF_NOT_FLAG MODEL_SDR_FLAG_LIGHT
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_SPEC
|
||||
baseColor.rgb += pow(1.0 - clamp(dot(eyeDir, normal), 0.0, 1.0), 5.0 * clamp(glossData, 0.01, 1.0)) * specColor.rgb;
|
||||
glossData = 0;
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_SPEC
|
||||
// If there is no lighting then we copy the color data so far into the emissive.
|
||||
emissiveColor.rgb += baseColor.rgb;
|
||||
aoFactors.x = 0;
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_LIGHT
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_DEFERRED
|
||||
|
||||
fragOut0 = baseColor;
|
||||
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_DEFERRED
|
||||
fragOut1 = vec4(vertIn.position.xy, compress_depth_value(vertIn.position.z), aoFactors.x);
|
||||
fragOut1 = vec4(vertIn.position.xyz, 1.0);
|
||||
fragOut2 = vec4(normal, glossData);
|
||||
fragOut3 = vec4(specColor.rgb, fresnelFactor);
|
||||
fragOut4 = emissiveColor;
|
||||
|
||||
@@ -39,14 +39,15 @@ layout (std140) uniform modelData {
|
||||
mat4 textureMatrix;
|
||||
mat4 shadow_mv_matrix;
|
||||
mat4 shadow_proj_matrix[4];
|
||||
mat4 envMatrix;
|
||||
|
||||
vec4 color;
|
||||
|
||||
model_light lights[MAX_LIGHTS];
|
||||
|
||||
float outlineWidth;
|
||||
float fogNear;
|
||||
float fogDensity;
|
||||
float fogStart;
|
||||
float fogScale;
|
||||
int buffer_matrix_offset;
|
||||
|
||||
vec4 clip_equation;
|
||||
@@ -102,6 +103,10 @@ layout (std140) uniform modelData {
|
||||
};
|
||||
|
||||
in VertexOutput {
|
||||
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_ENV
|
||||
vec3 envReflect;
|
||||
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_ENV
|
||||
|
||||
mat3 tangentMatrix;
|
||||
|
||||
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_FOG
|
||||
@@ -126,6 +131,10 @@ in VertexOutput {
|
||||
} vertIn[];
|
||||
|
||||
out VertexOutput {
|
||||
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_ENV
|
||||
vec3 envReflect;
|
||||
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_ENV
|
||||
|
||||
mat3 tangentMatrix;
|
||||
|
||||
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_FOG
|
||||
@@ -163,12 +172,19 @@ out VertexOutput {
|
||||
gl_Position = shadow_proj_matrix[instanceID] * gl_in[vert].gl_Position;
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_TRANSFORM
|
||||
|
||||
if(gl_Position.z < -1.0)
|
||||
gl_Position.z = -1.0;
|
||||
|
||||
vertOut.position = gl_in[vert].gl_Position;
|
||||
vertOut.normal = vertIn[vert].normal;
|
||||
vertOut.texCoord = vertIn[vert].texCoord;
|
||||
|
||||
gl_Layer = instanceID;
|
||||
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_ENV
|
||||
vertOut.envReflect = vertIn[vert].envReflect;
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_ENV
|
||||
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_NORMAL
|
||||
vertOut.tangentMatrix = vertIn[vert].tangentMatrix;
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_NORMAL
|
||||
@@ -223,6 +239,10 @@ out VertexOutput {
|
||||
vertOut.normal = vertIn[vert].normal;
|
||||
vertOut.texCoord = vertIn[vert].texCoord;
|
||||
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_ENV
|
||||
vertOut.envReflect = vertIn[vert].envReflect;
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_ENV
|
||||
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_NORMAL
|
||||
vertOut.tangentMatrix = vertIn[vert].tangentMatrix;
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_NORMAL
|
||||
|
||||
@@ -34,14 +34,15 @@ layout (std140) uniform modelData {
|
||||
mat4 textureMatrix;
|
||||
mat4 shadow_mv_matrix;
|
||||
mat4 shadow_proj_matrix[4];
|
||||
mat4 envMatrix;
|
||||
|
||||
vec4 color;
|
||||
|
||||
model_light lights[MAX_LIGHTS];
|
||||
|
||||
float outlineWidth;
|
||||
float fogNear;
|
||||
float fogDensity;
|
||||
float fogStart;
|
||||
float fogScale;
|
||||
int buffer_matrix_offset;
|
||||
|
||||
vec4 clip_equation;
|
||||
@@ -101,6 +102,10 @@ uniform samplerBuffer transform_tex;
|
||||
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_TRANSFORM
|
||||
|
||||
out VertexOutput {
|
||||
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_ENV
|
||||
vec3 envReflect;
|
||||
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_ENV
|
||||
|
||||
mat3 tangentMatrix;
|
||||
|
||||
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_FOG
|
||||
@@ -188,8 +193,14 @@ void main()
|
||||
vec3 b = cross(normal, t) * vertTangent.w;
|
||||
vertOut.tangentMatrix = mat3(t, b, normal);
|
||||
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_ENV
|
||||
// Environment mapping reflection vector.
|
||||
vec3 envReflect = reflect(normalize(position.xyz), normal);
|
||||
vertOut.envReflect = vec3(envMatrix * vec4(envReflect, 0.0));
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_ENV
|
||||
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_FOG
|
||||
vertOut.fogDist = gl_Position.z - fogNear;
|
||||
vertOut.fogDist = clamp((gl_Position.z - fogStart) * 0.75 * fogScale, 0.0, 1.0);
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_FOG
|
||||
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_TRANSFORM
|
||||
|
||||
@@ -14,21 +14,22 @@ SDR_FLAG(MODEL_SDR_FLAG_HDR , (1 << 2) , false)
|
||||
SDR_FLAG(MODEL_SDR_FLAG_DIFFUSE , (1 << 3) , false)
|
||||
SDR_FLAG(MODEL_SDR_FLAG_GLOW , (1 << 4) , false)
|
||||
SDR_FLAG(MODEL_SDR_FLAG_SPEC , (1 << 5) , false)
|
||||
SDR_FLAG(MODEL_SDR_FLAG_NORMAL , (1 << 6) , false)
|
||||
SDR_FLAG(MODEL_SDR_FLAG_AMBIENT , (1 << 7) , false)
|
||||
SDR_FLAG(MODEL_SDR_FLAG_MISC , (1 << 8) , false)
|
||||
SDR_FLAG(MODEL_SDR_FLAG_TEAMCOLOR , (1 << 9), false)
|
||||
SDR_FLAG(MODEL_SDR_FLAG_FOG , (1 << 10), false)
|
||||
SDR_FLAG(MODEL_SDR_FLAG_TRANSFORM , (1 << 11), false)
|
||||
SDR_FLAG(MODEL_SDR_FLAG_SHADOWS , (1 << 12), false)
|
||||
SDR_FLAG(MODEL_SDR_FLAG_THRUSTER , (1 << 13), false)
|
||||
SDR_FLAG(MODEL_SDR_FLAG_ALPHA_MULT , (1 << 14), false)
|
||||
SDR_FLAG(MODEL_SDR_FLAG_ENV , (1 << 6) , false)
|
||||
SDR_FLAG(MODEL_SDR_FLAG_NORMAL , (1 << 7) , false)
|
||||
SDR_FLAG(MODEL_SDR_FLAG_AMBIENT , (1 << 8) , false)
|
||||
SDR_FLAG(MODEL_SDR_FLAG_MISC , (1 << 9) , false)
|
||||
SDR_FLAG(MODEL_SDR_FLAG_TEAMCOLOR , (1 << 10), false)
|
||||
SDR_FLAG(MODEL_SDR_FLAG_FOG , (1 << 11), false)
|
||||
SDR_FLAG(MODEL_SDR_FLAG_TRANSFORM , (1 << 12), false)
|
||||
SDR_FLAG(MODEL_SDR_FLAG_SHADOWS , (1 << 13), false)
|
||||
SDR_FLAG(MODEL_SDR_FLAG_THRUSTER , (1 << 14), false)
|
||||
SDR_FLAG(MODEL_SDR_FLAG_ALPHA_MULT , (1 << 15), false)
|
||||
|
||||
#ifndef MODEL_SDR_FLAG_MODE_GLSL
|
||||
//The following ones are used ONLY as compile-time flags, but they still need to be defined here to ensure no conflict occurs
|
||||
//But since these are checked with ifdefs even for the large shader, they must never be available in GLSL mode
|
||||
|
||||
SDR_FLAG(MODEL_SDR_FLAG_SHADOW_MAP , (1 << 15), true)
|
||||
SDR_FLAG(MODEL_SDR_FLAG_THICK_OUTLINES, (1 << 16), true)
|
||||
SDR_FLAG(MODEL_SDR_FLAG_SHADOW_MAP , (1 << 16), true)
|
||||
SDR_FLAG(MODEL_SDR_FLAG_THICK_OUTLINES, (1 << 17), true)
|
||||
|
||||
#endif
|
||||
@@ -1,5 +1,3 @@
|
||||
#include "z-compress.sdr"
|
||||
|
||||
in vec4 fragTexCoord;
|
||||
out vec4 fragOut0;
|
||||
out vec4 fragOut1;
|
||||
@@ -34,7 +32,7 @@ float getMedianDist(ivec2 texel) {
|
||||
float dists[4];
|
||||
|
||||
for(int i = 0; i < 4; i++) {
|
||||
dists[i] = uncompress_depth_value(texelFetch(texPos, texel, i).z);
|
||||
dists[i] = texelFetch(texPos, texel, i).z;
|
||||
}
|
||||
|
||||
SORT(0, 2)
|
||||
@@ -53,7 +51,7 @@ float getMedianDist(ivec2 texel) {
|
||||
float dists[8];
|
||||
|
||||
for(int i = 0; i < 8; i++) {
|
||||
dists[i] = uncompress_depth_value(texelFetch(texPos, texel, i).z);
|
||||
dists[i] = texelFetch(texPos, texel, i).z;
|
||||
}
|
||||
|
||||
SORT(0, 4)
|
||||
@@ -84,7 +82,7 @@ float getMedianDist(ivec2 texel) {
|
||||
float dists[16];
|
||||
|
||||
for(int i = 0; i < 16; i++) {
|
||||
dists[i] = uncompress_depth_value(texelFetch(texPos, texel, i).z);
|
||||
dists[i] = texelFetch(texPos, texel, i).z;
|
||||
}
|
||||
|
||||
SORT(0, 1)
|
||||
@@ -147,7 +145,7 @@ float getMedianDist(ivec2 texel) {
|
||||
float getMedianDist(ivec2 texel) {
|
||||
float minDist = -1000000;
|
||||
for(int i = 0; i < samples; i++) {
|
||||
minDist = max(minDist, uncompress_depth_value(texelFetch(texPos, texel, i).z));
|
||||
minDist = max(minDist, texelFetch(texPos, texel, i).z);
|
||||
}
|
||||
return minDist;
|
||||
}
|
||||
@@ -175,7 +173,6 @@ void main()
|
||||
|
||||
for(int i = 0; i < samples; i++) {
|
||||
vec4 localPos = texelFetch(texPos, texel, i);
|
||||
localPos.z = uncompress_depth_value(localPos.z);
|
||||
//Calculate local weight from distance Voxel, but if the distance is 0 (i.e. no model at all), set weight to 1 to allow stuff like background emissive
|
||||
//However, if the median distance is 0, only deal with current texel if it's local distance is 0 as well
|
||||
float localWeight = max(step(-0.001, dist) * step(-0.001, localPos.z),
|
||||
@@ -192,11 +189,8 @@ void main()
|
||||
weight += localWeight;
|
||||
}
|
||||
|
||||
pos /= weight;
|
||||
pos.z = compress_depth_value(pos.z);
|
||||
|
||||
fragOut0 = color / weight;
|
||||
fragOut1 = pos;
|
||||
fragOut1 = pos / weight;
|
||||
fragOut2 = vec4(normalize(normal.xyz), normal.a / weight);
|
||||
fragOut3 = specular / weight;
|
||||
fragOut4 = emissive / weight;
|
||||
|
||||
@@ -18,14 +18,6 @@ layout (std140) uniform genericData {
|
||||
|
||||
vec3 tint;
|
||||
float dither;
|
||||
|
||||
// these are blank, valid slots for modders to create custom effects
|
||||
// that can be defined in post_processing.tbl and coded below
|
||||
vec3 custom_effect_vec3_a;
|
||||
float custom_effect_float_a;
|
||||
|
||||
vec3 custom_effect_vec3_b;
|
||||
float custom_effect_float_b;
|
||||
};
|
||||
|
||||
void main()
|
||||
|
||||
@@ -26,45 +26,48 @@ float sampleNoPCF(sampler2DArray shadow_map, float shadowDepth, int cascade, vec
|
||||
return computeShadowFactor(shadowDepth, sampleShadowMap(shadow_map, shadowUV[cascade].xy, vec2(0.0, 0.0), cascade, 1.0/1024.0), 0.05);
|
||||
}
|
||||
|
||||
float samplePoissonPCF(sampler2DArray shadow_map, float shadowDepth, int cascade, vec4 shadowUV[4], bool cockpit_shadow_bias)
|
||||
float samplePoissonPCF(sampler2DArray shadow_map, float shadowDepth, int cascade, vec4 shadowUV[4])
|
||||
{
|
||||
if(cascade > 3 || cascade < 0) return 1.0;
|
||||
|
||||
vec2 poissonDisc[16] = vec2[](
|
||||
vec2(-0.76275, -0.3432573),
|
||||
vec2(-0.5226235, -0.8277544),
|
||||
vec2(-0.3780261, 0.01528688),
|
||||
vec2(-0.7742821, 0.4245702),
|
||||
vec2(0.04196143, -0.02622231),
|
||||
vec2(-0.2974772, -0.4722782),
|
||||
vec2(-0.516093, 0.71495),
|
||||
vec2(-0.3257416, 0.3910343),
|
||||
vec2(0.2705966, 0.6670476),
|
||||
vec2(0.4918377, 0.1853267),
|
||||
vec2(0.4428544, -0.6251478),
|
||||
vec2(-0.09204347, 0.9267113),
|
||||
vec2(0.391505, -0.2558275),
|
||||
vec2(0.05605913, -0.7570801),
|
||||
vec2(0.81772, -0.02475523),
|
||||
vec2(0.6890262, 0.5191521)
|
||||
);
|
||||
|
||||
vec2 poissonDisc[16];
|
||||
poissonDisc[0] = vec2(-0.76275, -0.3432573);
|
||||
poissonDisc[1] = vec2(-0.5226235, -0.8277544);
|
||||
poissonDisc[2] = vec2(-0.3780261, 0.01528688);
|
||||
poissonDisc[3] = vec2(-0.7742821, 0.4245702);
|
||||
poissonDisc[4] = vec2(0.04196143, -0.02622231);
|
||||
poissonDisc[5] = vec2(-0.2974772, -0.4722782);
|
||||
poissonDisc[6] = vec2(-0.516093, 0.71495);
|
||||
poissonDisc[7] = vec2(-0.3257416, 0.3910343);
|
||||
poissonDisc[8] = vec2(0.2705966, 0.6670476);
|
||||
poissonDisc[9] = vec2(0.4918377, 0.1853267);
|
||||
poissonDisc[10] = vec2(0.4428544, -0.6251478);
|
||||
poissonDisc[11] = vec2(-0.09204347, 0.9267113);
|
||||
poissonDisc[12] = vec2(0.391505, -0.2558275);
|
||||
poissonDisc[13] = vec2(0.05605913, -0.7570801);
|
||||
poissonDisc[14] = vec2(0.81772, -0.02475523);
|
||||
poissonDisc[15] = vec2(0.6890262, 0.5191521);
|
||||
float maxUVOffset[4];
|
||||
maxUVOffset[0] = 1.0/300.0;
|
||||
maxUVOffset[1] = 1.0/250.0;
|
||||
maxUVOffset[2] = 1.0/200.0;
|
||||
maxUVOffset[3] = 1.0/200.0;
|
||||
|
||||
// default external shadows
|
||||
// bias is a bit larger to only pick up larger geometry
|
||||
// favors light over shadow to avoid flickering/spotty shadows
|
||||
// compute Chebyshev per-sample to avoid halos from moment-averaging at occluder edges
|
||||
float visibility = 0.0f;
|
||||
for (int i=0; i<16; i++) {
|
||||
vec2 shadow_sample = sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[i], cascade, maxUVOffset[cascade]);
|
||||
visibility += computeShadowFactor(shadowDepth, shadow_sample, cockpit_shadow_bias ? 0.01f : 0.1f);
|
||||
}
|
||||
return visibility * (1.0f/16.0f);
|
||||
vec2 sum = sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[0], cascade, maxUVOffset[cascade])*(1.0/16.0);
|
||||
sum += sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[1], cascade, maxUVOffset[cascade])*(1.0/16.0);
|
||||
sum += sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[2], cascade, maxUVOffset[cascade])*(1.0/16.0);
|
||||
sum += sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[3], cascade, maxUVOffset[cascade])*(1.0/16.0);
|
||||
sum += sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[4], cascade, maxUVOffset[cascade])*(1.0/16.0);
|
||||
sum += sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[5], cascade, maxUVOffset[cascade])*(1.0/16.0);
|
||||
sum += sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[6], cascade, maxUVOffset[cascade])*(1.0/16.0);
|
||||
sum += sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[7], cascade, maxUVOffset[cascade])*(1.0/16.0);
|
||||
sum += sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[8], cascade, maxUVOffset[cascade])*(1.0/16.0);
|
||||
sum += sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[9], cascade, maxUVOffset[cascade])*(1.0/16.0);
|
||||
sum += sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[10], cascade, maxUVOffset[cascade])*(1.0/16.0);
|
||||
sum += sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[11], cascade, maxUVOffset[cascade])*(1.0/16.0);
|
||||
sum += sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[12], cascade, maxUVOffset[cascade])*(1.0/16.0);
|
||||
sum += sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[13], cascade, maxUVOffset[cascade])*(1.0/16.0);
|
||||
sum += sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[14], cascade, maxUVOffset[cascade])*(1.0/16.0);
|
||||
sum += sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[15], cascade, maxUVOffset[cascade])*(1.0/16.0);
|
||||
return computeShadowFactor(shadowDepth, sum, 0.1);
|
||||
}
|
||||
|
||||
float getShadowValue(sampler2DArray shadow_map, float depth, float shadowDepth, vec4 shadowUV[4], float fardist,
|
||||
@@ -83,20 +86,10 @@ float getShadowValue(sampler2DArray shadow_map, float depth, float shadowDepth,
|
||||
cascade_start_dist[3] = middist;
|
||||
cascade_start_dist[4] = fardist;
|
||||
if(cascade > 3 || cascade < 0) return 1.0;
|
||||
|
||||
bool cockpit_shadow_bias;
|
||||
if (fardist < 50.0f) {
|
||||
// internal cockpit shadows
|
||||
cockpit_shadow_bias = true;
|
||||
} else {
|
||||
// default external shadows
|
||||
cockpit_shadow_bias = false;
|
||||
}
|
||||
|
||||
float dist_threshold = (cascade_start_dist[cascade+1] - cascade_start_dist[cascade])*0.2;
|
||||
if(cascade_start_dist[cascade+1] - dist_threshold > depth)
|
||||
return samplePoissonPCF(shadow_map, shadowDepth, cascade, shadowUV, cockpit_shadow_bias);
|
||||
return mix(samplePoissonPCF(shadow_map, shadowDepth, cascade, shadowUV, cockpit_shadow_bias), samplePoissonPCF(shadow_map, shadowDepth, cascade+1, shadowUV, cockpit_shadow_bias),
|
||||
return samplePoissonPCF(shadow_map, shadowDepth, cascade, shadowUV);
|
||||
return mix(samplePoissonPCF(shadow_map, shadowDepth, cascade, shadowUV), samplePoissonPCF(shadow_map, shadowDepth, cascade+1, shadowUV),
|
||||
smoothstep(cascade_start_dist[cascade+1] - dist_threshold, cascade_start_dist[cascade+1], depth));
|
||||
}
|
||||
|
||||
|
||||
@@ -100,6 +100,8 @@ void main()
|
||||
vec3 sampleposition = position / nebSize + 0.5;
|
||||
vec4 volume_sample = textureGrad(volume_tex, sampleposition, gradX, gradY);
|
||||
|
||||
float stepsize_current = min(max(stepsize, volume_sample.x * udfScale), mintMax - stept);
|
||||
|
||||
#ifdef DO_EDGE_SMOOTHING
|
||||
//Average 3D texel with texels on corner, in an attempt to reduce jagged edges.
|
||||
float stepcolor_alpha = volume_sample.a;
|
||||
@@ -119,8 +121,6 @@ void main()
|
||||
float stepcolor_alpha = volume_sample.a;
|
||||
#endif
|
||||
|
||||
float stepsize_current = min(max(stepsize, step(stepcolor_alpha, 0.01) * volume_sample.x * udfScale), mintMax - stept);
|
||||
|
||||
float stepalpha = -(pow(alphalim, 1.0 / (opacitydistance / stepsize_current)) - 1.0f) * stepcolor_alpha;
|
||||
//All the following computations are just required if we have a stepcoloralpha that is non-zero.
|
||||
if(stepcolor_alpha > 0.01)
|
||||
@@ -151,7 +151,7 @@ void main()
|
||||
//Emissive
|
||||
cumnebdist += stepcolor_alpha * stepsize_current;
|
||||
vec3 emissive_lod = textureLod(emissive, fragTexCoord.xy, clamp(cumnebdist * emissiveSpreadFactor, 0, float(textureQueryLevels(emissive) - 1))).rgb;
|
||||
vec3 stepcolor_emissive = clamp(emissive_lod.rgb * pow(alphalim, 1.0 / (opacitydistance / ((depth - stept) * emissiveFalloff + 0.01))) * emissiveIntensity, 0, 1);
|
||||
vec3 stepcolor_emissive = emissive_lod.rgb * pow(alphalim, 1.0 / (opacitydistance / ((depth - stept) * emissiveFalloff + 0.01))) * emissiveIntensity;
|
||||
|
||||
//Step finish
|
||||
vec3 stepcolor = clamp(stepcolor_diffuse + stepcolor_emissive, 0, 1);
|
||||
@@ -165,5 +165,7 @@ void main()
|
||||
break;
|
||||
}
|
||||
|
||||
fragOut0 = vec4(cumOMAlpha * color_in.rgb + ((1.0 - cumOMAlpha) * cumcolor), 1);
|
||||
cumcolor += cumOMAlpha * color_in.rgb;
|
||||
|
||||
fragOut0 = vec4(cumcolor, 1);
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
float compress_depth_value(float linear) {
|
||||
float linear_mult;
|
||||
float exponent_mult;
|
||||
float offset;
|
||||
|
||||
linear = max(-linear, 0.0);
|
||||
|
||||
if(linear < 10.0) {
|
||||
//Special handling for very close values. For smooth shadows at very close distances, equidistant steps get too inaccurate.
|
||||
//Scaling this down linearly will push more accuracy to closer distances. Due to the scaling, this does not lose accuracy
|
||||
//at any point over the worse of uncompressed / z-compress, but it does trade the gained accuracy from compression at 10m
|
||||
//distance for accuracy lost due to compression below 0.5m (roughly)
|
||||
return linear * 0.01;
|
||||
}
|
||||
else if (linear < 100.0) {
|
||||
linear_mult = 0.05550473078;
|
||||
exponent_mult = 0.08493173544;
|
||||
offset = 0.0;
|
||||
}
|
||||
else if (linear < 1570.0) {
|
||||
linear_mult = 11.53589613947;
|
||||
exponent_mult = 0.00793869919;
|
||||
offset = 0.0;
|
||||
}
|
||||
else if (linear < 3000.0) {
|
||||
linear_mult = -0.10000000000;
|
||||
exponent_mult = 0.00928910863;
|
||||
offset = 3000.0;
|
||||
}
|
||||
else if (linear < 10000.0) {
|
||||
linear_mult = -0.10000000000;
|
||||
exponent_mult = 0.00094912231;
|
||||
offset = 3000.0;
|
||||
}
|
||||
else if (linear < 100000.0) {
|
||||
linear_mult = -6.98947320727;
|
||||
exponent_mult = 0.00007382062;
|
||||
offset = 3000.0;
|
||||
}
|
||||
else {
|
||||
linear_mult = -1000.0;
|
||||
exponent_mult = log2(1000.0 / 65000.0) / (100000.0 - GLOBAL_FAR_Z);
|
||||
offset = 100000.0;
|
||||
}
|
||||
|
||||
return linear_mult * pow(2.0, (linear - offset) * exponent_mult);
|
||||
}
|
||||
|
||||
float uncompress_depth_value(float compressed) {
|
||||
float linear_mult;
|
||||
float exponent_mult;
|
||||
float offset;
|
||||
|
||||
if(compressed < -1000.0) {
|
||||
linear_mult = -1000.0;
|
||||
exponent_mult = log2(1000.0 / 65000.0) / (100000.0 - GLOBAL_FAR_Z);
|
||||
offset = 100000.0;
|
||||
}
|
||||
else if (compressed < -10.0) {
|
||||
linear_mult = -6.98947320727;
|
||||
exponent_mult = 0.00007382062;
|
||||
offset = 3000.0;
|
||||
}
|
||||
else if (compressed < -0.1) {
|
||||
linear_mult = -0.10000000000;
|
||||
exponent_mult = 0.00094912231;
|
||||
offset = 3000.0;
|
||||
}
|
||||
else if (compressed < 0.0) {
|
||||
linear_mult = -0.10000000000;
|
||||
exponent_mult = 0.00928910863;
|
||||
offset = 3000.0;
|
||||
}
|
||||
else if (compressed < 0.1) {
|
||||
return compressed * -100.0;
|
||||
}
|
||||
else if (compressed < 20.0) {
|
||||
linear_mult = 0.05550473078;
|
||||
exponent_mult = 0.08493173544;
|
||||
offset = 0.0;
|
||||
}
|
||||
else {
|
||||
linear_mult = 11.53589613947;
|
||||
exponent_mult = 0.00793869919;
|
||||
offset = 0.0;
|
||||
}
|
||||
|
||||
return -(log2(compressed / linear_mult) / exponent_mult + offset);
|
||||
}
|
||||
@@ -84,21 +84,3 @@ setmetatable(Globals, mt)
|
||||
Globals.nullVec = ba.createVector(0, 0, 0)
|
||||
Globals.zeroVec = Globals.nullVec
|
||||
Globals.identityOrient = ba.createOrientationFromVectors(ba.createVector(0, 0, 1), ba.createVector(0, 1, 0), ba.createVector(1, 0, 0))
|
||||
Globals.FSOObjectsTableMetatable = {
|
||||
__newindex = function(tbl, key, value)
|
||||
for k, v in pairs(tbl) do
|
||||
if k == key then
|
||||
rawset(tbl, k, value)
|
||||
return
|
||||
end
|
||||
end
|
||||
rawset(tbl, key, value)
|
||||
end,
|
||||
__index = function(tbl, key)
|
||||
for k, v in pairs(tbl) do
|
||||
if k == key then
|
||||
return v
|
||||
end
|
||||
end
|
||||
end
|
||||
}
|
||||
@@ -53,9 +53,8 @@ $AI:
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
$Name: Cargo
|
||||
$Targetable as unscanned: YES
|
||||
$Scannable by default: YES
|
||||
$Name: Cargo
|
||||
$Scannable: YES
|
||||
$Max Debris Speed: 200
|
||||
$FF Multiplier: 0.10
|
||||
$EMP Multiplier: 10.0
|
||||
@@ -111,9 +110,9 @@ $Fog:
|
||||
+Start dist: 10.0
|
||||
+Compl dist: 500.0
|
||||
$AI:
|
||||
+Valid goals: ( "fly to ship" "attack ship" "waypoints" "waypoints once" "depart" "attack subsys" "attack wing" "guard ship" "disable ship" "disable ship (tactical)" "disarm ship" "disarm ship (tactical)" "attack any" "attack ship class" "attack ship type" "ignore ship" "ignore ship (new)" "guard wing" "evade ship" "stay still" "play dead" "play dead (persistent)" "stay near ship" "keep safe dist" "form on wing")
|
||||
+Valid goals: ( "fly to ship" "attack ship" "waypoints" "waypoints once" "depart" "attack subsys" "attack wing" "guard ship" "disable ship" "disable ship (tactical)" "disarm ship" "disarm ship (tactical)" "attack any" "attack ship class" "ignore ship" "ignore ship (new)" "guard wing" "evade ship" "stay still" "play dead" "play dead (persistent)" "stay near ship" "keep safe dist" "form on wing")
|
||||
+Accept Player Orders: YES
|
||||
+Player Orders: ( "attack ship" "disable ship" "disable ship (tactical)" "disarm ship" "disarm ship (tactical)" "guard ship" "ignore ship" "ignore ship (new)" "form on wing" "cover me" "attack any" "attack ship class" "attack ship type" "depart" "disable subsys" )
|
||||
+Player Orders: ( "attack ship" "disable ship" "disable ship (tactical)" "disarm ship" "disarm ship (tactical)" "guard ship" "ignore ship" "ignore ship (new)" "form on wing" "cover me" "attack any" "attack ship class" "depart" "disable subsys" )
|
||||
+Auto attacks: YES
|
||||
+Actively Pursues: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Guards attack this: YES
|
||||
@@ -139,9 +138,9 @@ $Fog:
|
||||
+Start dist: 10.0
|
||||
+Compl dist: 500.0
|
||||
$AI:
|
||||
+Valid goals: ( "fly to ship" "attack ship" "waypoints" "waypoints once" "depart" "attack subsys" "attack wing" "guard ship" "disable ship" "disable ship (tactical)" "disarm ship" "disarm ship (tactical)" "attack any" "attack ship class" "attack ship type" "ignore ship" "ignore ship (new)" "guard wing" "evade ship" "stay still" "play dead" "play dead (persistent)" "stay near ship" "keep safe dist" "form on wing" )
|
||||
+Valid goals: ( "fly to ship" "attack ship" "waypoints" "waypoints once" "depart" "attack subsys" "attack wing" "guard ship" "disable ship" "disable ship (tactical)" "disarm ship" "disarm ship (tactical)" "attack any" "attack ship class" "ignore ship" "ignore ship (new)" "guard wing" "evade ship" "stay still" "play dead" "play dead (persistent)" "stay near ship" "keep safe dist" "form on wing" )
|
||||
+Accept Player Orders: YES
|
||||
+Player Orders: ( "attack ship" "disable ship" "disable ship (tactical)" "disarm ship" "disarm ship (tactical)" "guard ship" "ignore ship" "ignore ship (new)" "form on wing" "cover me" "attack any" "attack ship class" "attack ship type" "depart" "disable subsys" )
|
||||
+Player Orders: ( "attack ship" "disable ship" "disable ship (tactical)" "disarm ship" "disarm ship (tactical)" "guard ship" "ignore ship" "ignore ship (new)" "form on wing" "cover me" "attack any" "attack ship class" "depart" "disable subsys" )
|
||||
+Auto attacks: YES
|
||||
+Actively Pursues: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Guards attack this: YES
|
||||
@@ -157,8 +156,6 @@ $Praise Destruction: YES
|
||||
$On Hotkey List: YES
|
||||
$Target as Threat: YES
|
||||
$Show Attack Direction: YES
|
||||
$Targetable as unscanned: YES
|
||||
$Scannable by default: YES
|
||||
$Max Debris Speed: 150
|
||||
$FF Multiplier: 1.0
|
||||
$EMP Multiplier: 2.0
|
||||
@@ -189,6 +186,7 @@ $Praise Destruction: YES
|
||||
$On Hotkey List: YES
|
||||
$Target as Threat: YES
|
||||
$Show Attack Direction: YES
|
||||
$Scannable: YES
|
||||
$Max Debris Speed: 150
|
||||
$FF Multiplier: 1.0
|
||||
$EMP Multiplier: 1.75
|
||||
|
||||
Loaded 100 of 1581 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user