mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-07 22:56:30 -10:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
34bcb03ef8 |
No files matched your search
@@ -1,182 +0,0 @@
|
||||
version: 2
|
||||
|
||||
references:
|
||||
container_config: &container_config
|
||||
docker:
|
||||
- image: "debian:stretch"
|
||||
working_directory: /root/build
|
||||
|
||||
restore_repo: &restore_repo
|
||||
restore_cache:
|
||||
keys:
|
||||
- source-repo-{{ .Branch }}-{{ .Revision }}
|
||||
- source-repo-{{ .Branch }}
|
||||
- source-repo
|
||||
|
||||
cmake_configure: &cmake_configure
|
||||
run:
|
||||
name: Creating Build Files
|
||||
command: |
|
||||
mkdir build
|
||||
cd build
|
||||
|
||||
CXXFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas"
|
||||
CFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas"
|
||||
|
||||
if [[ "$CC" =~ ^clang.*$ ]]; then
|
||||
CXXFLAGS="$CXXFLAGS -stdlib=libc++"
|
||||
fi
|
||||
|
||||
eval $CC --version
|
||||
|
||||
export CXXFLAGS
|
||||
export CFLAGS
|
||||
CMAKE="cmake -G Ninja -DFSO_FATAL_WARNINGS=ON $CMAKE_OPTIONS"
|
||||
eval $CMAKE -DCMAKE_BUILD_TYPE=$CONFIGURATION -DFSO_BUILD_TESTS=ON -DFSO_BUILD_INCLUDED_LIBS=ON ..
|
||||
|
||||
compile: &compile
|
||||
run:
|
||||
name: Compiling Source code
|
||||
command: |
|
||||
cd build
|
||||
ninja -k 20 all
|
||||
|
||||
run_tests: &run_tests
|
||||
run:
|
||||
name: Run unit tests
|
||||
command: |
|
||||
./build/bin/unittests --gtest_shuffle
|
||||
|
||||
compile_steps: &compile_steps
|
||||
steps:
|
||||
- *restore_repo
|
||||
- *cmake_configure
|
||||
- *compile
|
||||
- *run_tests
|
||||
jobs:
|
||||
checkout_code:
|
||||
<<: *container_config
|
||||
steps:
|
||||
- run:
|
||||
name: Installing Git
|
||||
command: 'apt-get update && apt-get -yq install git'
|
||||
- *restore_repo
|
||||
- checkout
|
||||
- run:
|
||||
name: Updating submodules
|
||||
command: 'git submodule update --init --recursive'
|
||||
- save_cache:
|
||||
key: source-repo-{{ .Branch }}-{{ .Revision }}
|
||||
paths:
|
||||
- .
|
||||
|
||||
build_gcc_lowest_debug:
|
||||
docker:
|
||||
- image: asarium/fso_compile:gcc-lowest
|
||||
working_directory: /root/build
|
||||
environment:
|
||||
CC: gcc
|
||||
CXX: g++
|
||||
CONFIGURATION: Debug
|
||||
<<: *compile_steps
|
||||
|
||||
build_gcc_lowest_release:
|
||||
docker:
|
||||
- image: asarium/fso_compile:gcc-lowest
|
||||
working_directory: /root/build
|
||||
environment:
|
||||
CC: gcc
|
||||
CXX: g++
|
||||
CONFIGURATION: Release
|
||||
<<: *compile_steps
|
||||
|
||||
build_gcc_latest_debug:
|
||||
docker:
|
||||
- image: asarium/fso_compile:gcc-latest
|
||||
working_directory: /root/build
|
||||
environment:
|
||||
CC: gcc
|
||||
CXX: g++
|
||||
CONFIGURATION: Debug
|
||||
<<: *compile_steps
|
||||
|
||||
build_gcc_latest_release:
|
||||
docker:
|
||||
- image: asarium/fso_compile:gcc-latest
|
||||
working_directory: /root/build
|
||||
environment:
|
||||
CC: gcc
|
||||
CXX: g++
|
||||
CONFIGURATION: Release
|
||||
<<: *compile_steps
|
||||
|
||||
build_clang_latest_debug:
|
||||
docker:
|
||||
- image: asarium/fso_compile:clang-latest
|
||||
working_directory: /root/build
|
||||
environment:
|
||||
CC: clang-8
|
||||
CXX: clang++-8
|
||||
CONFIGURATION: Debug
|
||||
<<: *compile_steps
|
||||
|
||||
build_clang_latest_release:
|
||||
docker:
|
||||
- image: asarium/fso_compile:clang-latest
|
||||
working_directory: /root/build
|
||||
environment:
|
||||
CC: clang-8
|
||||
CXX: clang++-8
|
||||
CONFIGURATION: Release
|
||||
<<: *compile_steps
|
||||
|
||||
build_clang_lowest_debug:
|
||||
docker:
|
||||
- image: asarium/fso_compile:clang-lowest
|
||||
working_directory: /root/build
|
||||
environment:
|
||||
CC: clang
|
||||
CXX: clang++
|
||||
CONFIGURATION: Debug
|
||||
<<: *compile_steps
|
||||
|
||||
build_clang_lowest_release:
|
||||
docker:
|
||||
- image: asarium/fso_compile:clang-lowest
|
||||
working_directory: /root/build
|
||||
environment:
|
||||
CC: clang
|
||||
CXX: clang++
|
||||
CONFIGURATION: Release
|
||||
<<: *compile_steps
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
|
||||
build_test:
|
||||
jobs:
|
||||
- checkout_code
|
||||
- build_gcc_lowest_debug:
|
||||
requires:
|
||||
- checkout_code
|
||||
- build_gcc_lowest_release:
|
||||
requires:
|
||||
- checkout_code
|
||||
- build_gcc_latest_debug:
|
||||
requires:
|
||||
- checkout_code
|
||||
- build_gcc_latest_release:
|
||||
requires:
|
||||
- checkout_code
|
||||
- build_clang_latest_debug:
|
||||
requires:
|
||||
- checkout_code
|
||||
- build_clang_latest_release:
|
||||
requires:
|
||||
- checkout_code
|
||||
- build_clang_lowest_debug:
|
||||
requires:
|
||||
- checkout_code
|
||||
- build_clang_lowest_release:
|
||||
requires:
|
||||
- checkout_code
|
||||
-100
@@ -1,100 +0,0 @@
|
||||
---
|
||||
Language: Cpp
|
||||
# BasedOnStyle: LLVM
|
||||
AccessModifierOffset: -2
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveAssignments: true
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignEscapedNewlinesLeft: false
|
||||
AlignOperands: true
|
||||
AlignTrailingComments: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: true
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BraceWrapping:
|
||||
AfterClass: false
|
||||
AfterControlStatement: false
|
||||
AfterEnum: false
|
||||
AfterFunction: true
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
IndentBraces: false
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: Custom
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakStringLiterals: true
|
||||
ColumnLimit: 120
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
|
||||
IncludeBlocks: Regroup
|
||||
IncludeCategories:
|
||||
- Regex: '^(<.*\.(h|hh|hpp)>)$' # Includes of external libraries
|
||||
Priority: 4
|
||||
- Regex: '^(<.*>)$' # standard library includes (won't match deprecated C headers)
|
||||
Priority: 5
|
||||
- Regex: '^"[^/]*\.(h)"$' # Local includes
|
||||
Priority: 1
|
||||
- Regex: '^".*\.(h)"$' # standard engine includes
|
||||
Priority: 2
|
||||
- Regex: '.*' # Catch all in case something is unhandled above
|
||||
Priority: 3
|
||||
IncludeIsMainRegex: '$'
|
||||
IndentCaseLabels: false
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
ObjCBlockIndentWidth: 2
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PenaltyBreakBeforeFirstCallParameter: 19
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 60
|
||||
PointerAlignment: Left
|
||||
ReflowComments: true
|
||||
SortIncludes: true
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: false
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Cpp11
|
||||
TabWidth: 4
|
||||
UseTab: ForIndentation
|
||||
...
|
||||
|
||||
-24
@@ -1,24 +0,0 @@
|
||||
---
|
||||
Checks: "-*,\
|
||||
modernize-*,\
|
||||
-modernize-raw-string-literal,\
|
||||
-modernize-use-using,\
|
||||
-modernize-make-unique,\
|
||||
performance-*,\
|
||||
-performance-type-promotion-in-math-fn,\
|
||||
misc-*,\
|
||||
-misc-macro-parentheses,\
|
||||
-misc-misplaced-widening-cast,\
|
||||
-misc-static-assert,\
|
||||
-modernize-make-unique,\
|
||||
"
|
||||
WarningsAsErrors: ''
|
||||
HeaderFilterRegex: 'code/.*$|freespace2/.*$|qtfred/.*$|test/src/.*$|build/.*$'
|
||||
AnalyzeTemporaryDtors: false
|
||||
CheckOptions:
|
||||
- key: 'misc-assert-side-effect.AssertMacros'
|
||||
value: 'assert,Assert,Assertion'
|
||||
- key: 'modernize-use-emplace.ContainersWithPushBack'
|
||||
value: 'std::vector;std::deque;std::list;SCP_vector;SCP_deque;SCP_list'
|
||||
...
|
||||
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
|
||||
build:
|
||||
image: teaci/msys$$arch
|
||||
pull: true
|
||||
shell: mingw$$arch
|
||||
commands:
|
||||
- git submodule update --init --recursive
|
||||
- if [ $$arch = 32 ]; then target=i686; fi
|
||||
- if [ $$arch = 64 ]; then target=x86_64; fi
|
||||
- pacman -S --needed --noconfirm --noprogressbar mingw-w64-${target}-pkg-config mingw-w64-${target}-cmake
|
||||
- mkdir build && cd build
|
||||
- cmake -G"Unix Makefiles" -DCMAKE_BUILD_TYPE=$$CONFIGURATION -DFSO_USE_SPEECH=OFF -DFSO_USE_VOICEREC=OFF -DFSO_FATAL_WARNINGS=ON -DFSO_BUILD_FRED2=OFF ..
|
||||
- make -j$(nproc) all
|
||||
|
||||
matrix:
|
||||
arch:
|
||||
- 64
|
||||
- 32
|
||||
CONFIGURATION:
|
||||
- Debug
|
||||
- Release
|
||||
+3
-4
@@ -26,6 +26,9 @@
|
||||
*.unsuccessfulbuild
|
||||
ipch/
|
||||
[Oo]bj/
|
||||
[Bb]in
|
||||
[Dd]ebug*/
|
||||
[Rr]elease*/
|
||||
Ankh.NoLoad
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
@@ -253,7 +256,3 @@ CMakeSettings.json
|
||||
|
||||
# Weird files created by Linux
|
||||
.fuse_hidden*
|
||||
|
||||
# This gets ignored by one of the rules above for some reason...
|
||||
!/code/scripting/lua/LuaConvert.h
|
||||
!/code/debugconsole/
|
||||
@@ -1,6 +1,3 @@
|
||||
[submodule "cmake/external/rpavlik-cmake-modules"]
|
||||
path = cmake/external/rpavlik-cmake-modules
|
||||
url = https://github.com/asarium/cmake-modules.git
|
||||
[submodule "lib/libRocket"]
|
||||
path = lib/libRocket
|
||||
url = https://github.com/asarium/libRocket.git
|
||||
+109
-167
@@ -1,182 +1,124 @@
|
||||
language: bash
|
||||
language: generic
|
||||
sudo: required
|
||||
dist: trusty
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/cmake-3.8
|
||||
- $HOME/.ccache
|
||||
- $HOME/curl_cache
|
||||
directories:
|
||||
- $HOME/cmake
|
||||
addons:
|
||||
apt:
|
||||
packages: &global_deps
|
||||
- ninja-build
|
||||
- libopenal-dev
|
||||
- libreadline6-dev
|
||||
- libpng12-dev
|
||||
- libjpeg62-dev
|
||||
- liblua5.1-0-dev
|
||||
- libjansson-dev
|
||||
- libsdl2-dev
|
||||
- libfreetype6-dev
|
||||
- valgrind
|
||||
- qt57base
|
||||
coverity_scan:
|
||||
project:
|
||||
name: "scp-fs2open/fs2open.github.com"
|
||||
notification_email: [email protected]
|
||||
build_command: "ci/travis/script.sh"
|
||||
# must match TRAVIS_BRANCH check below
|
||||
branch_pattern: coverity_scan
|
||||
apt:
|
||||
packages: &global_deps
|
||||
- ninja-build
|
||||
- libopenal-dev
|
||||
- libreadline6-dev
|
||||
- libpng12-dev
|
||||
- libjpeg62-dev
|
||||
- liblua5.1-0-dev
|
||||
- libjansson-dev
|
||||
- libsdl2-dev
|
||||
- valgrind
|
||||
coverity_scan:
|
||||
project:
|
||||
name: "scp-fs2open/fs2open.github.com"
|
||||
notification_email: [email protected]
|
||||
build_command: "ci/travis/script.sh"
|
||||
# must match TRAVIS_BRANCH check below
|
||||
branch_pattern: coverity_scan
|
||||
env:
|
||||
global:
|
||||
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
|
||||
# via the "travis encrypt" command using the project repo's public key
|
||||
# also note that fork's don't get access to secure keys
|
||||
# you have to test using a branch in the main repo
|
||||
- secure: "C3wF967ZeliwwP1vC12EMIBOaC568n26Z/cPnwzn317ve59DWH3YSfPZVgvt08GzmaXITGGsJvPB+qxfGoKvQzYE4O1B73q81RpUe5pB3IhF+ThQ91VfQZIRJR5xEGJaLINUlHTTZGX5jxlkVO9wAcauVj/s3b8sQ3dvUZauPvk="
|
||||
# These declarations set INDIEGAMES_USER and INDIEGAMES_PASSWORD for uploading nightly builds to the indiegames server
|
||||
- secure: "lUuRu8XIi8MKNf1ebOfyC4iVEpPyASojJIDWXRo2bNqEF4ILAljXdkVeXeN6H5yKCHD52cxCNTtyePIG/o3p3QEuGSVud9bDS3D7LaQicLETGGrsw3l07U49gF2OKHXGopg0MzBbZUU9QmhoFTAe8t6PV9NDuEayYCheqvTqjZg="
|
||||
- secure: "E/DHLYcPK/hBUqxBYYlUqp5sjgvIqY5A0qRHyQ4bmjsB+WB/Xx71bGCSiF7hk6lTxar1ZI1i5RAXXh9AIvNVaYAIdEOlCP+q3gvwCYuc5naZEKmkxlUCf0oEL4O9Fye93A/3VkFHuBdC1TGPYYf69m4W5r4367wWO9dPRIdWpJA="
|
||||
# These declarations set FS2DOWNLOADS_USER and FS2DOWNLOADS_PASSWORD
|
||||
- secure: "h6GbMX2jLsW1bS9fCM9fthOSJ1nfQQIRWi6EUH2p8u4NFLD5Bfi/C8JhQPKHUzyo3wvKkSHl+PsW7bgr1oXLusRwAur/dtv2N3imqvtbfIz305b00hZlsvbcYmQmUzQFSAdOGShK57JJ5aKQKccaUBP25KqB7Q+JaqBRdaMBS54="
|
||||
- secure: "fUDAPAUUaaYZy8I4zU3SJ0JcK7aw4eb6eTdaEr7LyNyTMSfPgwY6P1MrbSQC0lJNQIUQ5ffjdxE5g7D7OYpoJF9L14ni4UY8t2QASt7kmpgcYihmjeuYy8FQXgmFG8CTxiWBPKTybZJ7voQcvIvRaNG7b2wM9PMfc5lRIondB6c="
|
||||
global:
|
||||
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
|
||||
# via the "travis encrypt" command using the project repo's public key
|
||||
# also note that fork's don't get access to secure keys
|
||||
# you have to test using a branch in the main repo
|
||||
- secure: "C3wF967ZeliwwP1vC12EMIBOaC568n26Z/cPnwzn317ve59DWH3YSfPZVgvt08GzmaXITGGsJvPB+qxfGoKvQzYE4O1B73q81RpUe5pB3IhF+ThQ91VfQZIRJR5xEGJaLINUlHTTZGX5jxlkVO9wAcauVj/s3b8sQ3dvUZauPvk="
|
||||
# These declarations set INDIEGAMES_USER and INDIEGAMES_PASSWORD for uploading nightly builds to the indiegames server
|
||||
- secure: "lUuRu8XIi8MKNf1ebOfyC4iVEpPyASojJIDWXRo2bNqEF4ILAljXdkVeXeN6H5yKCHD52cxCNTtyePIG/o3p3QEuGSVud9bDS3D7LaQicLETGGrsw3l07U49gF2OKHXGopg0MzBbZUU9QmhoFTAe8t6PV9NDuEayYCheqvTqjZg="
|
||||
- secure: "E/DHLYcPK/hBUqxBYYlUqp5sjgvIqY5A0qRHyQ4bmjsB+WB/Xx71bGCSiF7hk6lTxar1ZI1i5RAXXh9AIvNVaYAIdEOlCP+q3gvwCYuc5naZEKmkxlUCf0oEL4O9Fye93A/3VkFHuBdC1TGPYYf69m4W5r4367wWO9dPRIdWpJA="
|
||||
# These declarations set FS2DOWNLOADS_USER and FS2DOWNLOADS_PASSWORD
|
||||
- secure: "h6GbMX2jLsW1bS9fCM9fthOSJ1nfQQIRWi6EUH2p8u4NFLD5Bfi/C8JhQPKHUzyo3wvKkSHl+PsW7bgr1oXLusRwAur/dtv2N3imqvtbfIz305b00hZlsvbcYmQmUzQFSAdOGShK57JJ5aKQKccaUBP25KqB7Q+JaqBRdaMBS54="
|
||||
- secure: "fUDAPAUUaaYZy8I4zU3SJ0JcK7aw4eb6eTdaEr7LyNyTMSfPgwY6P1MrbSQC0lJNQIUQ5ffjdxE5g7D7OYpoJF9L14ni4UY8t2QASt7kmpgcYihmjeuYy8FQXgmFG8CTxiWBPKTybZJ7voQcvIvRaNG7b2wM9PMfc5lRIondB6c="
|
||||
deploy:
|
||||
- provider: releases
|
||||
api_key:
|
||||
secure: "Wdt4Ccefo7a0ZDjEJQJgpghh7n72FtNJuKSAPUvoz4gtEX6Ct9J8yJI1t9V3jE3CTbbLJ21/Q6eZRDfT7UfNJe5DdepoJsP9DeFhKMWqQCq+AChqQWlm0KeZAffJoJreL8vXYhnRYcLT9ceZHEH6AqwN9TPV+xJziGPISAkYNZ8="
|
||||
skip_cleanup: true
|
||||
file_glob: true
|
||||
file: "/tmp/builds/*"
|
||||
on:
|
||||
condition: '"$RELEASE_BUILD" == true'
|
||||
tags: true
|
||||
- provider: releases
|
||||
api_key:
|
||||
secure: "Wdt4Ccefo7a0ZDjEJQJgpghh7n72FtNJuKSAPUvoz4gtEX6Ct9J8yJI1t9V3jE3CTbbLJ21/Q6eZRDfT7UfNJe5DdepoJsP9DeFhKMWqQCq+AChqQWlm0KeZAffJoJreL8vXYhnRYcLT9ceZHEH6AqwN9TPV+xJziGPISAkYNZ8="
|
||||
skip_cleanup: true
|
||||
file_glob: true
|
||||
file: "/tmp/builds/*"
|
||||
on:
|
||||
condition: '"$RELEASE_BUILD" == true'
|
||||
tags: true
|
||||
|
||||
- provider: script
|
||||
script: bash ci/travis/ftp_deploy.sh
|
||||
on:
|
||||
condition: '"$NIGHTLY_BUILD" == true'
|
||||
tags: true
|
||||
- provider: script
|
||||
script: bash ci/travis/ftp_deploy.sh
|
||||
on:
|
||||
condition: '"$NIGHTLY_BUILD" == true'
|
||||
tags: true
|
||||
|
||||
- provider: script
|
||||
skip_cleanup: true
|
||||
script: bash ci/travis/ftp_deploy.sh
|
||||
on:
|
||||
condition: $TEST_BUILD = true
|
||||
all_branches: true
|
||||
- provider: script
|
||||
skip_cleanup: true
|
||||
script: bash ci/travis/ftp_deploy.sh
|
||||
on:
|
||||
condition: $TEST_BUILD = true
|
||||
all_branches: true
|
||||
|
||||
matrix:
|
||||
include:
|
||||
# note that gcc Debug MUST be 1st for Coverity
|
||||
- os: linux
|
||||
env: CONFIGURATION="Debug" CC=gcc-5 CXX=g++-5
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- sourceline: 'ppa:beineri/opt-qt571-trusty'
|
||||
packages:
|
||||
- *global_deps
|
||||
- g++-5
|
||||
- os: linux
|
||||
env: CONFIGURATION="Debug" CC=gcc-8 CXX=g++-8
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- sourceline: 'ppa:beineri/opt-qt571-trusty'
|
||||
packages:
|
||||
- g++-8
|
||||
- *global_deps
|
||||
- os: linux
|
||||
env: CONFIGURATION="Debug" CC=clang-4.0 CXX=clang++-4.0 CMAKE_OPTIONS="-DCMAKE_EXPORT_COMPILE_COMMANDS=ON"
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-trusty-4.0
|
||||
- sourceline: 'ppa:beineri/opt-qt571-trusty'
|
||||
packages:
|
||||
- *global_deps
|
||||
- clang-4.0
|
||||
- clang-tidy-4.0
|
||||
- libc++-dev
|
||||
script:
|
||||
- ./ci/travis/script.sh
|
||||
- ./ci/travis/clang_tidy.sh
|
||||
- os: osx
|
||||
env: CONFIGURATION="Debug"
|
||||
|
||||
- os: windows
|
||||
env: CONFIGURATION="Debug" CMAKE_TOOLSET=v141_xp CMAKE_GENERATOR="Visual Studio 15 2017"
|
||||
- os: windows
|
||||
env: CONFIGURATION="Debug" CMAKE_TOOLSET="" CMAKE_GENERATOR="Ninja"
|
||||
|
||||
- os: linux
|
||||
env: CONFIGURATION="Release" CC=gcc-5 CXX=g++-5
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- sourceline: 'ppa:beineri/opt-qt571-trusty'
|
||||
packages:
|
||||
- *global_deps
|
||||
- g++-5
|
||||
- os: linux
|
||||
env: CONFIGURATION="Release" CC=gcc-8 CXX=g++-8
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- sourceline: 'ppa:beineri/opt-qt571-trusty'
|
||||
packages:
|
||||
- g++-8
|
||||
- *global_deps
|
||||
- os: linux
|
||||
env: CONFIGURATION="Release" CC=clang-4.0 CXX=clang++-4.0
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-trusty-4.0
|
||||
- sourceline: 'ppa:beineri/opt-qt571-trusty'
|
||||
packages:
|
||||
- *global_deps
|
||||
- clang-4.0
|
||||
- libc++-dev
|
||||
- os: osx
|
||||
env: CONFIGURATION="Release"
|
||||
|
||||
- os: windows
|
||||
env: CONFIGURATION="Release" CMAKE_TOOLSET=v141_xp CMAKE_GENERATOR="Visual Studio 15 2017"
|
||||
- os: windows
|
||||
env: CONFIGURATION="Release" CMAKE_TOOLSET="" CMAKE_GENERATOR="Ninja"
|
||||
# As long as Windows is still experimental on Travis CI, allow failures
|
||||
allow_failures:
|
||||
- os: windows
|
||||
env: CONFIGURATION="Debug" CMAKE_TOOLSET=v141_xp CMAKE_GENERATOR="Visual Studio 15 2017"
|
||||
- os: windows
|
||||
env: CONFIGURATION="Debug" CMAKE_TOOLSET="" CMAKE_GENERATOR="Ninja"
|
||||
- os: windows
|
||||
env: CONFIGURATION="Release" CMAKE_TOOLSET=v141_xp CMAKE_GENERATOR="Visual Studio 15 2017"
|
||||
- os: windows
|
||||
env: CONFIGURATION="Release" CMAKE_TOOLSET="" CMAKE_GENERATOR="Ninja"
|
||||
fast_finish: true
|
||||
include:
|
||||
# note that gcc Debug MUST be 1st for Coverity
|
||||
- os: linux
|
||||
env: CONFIGURATION="Debug" CC=gcc-5 CXX=g++-5
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-5
|
||||
- *global_deps
|
||||
- os: linux
|
||||
env: CONFIGURATION="Debug" CC=clang-3.6 CXX=clang++-3.6
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- llvm-toolchain-precise
|
||||
packages:
|
||||
- clang-3.6
|
||||
- libc++-dev
|
||||
- *global_deps
|
||||
- os: osx
|
||||
env: CONFIGURATION="Debug"
|
||||
|
||||
- os: linux
|
||||
env: CONFIGURATION="Release" CC=gcc-5 CXX=g++-5
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-5
|
||||
- *global_deps
|
||||
- os: linux
|
||||
env: CONFIGURATION="Release" CC=clang-3.6 CXX=clang++-3.6
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- llvm-toolchain-precise
|
||||
packages:
|
||||
- clang-3.6
|
||||
- libc++-dev
|
||||
- *global_deps
|
||||
- os: osx
|
||||
env: CONFIGURATION="Release"
|
||||
before_install:
|
||||
# ugly hack; if running a coverity scan abort all except the 1st build
|
||||
# see note re gcc compiler above needing to be 1st
|
||||
# also note that branch_pattern & the TRAVIS_BRANCH check must match
|
||||
# unfortunately COVERITY_SCAN_BRANCH isn't defined until later in the
|
||||
# build process
|
||||
- if ([[ "${TRAVIS_JOB_NUMBER##*.}" != "1" ]] && [[ "${TRAVIS_BRANCH}" == "coverity_scan" ]]); then false ; fi
|
||||
- source "./ci/travis/check_release.sh"
|
||||
- "./ci/travis/before_install.sh"
|
||||
# ugly hack; if running a coverity scan abort all except the 1st build
|
||||
# see note re gcc compiler above needing to be 1st
|
||||
# also note that branch_pattern & the TRAVIS_BRANCH check must match
|
||||
# unfortunately COVERITY_SCAN_BRANCH isn't defined until later in the
|
||||
# build process
|
||||
- if ([[ "${TRAVIS_JOB_NUMBER##*.}" != "1" ]] && [[ "${TRAVIS_BRANCH}" == "coverity_scan" ]]); then false ; fi
|
||||
- source "./ci/travis/check_release.sh"
|
||||
- "./ci/travis/before_install.sh"
|
||||
install:
|
||||
- if [ "$TRAVIS_OS_NAME" = "windows" ]; then export PATH="/c/Program Files/CMake/bin":$PATH; fi
|
||||
- "./ci/travis/install.sh"
|
||||
- export PATH=$HOME/cmake-3.6/bin:$PATH
|
||||
- "./ci/travis/install.sh"
|
||||
- export PATH=$HOME/cmake/bin:$PATH
|
||||
before_script:
|
||||
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then QT_ENV_SCRIPT=$(find /opt -name 'qt*-env.sh'); source $QT_ENV_SCRIPT; fi
|
||||
- "./ci/travis/before_script.sh"
|
||||
- "./ci/travis/before_script.sh"
|
||||
script:
|
||||
- if [ "$BUILD_DEPLOYMENT" = true ] ; then ./ci/travis/release.sh ; else ./ci/travis/script.sh ; fi
|
||||
- if [ "$BUILD_DEPLOYMENT" = true ] ; then ./ci/travis/release.sh ; else ./ci/travis/script.sh ; fi
|
||||
+7
-19
@@ -40,14 +40,6 @@ set(CMAKE_CONFIGURATION_TYPES Debug Release FastDebug CACHE STRING "Available co
|
||||
|
||||
PROJECT(FS2_Open)
|
||||
|
||||
find_program(CCACHE_PROGRAM ccache)
|
||||
# Currently only GCC support ccache properly without generating additional warnings
|
||||
if(CCACHE_PROGRAM AND "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
message(STATUS "Using ccache for compilation: ${CCACHE_PROGRAM}")
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_PROGRAM}")
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK "${CCACHE_PROGRAM}")
|
||||
endif()
|
||||
|
||||
IF(CMAKE_CROSSCOMPILING)
|
||||
SET(IMPORT_EXE_DIR "IMPORT_EXE_DIR-NOTFOUND" CACHE FILEPATH "Required for a cross compiling build, point to binary directory of a cmake build for the real OS")
|
||||
INCLUDE(${IMPORT_EXE_DIR}/ImportExecutables.cmake)
|
||||
@@ -84,6 +76,7 @@ IF (WIN32)
|
||||
OPTION(FSO_BUILD_FRED2 "Build FRED2 binary" ON)
|
||||
elseif(UNIX)
|
||||
option(FSO_BUILD_APPIMAGE "Build an AppImage package" OFF)
|
||||
set(APPIMAGE_ASSISTANT "" CACHE STRING "The root directory of an AppImage clone.")
|
||||
ENDIF(WIN32)
|
||||
|
||||
OPTION(FSO_BUILD_TOOLS "Build tools related to FSO" OFF)
|
||||
@@ -92,7 +85,7 @@ OPTION(FSO_BUILD_TESTS "Build unit tests" OFF)
|
||||
|
||||
OPTION(FSO_DEVELOPMENT_MODE "Generate binaries in development mode, only use if you know what you're doing!" OFF)
|
||||
|
||||
OPTION(FSO_BUILD_QTFRED "Build qtFRED2 binary" OFF)
|
||||
OPTION(FSO_BUILD_WXFRED2 "Build wxFRED2 binary" OFF)
|
||||
|
||||
IF(WIN32 OR APPLE)
|
||||
# On windows and mac the default should be to always build the included libraries
|
||||
@@ -115,8 +108,6 @@ SET(FSO_RUN_ARGUMENTS "" CACHE STRING "Additional arguments passed to a generate
|
||||
|
||||
option(FSO_INSTALL_DEBUG_FILES "Install some debug files (currently only PDB files on windows)" OFF)
|
||||
|
||||
option(ENABLE_COTIRE "Enable cotire for faster compilation. Enabled by default." ON)
|
||||
|
||||
MARK_AS_ADVANCED(FORCE FSO_CMAKE_DEBUG)
|
||||
MARK_AS_ADVANCED(FORCE FSO_BUILD_INCLUDED_LIBS)
|
||||
MARK_AS_ADVANCED(FORCE FSO_USE_OPENALSOFT)
|
||||
@@ -124,7 +115,6 @@ MARK_AS_ADVANCED(FORCE FSO_USE_LUAJIT)
|
||||
MARK_AS_ADVANCED(FORCE FSO_DEVELOPMENT_MODE)
|
||||
MARK_AS_ADVANCED(FORCE FSO_FATAL_WARNINGS)
|
||||
mark_as_advanced(FORCE FSO_INSTALL_DEBUG_FILES)
|
||||
mark_as_advanced(FORCE ENABLE_COTIRE)
|
||||
|
||||
# Include cotire file from https://github.com/sakra/cotire/
|
||||
include(cotire)
|
||||
@@ -144,8 +134,6 @@ if(FSO_BUILD_APPIMAGE)
|
||||
include(appimage)
|
||||
endif()
|
||||
|
||||
include(clang-tidy)
|
||||
|
||||
# This includes source code for some tools, either used in the build or also for something else
|
||||
ADD_SUBDIRECTORY(tools)
|
||||
|
||||
@@ -159,9 +147,9 @@ IF(FSO_BUILD_FRED2)
|
||||
ADD_SUBDIRECTORY(fred2)
|
||||
ENDIF(FSO_BUILD_FRED2)
|
||||
|
||||
IF(FSO_BUILD_QTFRED)
|
||||
ADD_SUBDIRECTORY(qtfred)
|
||||
ENDIF()
|
||||
IF(FSO_BUILD_WXFRED2)
|
||||
ADD_SUBDIRECTORY(wxfred2)
|
||||
ENDIF(FSO_BUILD_WXFRED2)
|
||||
|
||||
if(FSO_BUILD_TESTS)
|
||||
add_subdirectory(test)
|
||||
@@ -188,12 +176,12 @@ include(doxygen)
|
||||
|
||||
# Print used options to log
|
||||
IF (WIN32)
|
||||
message(STATUS "Building FRED2: ${FSO_BUILD_FRED2}")
|
||||
message(STATUS "Using text to speech: ${FSO_USE_SPEECH}")
|
||||
message(STATUS "Using voice recogition: ${FSO_USE_VOICEREC}")
|
||||
message(STATUS "Building FRED2: ${FSO_BUILD_FRED2}")
|
||||
elseif(UNIX)
|
||||
message(STATUS "Building AppImage: ${FSO_BUILD_APPIMAGE}")
|
||||
ENDIF()
|
||||
message(STATUS "Building FSO tools: ${FSO_BUILD_TOOLS}")
|
||||
message(STATUS "Building qtFRED: ${FSO_BUILD_QTFRED}")
|
||||
message(STATUS "Building wxFRED: ${FSO_BUILD_WXFRED2}")
|
||||
message(STATUS "Fatal warnings: ${FSO_FATAL_WARNINGS}")
|
||||
+2
-5
@@ -1,5 +1,4 @@
|
||||
version: 1.0.0.{build}
|
||||
image: Visual Studio 2015
|
||||
configuration:
|
||||
- Debug
|
||||
- Release
|
||||
@@ -7,13 +6,11 @@ clone_depth: 10
|
||||
environment:
|
||||
matrix:
|
||||
- BuildID: 0
|
||||
CMAKE_GENERATOR: Visual Studio 14 2015
|
||||
PlatformToolset: v140_xp
|
||||
QT_DIR: C:\Qt\5.9\msvc2015
|
||||
CMAKE_GENERATOR: Visual Studio 12 2013
|
||||
PlatformToolset: v120_xp
|
||||
- BuildID: 1
|
||||
CMAKE_GENERATOR: Visual Studio 14 2015 Win64
|
||||
PlatformToolset: v140_xp
|
||||
QT_DIR: C:\Qt\5.9\msvc2015_64
|
||||
before_build:
|
||||
- git submodule update --init --recursive
|
||||
build_script:
|
||||
|
||||
@@ -4,7 +4,6 @@ class BuildConfig {
|
||||
[string]$PackageType
|
||||
[string]$Toolset
|
||||
[string]$SimdType
|
||||
[string]$QtDir
|
||||
[Bool]$SourcePackage
|
||||
}
|
||||
|
||||
@@ -14,7 +13,6 @@ $NightlyConfigurations = @(
|
||||
PackageType="Win64";
|
||||
Toolset="v140_xp";
|
||||
SimdType="SSE2";
|
||||
QtDir="C:\Qt\5.9\msvc2015_64";
|
||||
SourcePackage=$false;
|
||||
},
|
||||
[BuildConfig]@{
|
||||
@@ -22,7 +20,6 @@ $NightlyConfigurations = @(
|
||||
PackageType="Win32";
|
||||
Toolset="v140_xp";
|
||||
SimdType="SSE2";
|
||||
QtDir="C:\Qt\5.9\msvc2015";
|
||||
SourcePackage=$false;
|
||||
}
|
||||
)
|
||||
@@ -32,7 +29,6 @@ $ReleaseConfigurations = @(
|
||||
PackageType="Win32";
|
||||
Toolset="v140_xp";
|
||||
SimdType="SSE2";
|
||||
QtDir="C:\Qt\5.9\msvc2015";
|
||||
SourcePackage=$true;
|
||||
}
|
||||
[BuildConfig]@{
|
||||
@@ -40,7 +36,6 @@ $ReleaseConfigurations = @(
|
||||
PackageType="Win32-AVX";
|
||||
Toolset="v140_xp";
|
||||
SimdType="AVX";
|
||||
QtDir="C:\Qt\5.9\msvc2015";
|
||||
SourcePackage=$false;
|
||||
}
|
||||
[BuildConfig]@{
|
||||
@@ -48,7 +43,6 @@ $ReleaseConfigurations = @(
|
||||
PackageType="Win64";
|
||||
Toolset="v140_xp";
|
||||
SimdType="SSE2";
|
||||
QtDir="C:\Qt\5.9\msvc2015_64";
|
||||
SourcePackage=$false;
|
||||
}
|
||||
[BuildConfig]@{
|
||||
@@ -56,7 +50,6 @@ $ReleaseConfigurations = @(
|
||||
PackageType="Win64-AVX";
|
||||
Toolset="v140_xp";
|
||||
SimdType="AVX";
|
||||
QtDir="C:\Qt\5.9\msvc2015_64";
|
||||
SourcePackage=$false;
|
||||
}
|
||||
)
|
||||
@@ -133,7 +126,6 @@ if ($DeployBuild) {
|
||||
|
||||
cmake -DCMAKE_INSTALL_PREFIX="$env:APPVEYOR_BUILD_FOLDER/../install" -DFSO_USE_SPEECH="ON" `
|
||||
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS="$($buildConfig.SimdType)" `
|
||||
-DQT5_INSTALL_ROOT="$($buildConfig.QtDir)" -DFSO_BUILD_QTFRED=ON `
|
||||
-G "$($buildConfig.Generator)" -T "$($buildConfig.Toolset)" ..
|
||||
|
||||
$Configs = @("Release", "FastDebug")
|
||||
@@ -149,7 +141,6 @@ if ($DeployBuild) {
|
||||
Push-AppveyorArtifact "$($PackageName)-builds-$($buildConfig.PackageType).zip"
|
||||
} else {
|
||||
cmake -DFSO_USE_SPEECH="ON" -DFSO_FATAL_WARNINGS="ON" -DFSO_USE_VOICEREC="ON" -DFSO_BUILD_TESTS="ON" -DMSVC_SIMD_INSTRUCTIONS=SSE2 `
|
||||
-DFSO_BUILD_QTFRED=ON -DQT5_INSTALL_ROOT="$env:QT_DIR" -DFSO_BUILD_FRED2="ON" `
|
||||
-G "$Env:CMAKE_GENERATOR" -T "$Env:PlatformToolset" ..
|
||||
|
||||
cmake --build . --config "$Env:CONFIGURATION" -- /verbosity:minimal
|
||||
|
||||
@@ -8,7 +8,4 @@ if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
# Nothing to do here
|
||||
:
|
||||
elif [ "$TRAVIS_OS_NAME" = "windows" ]; then
|
||||
# Nothing to do here
|
||||
:
|
||||
fi
|
||||
+10
-21
@@ -2,19 +2,15 @@
|
||||
|
||||
set -ex
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
mkdir -p /tmp/builds
|
||||
if [ "$RELEASE_BUILD" = true ]; then
|
||||
# Package the source code in release builds
|
||||
PARENT_DIR="$(basename "$PWD")"
|
||||
(cd .. && tar -czvf /tmp/builds/$PACKAGE_NAME-source-Unix.tar.gz --exclude-vcs "$PARENT_DIR")
|
||||
fi
|
||||
fi
|
||||
|
||||
mkdir -p build
|
||||
cd build
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
if [ "$RELEASE_BUILD" = true ]; then
|
||||
PARENT_DIR="$(basename $PWD)"
|
||||
(cd .. && tar -czvf /tmp/builds/$PACKAGE_NAME-source-Unix.tar.gz --exclude-vcs "$PARENT_DIR")
|
||||
fi
|
||||
|
||||
CXXFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas"
|
||||
CFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas"
|
||||
|
||||
@@ -24,31 +20,24 @@ if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
|
||||
export CXXFLAGS
|
||||
export CFLAGS
|
||||
CMAKE="cmake -G Ninja -DFSO_FATAL_WARNINGS=ON $CMAKE_OPTIONS"
|
||||
CMAKE="cmake -G Ninja -DFSO_FATAL_WARNINGS=ON"
|
||||
if [ "$BUILD_DEPLOYMENT" = true ]; then
|
||||
for config in $BUILD_CONFIGS
|
||||
do
|
||||
mkdir -p $config
|
||||
cd $config
|
||||
eval $CMAKE -DFSO_INSTALL_DEBUG_FILES=ON -DCMAKE_BUILD_TYPE=$config -DCMAKE_INSTALL_PREFIX="/tmp/release/$config" \
|
||||
-DFSO_BUILD_APPIMAGE=ON -DFSO_BUILD_INCLUDED_LIBS=ON -DFFMPEG_USE_PRECOMPILED=ON -DFSO_BUILD_QTFRED=OFF ../..
|
||||
-DFSO_BUILD_APPIMAGE=ON -DAPPIMAGE_ASSISTANT="$HOME/AppImageAssistant" \
|
||||
-DFSO_BUILD_INCLUDED_LIBS=ON -DFFMPEG_USE_PRECOMPILED=ON ../..
|
||||
cd ..
|
||||
done
|
||||
else
|
||||
eval $CMAKE -DCMAKE_BUILD_TYPE=$CONFIGURATION -DFSO_BUILD_TESTS=ON -DFSO_BUILD_INCLUDED_LIBS=ON -DFSO_BUILD_QTFRED=ON ..
|
||||
eval $CMAKE -DCMAKE_BUILD_TYPE=$CONFIGURATION -DFSO_BUILD_TESTS=ON -DFSO_BUILD_INCLUDED_LIBS=ON ..
|
||||
fi
|
||||
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
if [ "$BUILD_DEPLOYMENT" = true ]; then
|
||||
cmake -G "Xcode" -DFSO_FATAL_WARNINGS=ON -DFSO_INSTALL_DEBUG_FILES=ON -DCMAKE_INSTALL_PREFIX="/tmp/release" ..
|
||||
else
|
||||
cmake -G "Xcode" $CMAKE_OPTIONS ..
|
||||
fi
|
||||
elif [ "$TRAVIS_OS_NAME" = "windows" ]; then
|
||||
if [ "$CMAKE_GENERATOR" = "Ninja" ]; then
|
||||
cmake -DFSO_USE_SPEECH="OFF" -DFSO_FATAL_WARNINGS="ON" -DFSO_USE_VOICEREC="OFF" -DFSO_BUILD_TESTS="ON" \
|
||||
-DFSO_BUILD_FRED2="OFF" -G "$CMAKE_GENERATOR" ..
|
||||
else
|
||||
cmake -DFSO_USE_SPEECH="ON" -DFSO_FATAL_WARNINGS="ON" -DFSO_USE_VOICEREC="OFF" -DFSO_BUILD_TESTS="ON" \
|
||||
-DMSVC_SIMD_INSTRUCTIONS=SSE2 -DFSO_BUILD_FRED2="ON" -G "$CMAKE_GENERATOR" -T "$CMAKE_TOOLSET" ..
|
||||
cmake -G "Xcode" ..
|
||||
fi
|
||||
fi
|
||||
@@ -49,7 +49,7 @@ if ([ "$RELEASE_BUILD" = true ] || [ "$NIGHTLY_BUILD" = true ] || [ "$TEST_BUILD
|
||||
fi
|
||||
|
||||
if [ "$BUILD_DEPLOYMENT" = true ]; then
|
||||
if ([ "$TRAVIS_OS_NAME" = "linux" ] && (! [[ "$CC" =~ ^gcc-5.*$ ]])); then
|
||||
if ([ "$TRAVIS_OS_NAME" = "linux" ] && (! [[ "$CC" =~ ^gcc.*$ ]])); then
|
||||
echo "Skipping non-release compiler";
|
||||
exit 0;
|
||||
fi
|
||||
@@ -58,11 +58,6 @@ if [ "$BUILD_DEPLOYMENT" = true ]; then
|
||||
echo "Skipping non-release configuration";
|
||||
exit 0;
|
||||
fi
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" = "windows" ]; then
|
||||
echo "Skipping non-release platform"
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
export RELEASE_BUILD
|
||||
|
||||
@@ -1,141 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
#===- clang-tidy-diff.py - ClangTidy Diff Checker ------------*- python -*--===#
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
#===------------------------------------------------------------------------===#
|
||||
|
||||
r"""
|
||||
ClangTidy Diff Checker
|
||||
======================
|
||||
|
||||
This script reads input from a unified diff, runs clang-tidy on all changed
|
||||
files and outputs clang-tidy warnings in changed lines only. This is useful to
|
||||
detect clang-tidy regressions in the lines touched by a specific patch.
|
||||
Example usage for git/svn users:
|
||||
|
||||
git diff -U0 HEAD^ | clang-tidy-diff.py -p1
|
||||
svn diff --diff-cmd=diff -x-U0 | \
|
||||
clang-tidy-diff.py -fix -checks=-*,modernize-use-override
|
||||
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=
|
||||
'Run clang-tidy against changed files, and '
|
||||
'output diagnostics only for modified '
|
||||
'lines.')
|
||||
parser.add_argument('-clang-tidy-binary', metavar='PATH',
|
||||
default='clang-tidy',
|
||||
help='path to clang-tidy binary')
|
||||
parser.add_argument('-p', metavar='NUM', default=0,
|
||||
help='strip the smallest prefix containing P slashes')
|
||||
parser.add_argument('-regex', metavar='PATTERN', default=None,
|
||||
help='custom pattern selecting file paths to check '
|
||||
'(case sensitive, overrides -iregex)')
|
||||
parser.add_argument('-iregex', metavar='PATTERN', default=
|
||||
r'.*\.(cpp|cc|c\+\+|cxx|c|cl|h|hpp|m|mm|inc)',
|
||||
help='custom pattern selecting file paths to check '
|
||||
'(case insensitive, overridden by -regex)')
|
||||
|
||||
parser.add_argument('-fix', action='store_true', default=False,
|
||||
help='apply suggested fixes')
|
||||
parser.add_argument('-checks',
|
||||
help='checks filter, when not specified, use clang-tidy '
|
||||
'default',
|
||||
default='')
|
||||
parser.add_argument('-path', dest='build_path',
|
||||
help='Path used to read a compile command database.')
|
||||
parser.add_argument('-extra-arg', dest='extra_arg',
|
||||
action='append', default=[],
|
||||
help='Additional argument to append to the compiler '
|
||||
'command line.')
|
||||
parser.add_argument('-extra-arg-before', dest='extra_arg_before',
|
||||
action='append', default=[],
|
||||
help='Additional argument to prepend to the compiler '
|
||||
'command line.')
|
||||
parser.add_argument('-quiet', action='store_true', default=False,
|
||||
help='Run clang-tidy in quiet mode')
|
||||
clang_tidy_args = []
|
||||
argv = sys.argv[1:]
|
||||
if '--' in argv:
|
||||
clang_tidy_args.extend(argv[argv.index('--'):])
|
||||
argv = argv[:argv.index('--')]
|
||||
|
||||
args = parser.parse_args(argv)
|
||||
|
||||
# Extract changed lines for each file.
|
||||
filename = None
|
||||
lines_by_file = {}
|
||||
for line in sys.stdin:
|
||||
match = re.search('^\+\+\+\ \"?(.*?/){%s}([^ \t\n\"]*)' % args.p, line)
|
||||
if match:
|
||||
filename = match.group(2)
|
||||
if filename == None:
|
||||
continue
|
||||
|
||||
if args.regex is not None:
|
||||
if not re.match('^%s$' % args.regex, filename):
|
||||
continue
|
||||
else:
|
||||
if not re.match('^%s$' % args.iregex, filename, re.IGNORECASE):
|
||||
continue
|
||||
|
||||
match = re.search('^@@.*\+(\d+)(,(\d+))?', line)
|
||||
if match:
|
||||
start_line = int(match.group(1))
|
||||
line_count = 1
|
||||
if match.group(3):
|
||||
line_count = int(match.group(3))
|
||||
if line_count == 0:
|
||||
continue
|
||||
end_line = start_line + line_count - 1;
|
||||
lines_by_file.setdefault(filename, []).append([start_line, end_line])
|
||||
|
||||
if len(lines_by_file) == 0:
|
||||
print("No relevant changes found.")
|
||||
sys.exit(0)
|
||||
|
||||
line_filter_json = json.dumps(
|
||||
[{"name" : name, "lines" : lines_by_file[name]} for name in lines_by_file],
|
||||
separators = (',', ':'))
|
||||
|
||||
quote = "";
|
||||
if sys.platform == 'win32':
|
||||
line_filter_json=re.sub(r'"', r'"""', line_filter_json)
|
||||
else:
|
||||
quote = "'";
|
||||
|
||||
# Run clang-tidy on files containing changes.
|
||||
command = [args.clang_tidy_binary]
|
||||
command.append('-line-filter=' + quote + line_filter_json + quote)
|
||||
if args.fix:
|
||||
command.append('-fix')
|
||||
if args.checks != '':
|
||||
command.append('-checks=' + quote + args.checks + quote)
|
||||
if args.quiet:
|
||||
command.append('-quiet')
|
||||
if args.build_path is not None:
|
||||
command.append('-p=%s' % args.build_path)
|
||||
command.extend(lines_by_file.keys())
|
||||
for arg in args.extra_arg:
|
||||
command.append('-extra-arg=%s' % arg)
|
||||
for arg in args.extra_arg_before:
|
||||
command.append('-extra-arg-before=%s' % arg)
|
||||
command.extend(clang_tidy_args)
|
||||
|
||||
sys.exit(subprocess.call(' '.join(command), shell=True))
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,24 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
if ! git rev-list $TRAVIS_COMMIT_RANGE 2>1 >/dev/null; then
|
||||
echo "\$TRAVIS_COMMIT_RANGE ($TRAVIS_COMMIT_RANGE) is not valid for this build (probably caused by a rebase)."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
cd "$TRAVIS_BUILD_DIR"
|
||||
|
||||
echo "Running clang-tidy on changed files"
|
||||
git diff -U0 --no-color $TRAVIS_COMMIT_RANGE | \
|
||||
$TRAVIS_BUILD_DIR/ci/travis/clang-tidy-diff.py -path "$TRAVIS_BUILD_DIR/build" -p1 \
|
||||
-regex 'code/.*$|freespace2/.*$|qtfred/.*$|test/src/.*$|build/.*$|tools/.*' \
|
||||
-clang-tidy-binary /usr/bin/clang-tidy-4.0 2>/dev/null | \
|
||||
tee clang-tidy-output.txt
|
||||
|
||||
if [[ -n $(grep "warning: " clang-tidy-output.txt) ]] || [[ -n $(grep "error: " clang-tidy-output.txt) ]]; then
|
||||
echo "Errors or warnings were detected in the clang-tidy output!"
|
||||
exit 1
|
||||
else
|
||||
echo -e "\033[1;32m\xE2\x9C\x93 passed:\033[0m clang-tidy test succeeded";
|
||||
fi
|
||||
+18
-53
@@ -10,62 +10,27 @@ if [[ ! "$(curl -V)" == *"sftp"* ]]; then
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
|
||||
if [ -f ~/curl_cache/curl*.deb ]; then
|
||||
cd ~/curl_cache
|
||||
sudo dpkg -i libcurl3*.deb
|
||||
sudo dpkg -i curl*.deb
|
||||
else
|
||||
# Since the Travis CI people are not capable of enabling SSH/SCP support for their libcurl we need to build that manually...
|
||||
# These commands are based on the tutorial from here: http://zeroset.mnim.org/2013/03/14/sftp-support-for-curl-in-ubuntu-12-10-quantal-quetzal-and-later/
|
||||
mkdir /tmp/curl
|
||||
cd /tmp/curl
|
||||
sudo apt-get update
|
||||
sudo apt-get install build-essential debhelper libssh2-1-dev libgnutls-dev libidn11-dev libkrb5-dev libldap2-dev libnss3-dev librtmp-dev libtool openssh-server quilt
|
||||
apt-get source curl
|
||||
sudo apt-get build-dep curl
|
||||
# Since the Travis CI people are not capable of enabling SSH/SCP support for their libcurl we need to build that manually...
|
||||
# These commands are based on the tutorial from here: http://zeroset.mnim.org/2013/03/14/sftp-support-for-curl-in-ubuntu-12-10-quantal-quetzal-and-later/
|
||||
mkdir /tmp/curl
|
||||
cd /tmp/curl
|
||||
sudo apt-get update
|
||||
sudo apt-get install build-essential debhelper libssh2-1-dev libgnutls-dev libidn11-dev libkrb5-dev libldap2-dev libnss3-dev librtmp-dev libtool openssh-server quilt
|
||||
apt-get source curl
|
||||
sudo apt-get build-dep curl
|
||||
|
||||
cd curl-*
|
||||
export DEB_BUILD_OPTIONS="nocheck"
|
||||
sudo dpkg-buildpackage -uc -us -j"$(grep -c ^processor /proc/cpuinfo)"
|
||||
cd curl-*
|
||||
export DEB_BUILD_OPTIONS="nocheck"
|
||||
sudo dpkg-buildpackage -uc -us -j"$(grep -c ^processor /proc/cpuinfo)"
|
||||
|
||||
cd ..
|
||||
dpkg -l | grep curl
|
||||
ls -al
|
||||
|
||||
if [ ! -d ~/curl_cache ]; then
|
||||
mkdir ~/curl_cache
|
||||
fi
|
||||
|
||||
cp libcurl3*.deb curl*.deb ~/curl_cache
|
||||
|
||||
sudo dpkg -i libcurl3*.deb
|
||||
sudo dpkg -i curl*.deb
|
||||
fi
|
||||
cd ..
|
||||
dpkg -l | grep curl
|
||||
ls -al
|
||||
sudo dpkg -i libcurl3*.deb
|
||||
sudo dpkg -i curl*.deb
|
||||
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
brew install libssh2
|
||||
|
||||
if [ -d ~/curl_cache/curl ]; then
|
||||
cd ~/curl_cache/curl
|
||||
sudo make install
|
||||
else
|
||||
mkdir /tmp/curl
|
||||
cd /tmp/curl
|
||||
|
||||
curl -LO "https://curl.haxx.se/download/curl-7.64.0.tar.bz2"
|
||||
tar -xjf curl-7.64.0.tar.bz2
|
||||
|
||||
cd curl-7.64.0
|
||||
./configure --disable-debug --disable-dependency-tracking --disable-silent-rules --with-libssh2 --with-darwinssl --without-ca-bundle --without-ca-path
|
||||
make -j"$(sysctl hw.logicalcpu | cut -d " " -f 2)"
|
||||
|
||||
if [ ! -d ~/curl_cache ]; then
|
||||
mkdir ~/curl_cache
|
||||
fi
|
||||
|
||||
cp -a . ~/curl_cache/curl
|
||||
sudo make install
|
||||
fi
|
||||
export PATH=/usr/local/bin:$PATH
|
||||
brew install curl --with-libssh2
|
||||
export PATH="/usr/local/opt/curl/bin:$PATH"
|
||||
fi
|
||||
|
||||
# After
|
||||
|
||||
+9
-12
@@ -4,31 +4,28 @@ set -ex
|
||||
|
||||
FILENAME=
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
if [ ! -d "$HOME/cmake-3.8/bin" ]; then
|
||||
if [ ! -d "$HOME/cmake/bin" ]; then
|
||||
# If the cache does not currently contain CMake then download and install it
|
||||
mkdir -p $HOME/cmake-3.8/
|
||||
FILENAME=cmake-3.4.3-Linux-x86_64
|
||||
|
||||
wget -O /tmp/cmake.tar.gz --no-check-certificate https://cmake.org/files/v3.8/cmake-3.8.2-Linux-x86_64.tar.gz
|
||||
tar -xzf /tmp/cmake.tar.gz -C $HOME/cmake-3.8/ --strip-components=1
|
||||
mkdir -p $HOME/cmake/
|
||||
|
||||
wget -O /tmp/cmake.tar.gz --no-check-certificate https://www.cmake.org/files/v3.4/$FILENAME.tar.gz
|
||||
tar -xzf /tmp/cmake.tar.gz -C $HOME/cmake/ --strip-components=1
|
||||
fi
|
||||
export PATH=$HOME/cmake-3.8/bin:$PATH
|
||||
export PATH=$HOME/cmake/bin:$PATH
|
||||
|
||||
cd $HOME
|
||||
|
||||
if [ "${BUILD_DEPLOYMENT}" = true ]; then
|
||||
wget -O appimagetool -c "https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage" # (64-bit)
|
||||
chmod a+x ./appimagetool
|
||||
|
||||
wget -O linuxdeployqt -c "https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage" # (64-bit)
|
||||
chmod a+x ./linuxdeployqt
|
||||
wget -c "https://github.com/probonopd/AppImageKit/releases/download/5/AppImageAssistant" # (64-bit)
|
||||
chmod a+x ./AppImageAssistant
|
||||
fi
|
||||
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
gem install xcpretty
|
||||
|
||||
brew update
|
||||
brew outdated cmake || brew upgrade cmake
|
||||
elif [ "$TRAVIS_OS_NAME" = "windows" ]; then
|
||||
choco install mingw ninja
|
||||
fi
|
||||
|
||||
cmake --version
|
||||
+1
-34
@@ -8,40 +8,7 @@ if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
for config in $BUILD_CONFIGS
|
||||
do
|
||||
cd "$config"
|
||||
|
||||
# Compile all targets
|
||||
ninja all
|
||||
|
||||
# Install Freespace2 targets
|
||||
cmake -DCMAKE_INSTALL_PREFIX=/tmp/release/$config/fso -DCOMPONENT=Unspecified -P cmake_install.cmake
|
||||
cmake -DCMAKE_INSTALL_PREFIX=/tmp/release/$config/fso -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 /tmp/release/$config/fso/bin -name 'fs2_open_*' -type f -printf "%f\n").AppImage"
|
||||
$HOME/appimagetool -n /tmp/release/$config/fso "/tmp/release/$config/fso/$FILENAME"
|
||||
|
||||
: <<'END'
|
||||
# Install qtFRED targets
|
||||
cmake -DCMAKE_INSTALL_PREFIX=/tmp/release/$config/qtfred/usr -DCOMPONENT=Unspecified -P cmake_install.cmake
|
||||
cmake -DCMAKE_INSTALL_PREFIX=/tmp/release/$config/qtfred/usr -DCOMPONENT=qtFRED -P cmake_install.cmake
|
||||
|
||||
PREV="$(pwd)"
|
||||
cd /tmp/release/$config/qtfred
|
||||
|
||||
unset QTDIR; unset QT_PLUGIN_PATH; unset LD_LIBRARY_PATH
|
||||
$HOME/linuxdeployqt usr/qtfred.desktop -bundle-non-qt-libs
|
||||
# Move our AppRun script to the right location
|
||||
mv usr/AppRun AppRun
|
||||
|
||||
echo "Embed newer libstdc++ for distros that don't come with it (ubuntu 14.04)";
|
||||
mkdir -p usr/optional/; mkdir -p usr/optional/libstdc++/;
|
||||
cp /usr/lib/x86_64-linux-gnu/libstdc++.so.6 ./usr/optional/libstdc++/;
|
||||
|
||||
$HOME/appimagetool -n . "$(find /tmp/release/$config/qtfred/usr/bin -name 'qtfred_*' -type f -printf "%f\n").AppImage"
|
||||
|
||||
cd "$PREV"
|
||||
END
|
||||
|
||||
ninja appimage
|
||||
cd ..
|
||||
done
|
||||
|
||||
|
||||
+3
-14
@@ -5,15 +5,10 @@ set -e
|
||||
cd build
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
ninja -k 20 all
|
||||
ninja all
|
||||
|
||||
|
||||
if [ "$CONFIGURATION" = "Debug" ]; then
|
||||
valgrind --leak-check=full --error-exitcode=1 --gen-suppressions=all \
|
||||
--suppressions="$TRAVIS_BUILD_DIR/ci/travis/valgrind.supp" ./bin/unittests --gtest_shuffle
|
||||
else
|
||||
./bin/unittests --gtest_shuffle
|
||||
fi
|
||||
valgrind --leak-check=full --error-exitcode=1 --gen-suppressions=all \
|
||||
--suppressions="$TRAVIS_BUILD_DIR/ci/travis/valgrind.supp" ./bin/unittests --gtest_shuffle
|
||||
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
cmake --build . --config "$CONFIGURATION" | tee build.log | xcpretty
|
||||
XCODE_RET=${PIPESTATUS[0]}
|
||||
@@ -22,10 +17,4 @@ elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
curl --upload-file build.log.tar.gz "https://transfer.sh/build.log.tar.gz"
|
||||
exit $XCODE_RET
|
||||
fi
|
||||
elif [ "$TRAVIS_OS_NAME" = "windows" ]; then
|
||||
if [ "$CMAKE_GENERATOR" = "Ninja" ]; then
|
||||
cmake --build . --config "$CONFIGURATION"
|
||||
else
|
||||
cmake --build . --config "$CONFIGURATION" -- /verbosity:minimal
|
||||
fi
|
||||
fi
|
||||
+1
-16
@@ -25,19 +25,4 @@
|
||||
fun:_dl_init
|
||||
fun:dl_open_worker
|
||||
fun:_dl_catch_error
|
||||
}
|
||||
{
|
||||
CLang Lua unitialized value error
|
||||
Memcheck:Cond
|
||||
...
|
||||
fun:luaH_get
|
||||
fun:lua_rawget
|
||||
fun:_ZN12_GLOBAL__N_117ade_index_handlerEP9lua_State
|
||||
}
|
||||
{
|
||||
False-positive uninitialized variable warning
|
||||
Memcheck:Cond
|
||||
fun:_Z23cf_check_location_flagsjj
|
||||
fun:_Z29cf_create_default_path_stringPcjiPKcbj
|
||||
...
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,4 @@
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Name=FreeSpace Open
|
||||
Exec=$<TARGET_FILE_NAME:Freespace2>
|
||||
Icon=app_icon
|
||||
Categories=Game;
|
||||
Icon=app_icon.png
|
||||
@@ -6,16 +6,18 @@ configure_file("${CMAKE_CURRENT_LIST_DIR}/AppRun.in" "${CMAKE_CURRENT_BINARY_DIR
|
||||
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")
|
||||
install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/AppRun-$<CONFIG>" DESTINATION "." RENAME "AppRun")
|
||||
|
||||
|
||||
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_CURRENT_BINARY_DIR}/AppImage-$<CONFIG>.desktop" DESTINATION "." RENAME "fso.desktop")
|
||||
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/freespace2/resources/app_icon.png" DESTINATION "."
|
||||
COMPONENT "Freespace2")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/freespace2/resources/app_icon.png" DESTINATION ".")
|
||||
|
||||
add_custom_target(appimage
|
||||
COMMAND "${APPIMAGE_ASSISTANT}" "${CMAKE_INSTALL_PREFIX}" "${CMAKE_INSTALL_PREFIX}/fs2_open_${FSO_BINARY_SUFFIX}.AppImage")
|
||||
|
||||
add_dependencies(appimage install)
|
||||
@@ -1,37 +0,0 @@
|
||||
option(ENABLE_CLANG_TIDY "Enable source code checking using clang-tidy" OFF)
|
||||
|
||||
find_program(
|
||||
CLANG_TIDY_EXE
|
||||
NAMES "clang-tidy"
|
||||
DOC "Path to clang-tidy executable"
|
||||
)
|
||||
|
||||
function(enable_clang_tidy target)
|
||||
# Not enabled in this configuration
|
||||
endfunction()
|
||||
|
||||
if(NOT ENABLE_CLANG_TIDY)
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(NOT EXISTS "${CLANG_TIDY_EXE}")
|
||||
message(SEND_ERROR "clang-tidy: Could not find clang-tidy executable (value of variable is \"${CLANG_TIDY_EXE}\".")
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(CMAKE_VERSION VERSION_LESS "3.6.0")
|
||||
message(SEND_ERROR "Clang-tidy support requires CMake 3.6")
|
||||
return()
|
||||
endif()
|
||||
|
||||
message(STATUS "clang-tidy: Using \"${CLANG_TIDY_EXE}\"")
|
||||
|
||||
function(enable_clang_tidy target)
|
||||
SET(TIDY_OPTIONS "${CLANG_TIDY_EXE}")
|
||||
if(FSO_FATAL_WARNINGS)
|
||||
set(TIDY_OPTIONS "${TIDY_OPTIONS};-warnings-as-errors=*")
|
||||
endif()
|
||||
|
||||
set_target_properties(${target} PROPERTIES CXX_CLANG_TIDY "${TIDY_OPTIONS}")
|
||||
endfunction()
|
||||
|
||||
@@ -41,8 +41,5 @@ CHECK_FUNCTION_EXISTS(strlwr HAVE_STRLWR)
|
||||
|
||||
CHECK_INCLUDE_FILE("strings.h" HAVE_STRINGS_H)
|
||||
|
||||
check_symbol_exists(snprintf "stdio.h" HAVE_SNPRINTF)
|
||||
check_symbol_exists(_snprintf "stdio.h" HAVE__SNPRINTF)
|
||||
|
||||
set(PLATFORM_CHECK_HEADER "${GENERATED_SOURCE_DIR}/platformChecks.h")
|
||||
CONFIGURE_FILE(${CMAKE_CURRENT_LIST_DIR}/platformChecks.h.in "${PLATFORM_CHECK_HEADER}")
|
||||
@@ -25,7 +25,4 @@
|
||||
#cmakedefine01 HAVE_CHAR32_T
|
||||
#cmakedefine01 HAVE_UNICODE_CHAR_LITERAL
|
||||
|
||||
#cmakedefine01 HAVE_SNPRINTF
|
||||
#cmakedefine01 HAVE__SNPRINTF
|
||||
|
||||
#endif // __PLATFORM_CHECKS_H__
|
||||
@@ -9,6 +9,8 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -funroll-loops -fsigned-char -Wno-
|
||||
# Omit "conversion from string literal to 'char *' is deprecated" warnings.
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-write-strings")
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-function")
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated -Wno-char-subscripts")
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fcolor-diagnostics")
|
||||
|
||||
@@ -66,17 +66,21 @@ set(COMPILER_FLAGS "${COMPILER_FLAGS} ${SANITIZE_FLAGS}")
|
||||
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wformat-security")
|
||||
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wno-unused-function")
|
||||
|
||||
# Dear Clang, please tell us if a function does not return a value since that part of the standard is stupid!
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wreturn-type")
|
||||
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wno-char-subscripts")
|
||||
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wno-unused-parameter")
|
||||
|
||||
check_cxx_compiler_flag(-Wshift-negative-value SUPPORTS_SHIFT_NEGATIVE_VALUE)
|
||||
if(SUPPORTS_SHIFT_NEGATIVE_VALUE)
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wno-shift-negative-value")
|
||||
endif()
|
||||
|
||||
set(COMPILER_FLAGS_RELEASE "-O2 -Wno-unused-variable -Wno-unused-parameter")
|
||||
set(COMPILER_FLAGS_RELEASE "-O2 -Wno-unused-variable")
|
||||
|
||||
set(COMPILER_FLAGS_DEBUG "-O0 -g -Wshadow")
|
||||
|
||||
|
||||
@@ -78,23 +78,16 @@ set(COMPILER_FLAGS "${COMPILER_FLAGS} ${SANITIZE_FLAGS}")
|
||||
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wformat-security")
|
||||
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wno-unused-function")
|
||||
|
||||
# Dear GCC, please tell us if a function does not return a value since that part of the standard is stupid!
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wreturn-type")
|
||||
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wno-deprecated -Wno-char-subscripts")
|
||||
|
||||
# These two warnings cause a lot of false-positives in the FSO code base
|
||||
check_cxx_compiler_flag(-Wstringop-truncation SUPPORTS_STRINGOP_TRUNCATION)
|
||||
if(SUPPORTS_STRINGOP_TRUNCATION)
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wno-stringop-truncation")
|
||||
endif()
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wno-unused-parameter")
|
||||
|
||||
check_cxx_compiler_flag(-Wstringop-overflow SUPPORTS_STRINGOP_OVERFLOW)
|
||||
if(SUPPORTS_STRINGOP_TRUNCATION)
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wno-stringop-overflow")
|
||||
endif()
|
||||
|
||||
set(COMPILER_FLAGS_RELEASE "-O2 -Wno-unused-variable -Wno-unused-but-set-variable -Wno-array-bounds -Wno-empty-body -Wno-clobbered -Wno-unused-parameter")
|
||||
set(COMPILER_FLAGS_RELEASE "-O2 -Wno-unused-variable -Wno-unused-but-set-variable -Wno-array-bounds -Wno-empty-body -Wno-clobbered")
|
||||
|
||||
set(COMPILER_FLAGS_DEBUG "-O0 -g -Wshadow")
|
||||
|
||||
@@ -112,7 +105,6 @@ set(CMAKE_EXE_LINKER_FLAGS "")
|
||||
|
||||
IF (MINGW)
|
||||
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static -static-libgcc -static-libstdc++ -Wl,--enable-auto-import")
|
||||
target_compile_definitions(compiler INTERFACE __USE_MINGW_ANSI_STDIO=1)
|
||||
ENDIF(MINGW)
|
||||
|
||||
if (SANITIZE_FLAGS)
|
||||
@@ -139,4 +131,4 @@ if (FSO_FATAL_WARNINGS)
|
||||
endif()
|
||||
|
||||
# Always define this to make sure that the fixed width format macros are available
|
||||
target_compile_definitions(compiler INTERFACE __STDC_FORMAT_MACROS=1)
|
||||
target_compile_definitions(compiler INTERFACE __STDC_FORMAT_MACROS)
|
||||
@@ -36,7 +36,6 @@ set(WARNING_FLAGS
|
||||
/wd4592 # "symbol will be dynamically initialized" is being generated by a compiler bug, see https://stackoverflow.com/a/34027257 for an explanation - m!m
|
||||
$<$<CONFIG:Release>:/wd4101> # In release mode there are unreferenced variables because debug needs them
|
||||
/wd4995 # "'vsprintf': name was marked as #pragma deprecated" is being caused by our custom definition of vsprintf. I have no idea what causes this or how to fix it - m!m
|
||||
/wd4723 # "potential divide by 0" is caused by some code that definitely will not divide by zero - m!m
|
||||
)
|
||||
|
||||
target_compile_options(compiler INTERFACE ${WARNING_FLAGS})
|
||||
@@ -136,9 +135,9 @@ else()
|
||||
ENDIF()
|
||||
endif()
|
||||
|
||||
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)
|
||||
|
||||
target_compile_definitions(compiler INTERFACE _CRT_SECURE_NO_DEPRECATE
|
||||
_CRT_SECURE_NO_WARNINGS _SECURE_SCL=0 NOMINMAX "$<$<CONFIG:FastDebug>:_ITERATOR_DEBUG_LEVEL=0>")
|
||||
|
||||
if (FSO_FATAL_WARNINGS)
|
||||
# Make warnings fatal if the right variable is set
|
||||
target_compile_options(compiler INTERFACE "/WX")
|
||||
|
||||
+4
-44
@@ -10,7 +10,7 @@ FUNCTION(ADD_IMPORTED_LIB NAME INCLUDES LIBS)
|
||||
|
||||
target_link_libraries(${NAME} INTERFACE "${LIBS}")
|
||||
|
||||
target_include_directories(${NAME} SYSTEM INTERFACE "${INCLUDES}")
|
||||
target_include_directories(${NAME} INTERFACE "${INCLUDES}")
|
||||
ENDFUNCTION(ADD_IMPORTED_LIB)
|
||||
|
||||
MACRO(PKG_CONFIG_LIB_RESOLVE NAME OUTVAR)
|
||||
@@ -141,12 +141,10 @@ macro(set_if_not_defined VAR VALUE)
|
||||
endmacro(set_if_not_defined)
|
||||
|
||||
macro(configure_cotire target)
|
||||
if(ENABLE_COTIRE)
|
||||
# Disable unity build as it doesn't work well for us
|
||||
set_target_properties(${target} PROPERTIES COTIRE_ADD_UNITY_BUILD FALSE)
|
||||
# Disable unity build as it doesn't work well for us
|
||||
set_target_properties(${target} PROPERTIES COTIRE_ADD_UNITY_BUILD FALSE)
|
||||
|
||||
cotire(${target})
|
||||
endif()
|
||||
cotire(${target})
|
||||
endmacro(configure_cotire)
|
||||
|
||||
macro(add_target_copy_files)
|
||||
@@ -197,41 +195,3 @@ function(suppress_warnings _target)
|
||||
target_compile_options(${_target} PRIVATE "-w")
|
||||
endif()
|
||||
endfunction(suppress_warnings)
|
||||
|
||||
|
||||
function(list_target_dependencies _target _out_var)
|
||||
set(out_list)
|
||||
set(work_libs ${_target})
|
||||
list(LENGTH work_libs libs_length)
|
||||
|
||||
while(libs_length GREATER 0)
|
||||
list(GET work_libs 0 current)
|
||||
list(REMOVE_AT work_libs 0)
|
||||
list(APPEND out_list ${current})
|
||||
|
||||
get_target_property(current_libs ${current} INTERFACE_LINK_LIBRARIES)
|
||||
|
||||
if(current_libs)
|
||||
foreach(lib ${current_libs})
|
||||
if (TARGET ${lib})
|
||||
list(APPEND work_libs ${lib})
|
||||
endif (TARGET ${lib})
|
||||
endforeach(lib)
|
||||
endif(current_libs)
|
||||
|
||||
list(LENGTH work_libs libs_length)
|
||||
endwhile(libs_length GREATER 0)
|
||||
|
||||
list(REMOVE_DUPLICATES out_list)
|
||||
set(${_out_var} ${out_list} PARENT_SCOPE)
|
||||
endfunction(list_target_dependencies)
|
||||
|
||||
macro(add_file_folder FOLDER_NAME)
|
||||
string(MAKE_C_IDENTIFIER "${FOLDER_NAME}" VARIABLE_NAME)
|
||||
set(files_${VARIABLE_NAME} ${files_${VARIABLE_NAME}} ${ARGN})
|
||||
|
||||
string(REPLACE "/" "\\" FIXED_FOLDER_FILE "${FOLDER_NAME}")
|
||||
|
||||
source_group("${FIXED_FOLDER_FILE}" FILES ${ARGN})
|
||||
set(source_files ${source_files} ${ARGN})
|
||||
endmacro(add_file_folder)
|
||||
+2
-22
@@ -3,7 +3,7 @@ INCLUDE(source_groups.cmake)
|
||||
|
||||
INCLUDE(voice_rec.cmake)
|
||||
|
||||
ADD_LIBRARY(code STATIC ${source_files} ${VOICE_REC_FILES})
|
||||
ADD_LIBRARY(code STATIC ${file_root} ${VOICE_REC_FILES})
|
||||
|
||||
target_compile_features(code PUBLIC ${REQUIRED_CXX_FEATURES})
|
||||
|
||||
@@ -37,12 +37,6 @@ TARGET_LINK_LIBRARIES(code PUBLIC compiler)
|
||||
|
||||
target_link_libraries(code PUBLIC md5)
|
||||
|
||||
target_link_libraries(code PUBLIC discord-rpc)
|
||||
|
||||
target_link_libraries(code PUBLIC libRocket)
|
||||
|
||||
enable_clang_tidy(code)
|
||||
|
||||
IF (FSO_USE_SPEECH)
|
||||
find_package(Speech REQUIRED)
|
||||
target_link_libraries(code PUBLIC speech)
|
||||
@@ -61,21 +55,7 @@ IF(FSO_BUILD_TOOLS)
|
||||
ADD_SUBDIRECTORY(cfileextractor)
|
||||
ENDIF(FSO_BUILD_TOOLS)
|
||||
|
||||
if (ENABLE_COTIRE)
|
||||
set_target_properties(code PROPERTIES COTIRE_CXX_PREFIX_HEADER_INIT "${CMAKE_CURRENT_SOURCE_DIR}/prefix_header.h")
|
||||
else()
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
target_compile_options(code PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:-include${CMAKE_CURRENT_SOURCE_DIR}/prefix_header.h>")
|
||||
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
target_compile_options(code PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:/FI ${CMAKE_CURRENT_SOURCE_DIR}/prefix_header.h>")
|
||||
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
target_compile_options(code PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:-include${CMAKE_CURRENT_SOURCE_DIR}/prefix_header.h>")
|
||||
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang")
|
||||
target_compile_options(code PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:-include${CMAKE_CURRENT_SOURCE_DIR}/prefix_header.h>")
|
||||
ELSE()
|
||||
MESSAGE("Unknown compiler for global includes. This will probably break the build.")
|
||||
ENDIF()
|
||||
endif()
|
||||
set_target_properties(code PROPERTIES COTIRE_CXX_PREFIX_HEADER_INIT "prefix_header.h")
|
||||
|
||||
include(util)
|
||||
configure_cotire(code)
|
||||
|
||||
+9
-4
@@ -567,9 +567,9 @@ extern void ai_dock_with_object(object *docker, int docker_index, object *dockee
|
||||
extern void ai_stay_still(object *still_objp, vec3d *view_pos);
|
||||
extern void ai_do_default_behavior(object *obj);
|
||||
extern void ai_start_waypoints(object *objp, waypoint_list *wp_list, int wp_flags);
|
||||
extern void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hit_normal);
|
||||
extern void ai_ship_destroy(int shipnum);
|
||||
extern void ai_turn_towards_vector(vec3d *dest, object *objp, float turn_time, vec3d *slide_vec, vec3d *rel_pos, float bank_override, int flags, vec3d *rvec = nullptr, int sexp_flags = 0);
|
||||
extern void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hitpos, int shield_quadrant, vec3d *hit_normal);
|
||||
extern void ai_ship_destroy(int shipnum, Ship::Exit_Flags method);
|
||||
extern void ai_turn_towards_vector(vec3d *dest, object *objp, float frametime, float turn_time, vec3d *slide_vec, vec3d *rel_pos, float bank_override, int flags, vec3d *rvec = NULL, int sexp_flags = 0);
|
||||
extern void init_ai_object(int objnum);
|
||||
extern void ai_init(void); // Call this one to parse ai.tbl.
|
||||
extern void ai_level_init(void); // Call before each level to reset AI
|
||||
@@ -587,10 +587,13 @@ extern void get_absolute_wing_pos_autopilot( vec3d *result_pos, object *leader_o
|
||||
|
||||
// Interface from goals code to AI. Set ship to guard. *objp guards *other_objp
|
||||
extern void ai_set_guard_object(object *objp, object *other_objp);
|
||||
extern void ai_set_evade_object(object *objp, object *other_objp);
|
||||
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 void ai_fly_in_formation(int wing_num); // Force wing to fly in formation.
|
||||
extern void ai_disband_formation(int wing_num); // Force wing to disband formation flying.
|
||||
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);
|
||||
@@ -619,7 +622,7 @@ extern float ai_path();
|
||||
extern void evade_weapon();
|
||||
extern int might_collide_with_ship(object *obj1, object *obj2, float dot_to_enemy, float dist_to_enemy, float duration);
|
||||
extern int ai_fire_primary_weapon(object *objp); //changed to return weather it fired-Bobboau
|
||||
extern int ai_fire_secondary_weapon(object *objp);
|
||||
extern int ai_fire_secondary_weapon(object *objp, int priority1 = -1, int priority2 = -1);
|
||||
extern float ai_get_weapon_dist(ship_weapon *swp);
|
||||
extern void turn_towards_point(object *objp, vec3d *point, vec3d *slide_vec, float bank_override);
|
||||
extern int ai_maybe_fire_afterburner(object *objp, ai_info *aip);
|
||||
@@ -643,6 +646,8 @@ extern void ai_do_objects_repairing_stuff( object *repaired_obj, object *repair_
|
||||
// Move to a position relative to a dock bay using thrusters.
|
||||
extern float dock_orient_and_approach(object *docker_objp, int docker_index, object *dockee_objp, int dockee_index, int dock_mode, rotating_dockpoint_info *rdinfo = NULL);
|
||||
|
||||
extern int find_danger_weapon(object *sobjp, float dtime, float *atime, float dot_threshhold);
|
||||
|
||||
void ai_set_mode_warp_out(object *objp, ai_info *aip);
|
||||
|
||||
// prototyped by Goober5000
|
||||
|
||||
@@ -87,7 +87,6 @@ namespace AI {
|
||||
Fix_heat_seeker_stealth_bug,
|
||||
Fix_linked_primary_bug,
|
||||
Force_beam_turret_fov,
|
||||
Free_afterburner_use,
|
||||
Glide_decay_requires_thrust,
|
||||
Hack_improve_non_homing_swarm_turret_fire_accuracy,
|
||||
Huge_turret_weapons_ignore_bombs,
|
||||
@@ -110,9 +109,7 @@ namespace AI {
|
||||
Smart_shield_management,
|
||||
Smart_subsystem_targeting_for_turrets,
|
||||
Strict_turred_tagged_only_targeting,
|
||||
Support_dont_add_primaries, //Prevents support ship from equipping new primary as requested in http://scp.indiegames.us/mantis/view.php?id=3198
|
||||
Turrets_ignore_target_radius,
|
||||
Use_actual_primary_range,
|
||||
Use_additive_weapon_velocity,
|
||||
Use_newtonian_dampening,
|
||||
Use_only_single_fov_for_turrets,
|
||||
|
||||
@@ -357,8 +357,6 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
|
||||
set_flag(profile, "$smart afterburner management:", AI::Profile_Flags::Smart_afterburner_management);
|
||||
|
||||
set_flag(profile, "$free afterburner use:", AI::Profile_Flags::Free_afterburner_use);
|
||||
|
||||
set_flag(profile, "$allow rapid secondary dumbfire:", AI::Profile_Flags::Allow_rapid_secondary_dumbfire);
|
||||
|
||||
set_flag(profile, "$huge turret weapons ignore bombs:", AI::Profile_Flags::Huge_turret_weapons_ignore_bombs);
|
||||
@@ -435,8 +433,6 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
|
||||
set_flag(profile, "$ai guards specific ship in wing:", AI::Profile_Flags::Ai_guards_specific_ship_in_wing);
|
||||
|
||||
set_flag(profile, "$support don't add primaries:", AI::Profile_Flags::Support_dont_add_primaries);
|
||||
|
||||
profile->ai_path_mode = AI_PATH_MODE_NORMAL;
|
||||
if (optional_string("$ai path mode:"))
|
||||
{
|
||||
@@ -462,8 +458,6 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
|
||||
set_flag(profile, "$ai can slow down when attacking big ships:", AI::Profile_Flags::Ai_can_slow_down_attacking_big_ships);
|
||||
|
||||
set_flag(profile, "$use actual primary range:", AI::Profile_Flags::Use_actual_primary_range);
|
||||
|
||||
profile->bay_arrive_speed_mult = 1.0f;
|
||||
profile->bay_depart_speed_mult = 1.0f;
|
||||
if (optional_string("$bay arrive speed multiplier:")) {
|
||||
@@ -504,8 +498,7 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
}
|
||||
|
||||
// find next valid option
|
||||
if (!skip_to_start_of_string_either("$", "#"))
|
||||
break;
|
||||
skip_to_start_of_string_either("$", "#");
|
||||
saved_Mp = Mp;
|
||||
}
|
||||
}
|
||||
|
||||
+26
-20
@@ -64,11 +64,10 @@ void ai_big_chase_attack(ai_info *aip, ship_info *sip, vec3d *enemy_pos, float d
|
||||
void ai_big_avoid_ship();
|
||||
int ai_big_maybe_follow_subsys_path(int do_dot_check=1);
|
||||
void ai_big_strafe_position();
|
||||
static int ai_big_strafe_maybe_retreat(const vec3d *target_pos);
|
||||
|
||||
extern int model_which_octant_distant_many( vec3d *pnt, int model_num,matrix *model_orient, vec3d * model_pos, polymodel **pm, int *octs);
|
||||
extern void compute_desired_rvec(vec3d *rvec, vec3d *goal_pos, vec3d *cur_pos);
|
||||
extern void big_ship_collide_recover_start(object *objp, object *big_objp, vec3d *collision_normal);
|
||||
extern void big_ship_collide_recover_start(object *objp, object *big_objp, vec3d *collide_pos, vec3d *collision_normal);
|
||||
|
||||
|
||||
// Called by ai_big_pick_attack_point.
|
||||
@@ -632,7 +631,7 @@ void ai_big_chase_attack(ai_info *aip, ship_info *sip, vec3d *enemy_pos, float d
|
||||
else
|
||||
rvec = NULL;
|
||||
|
||||
ai_turn_towards_vector(enemy_pos, Pl_objp, sip->srotation_time, nullptr, rel_pos, 0.0f, 0, rvec);
|
||||
ai_turn_towards_vector(enemy_pos, Pl_objp, flFrametime, sip->srotation_time, NULL, rel_pos, 0.0f, 0, rvec);
|
||||
|
||||
// calc range of primary weapon
|
||||
weapon_travel_dist = ai_get_weapon_dist(&Ships[Pl_objp->instance].weapons);
|
||||
@@ -642,7 +641,7 @@ void ai_big_chase_attack(ai_info *aip, ship_info *sip, vec3d *enemy_pos, float d
|
||||
accelerate_ship(aip, 1.0f);
|
||||
|
||||
ship *shipp = &Ships[Pl_objp->instance];
|
||||
if ((aip->ai_flags[AI::AI_Flags::Free_afterburner_use] || aip->ai_profile_flags[AI::Profile_Flags::Free_afterburner_use]) && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) && (dot_to_enemy > 0.75f)) {
|
||||
if ((aip->ai_flags[AI::AI_Flags::Free_afterburner_use]) && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) && (dot_to_enemy > 0.75f)) {
|
||||
if (ai_maybe_fire_afterburner(Pl_objp, aip)) {
|
||||
afterburners_start(Pl_objp);
|
||||
aip->afterburner_stop_time = Missiontime + 3*F1_0;
|
||||
@@ -684,7 +683,7 @@ void ai_big_chase_attack(ai_info *aip, ship_info *sip, vec3d *enemy_pos, float d
|
||||
accelerate_ship(aip, accel);
|
||||
|
||||
ship *shipp = &Ships[Pl_objp->instance];
|
||||
if ((aip->ai_flags[AI::AI_Flags::Free_afterburner_use] || aip->ai_profile_flags[AI::Profile_Flags::Free_afterburner_use]) && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) && (accel > 0.95f)) {
|
||||
if ((aip->ai_flags[AI::AI_Flags::Free_afterburner_use]) && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) && (accel > 0.95f)) {
|
||||
if (ai_maybe_fire_afterburner(Pl_objp, aip)) {
|
||||
afterburners_start(Pl_objp);
|
||||
aip->afterburner_stop_time = Missiontime + 3*F1_0;
|
||||
@@ -708,14 +707,14 @@ extern float set_secondary_fire_delay(ai_info *aip, ship *shipp, weapon_info *sw
|
||||
extern void ai_choose_secondary_weapon(object *objp, ai_info *aip, object *en_objp);
|
||||
extern int maybe_avoid_big_ship(object *objp, object *ignore_objp, ai_info *aip, vec3d *goal_point, float delta_time);
|
||||
|
||||
extern void maybe_cheat_fire_synaptic(object *objp);
|
||||
extern void maybe_cheat_fire_synaptic(object *objp, ai_info *aip);
|
||||
|
||||
// Determine if Pl_objp should fire weapons at current target, based on input parameters
|
||||
//
|
||||
// dist_to_enemy => distance (in m) to attack point on current target
|
||||
// dot_to_enemy => dot product between fvec of Pl_objp and vector from Pl_objp to attack point
|
||||
//
|
||||
static void ai_big_maybe_fire_weapons(float dist_to_enemy, float dot_to_enemy)
|
||||
void ai_big_maybe_fire_weapons(float dist_to_enemy, float dot_to_enemy, vec3d *firing_pos, vec3d *enemy_pos, vec3d *enemy_vel)
|
||||
{
|
||||
ai_info *aip;
|
||||
ship_weapon *swp;
|
||||
@@ -846,6 +845,8 @@ void ai_big_switch_to_chase_mode(ai_info *aip)
|
||||
aip->submode_start_time = Missiontime;
|
||||
}
|
||||
|
||||
extern int ai_big_strafe_maybe_retreat(float dist, vec3d *target_pos);
|
||||
|
||||
// Make object Pl_objp chase object En_objp, which is a big ship, not a small ship.
|
||||
void ai_big_chase()
|
||||
{
|
||||
@@ -858,7 +859,7 @@ void ai_big_chase()
|
||||
|
||||
Assert(aip->mode == AIM_CHASE);
|
||||
|
||||
maybe_cheat_fire_synaptic(Pl_objp);
|
||||
maybe_cheat_fire_synaptic(Pl_objp, aip);
|
||||
|
||||
ai_set_positions(Pl_objp, En_objp, aip, &player_pos, &enemy_pos);
|
||||
|
||||
@@ -881,7 +882,7 @@ void ai_big_chase()
|
||||
dot_to_enemy = vm_vec_dot(&vec_to_enemy, &Pl_objp->orient.vec.fvec);
|
||||
|
||||
if (aip->ai_flags[AI::AI_Flags::Target_collision]) {
|
||||
if ( ai_big_strafe_maybe_retreat(&enemy_pos) ) {
|
||||
if ( ai_big_strafe_maybe_retreat(dist_to_enemy, &enemy_pos) ) {
|
||||
aip->mode = AIM_STRAFE;
|
||||
aip->submode_parm0 = Missiontime; // use parm0 as time strafe mode entered (i.e. MODE start time)
|
||||
aip->submode = AIS_STRAFE_AVOID;
|
||||
@@ -1044,7 +1045,7 @@ void ai_big_chase()
|
||||
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);
|
||||
big_ship_collide_recover_start(Pl_objp, En_objp, &Pl_objp->pos, NULL);
|
||||
// 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) ) {
|
||||
@@ -1143,7 +1144,7 @@ void ai_big_chase()
|
||||
// TODO: investigate why ships fire (and aren't close to hitting ship) when following a path near
|
||||
// a big ship
|
||||
if (aip->mode != AIM_EVADE && aip->path_start == -1 ) {
|
||||
ai_big_maybe_fire_weapons(dist_to_enemy, dot_to_enemy);
|
||||
ai_big_maybe_fire_weapons(dist_to_enemy, dot_to_enemy, &player_pos, &predicted_enemy_pos, &En_objp->phys_info.vel);
|
||||
} else {
|
||||
if (flFrametime < 1.0f)
|
||||
aip->time_enemy_in_range *= (1.0f - flFrametime);
|
||||
@@ -1152,6 +1153,11 @@ void ai_big_chase()
|
||||
}
|
||||
}
|
||||
|
||||
void ai_big_ship(object *objp)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
// all three parms are output parameters
|
||||
// Enemy object is En_objp
|
||||
// pos => world pos of attack point
|
||||
@@ -1222,7 +1228,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 int ai_big_strafe_maybe_retreat(const vec3d *target_pos)
|
||||
int ai_big_strafe_maybe_retreat(float dist, vec3d *target_pos)
|
||||
{
|
||||
ai_info *aip;
|
||||
aip = &Ai_info[Ships[Pl_objp->instance].ai_index];
|
||||
@@ -1252,7 +1258,7 @@ static int ai_big_strafe_maybe_retreat(const vec3d *target_pos)
|
||||
if (aip->ai_flags[AI::AI_Flags::Target_collision]) {
|
||||
// use standard collision resolution
|
||||
aip->ai_flags.remove(AI::AI_Flags::Target_collision);
|
||||
big_ship_collide_recover_start(Pl_objp, En_objp, nullptr);
|
||||
big_ship_collide_recover_start(Pl_objp, En_objp, &Pl_objp->pos, NULL);
|
||||
} else {
|
||||
// too close for comfort so fly to box point + 300
|
||||
aip->submode = AIS_STRAFE_RETREAT1;
|
||||
@@ -1292,12 +1298,12 @@ void ai_big_strafe_attack()
|
||||
}
|
||||
|
||||
ai_big_attack_get_data(&target_pos, &target_dist, &target_dot);
|
||||
if ( ai_big_strafe_maybe_retreat(&target_pos) )
|
||||
if ( ai_big_strafe_maybe_retreat(target_dist, &target_pos) )
|
||||
return;
|
||||
|
||||
if (aip->ai_flags[AI::AI_Flags::Kamikaze]) {
|
||||
if (target_dist < 1200.0f) {
|
||||
ai_turn_towards_vector(&target_pos, Pl_objp, Ship_info[Ships[Pl_objp->instance].ship_info_index].srotation_time, nullptr, nullptr, 0.0f, 0);
|
||||
ai_turn_towards_vector(&target_pos, Pl_objp, flFrametime, Ship_info[Ships[Pl_objp->instance].ship_info_index].srotation_time, NULL, NULL, 0.0f, 0);
|
||||
accelerate_ship(aip, 1.0f);
|
||||
if ((target_dist < 400.0f) && ai_maybe_fire_afterburner(Pl_objp, aip)) {
|
||||
afterburners_start(Pl_objp);
|
||||
@@ -1341,7 +1347,7 @@ void ai_big_strafe_attack()
|
||||
}
|
||||
|
||||
// maybe fire weapons at target
|
||||
ai_big_maybe_fire_weapons(target_dist, target_dot);
|
||||
ai_big_maybe_fire_weapons(target_dist, target_dot, &Pl_objp->pos, &En_objp->pos, &En_objp->phys_info.vel);
|
||||
turn_towards_point(Pl_objp, &target_pos, NULL, 0.0f);
|
||||
|
||||
fix last_hit = Missiontime - aip->last_hit_time;
|
||||
@@ -1487,7 +1493,7 @@ void ai_big_strafe_glide_attack()
|
||||
vm_vec_sub2(&target_pos, &En_objp->pos);
|
||||
|
||||
turn_towards_point(Pl_objp, &target_pos, NULL, 0.0f);
|
||||
ai_big_maybe_fire_weapons(target_dist, target_dot);
|
||||
ai_big_maybe_fire_weapons(target_dist, target_dot, &Pl_objp->pos, &En_objp->pos, &En_objp->phys_info.vel);
|
||||
}
|
||||
|
||||
// if haven't been hit in quite a while, leave strafe mode
|
||||
@@ -1511,7 +1517,7 @@ void ai_big_strafe_avoid()
|
||||
mode_time = Missiontime - aip->submode_start_time;
|
||||
|
||||
ai_big_attack_get_data(&target_pos, &target_dist, &target_dot);
|
||||
if ( ai_big_strafe_maybe_retreat(&target_pos) )
|
||||
if ( ai_big_strafe_maybe_retreat(target_dist, &target_pos) )
|
||||
return;
|
||||
|
||||
if ( mode_time > fl2f(0.5)) {
|
||||
@@ -1698,7 +1704,7 @@ void ai_big_strafe()
|
||||
//
|
||||
// Check if weapon_objnum was fired by Pl_objp's target, and whether Pl_objp's target is a big ship, if
|
||||
// so, enter AIM_STRAFE
|
||||
int ai_big_maybe_enter_strafe_mode(const object *pl_objp, int weapon_objnum)
|
||||
int ai_big_maybe_enter_strafe_mode(object *pl_objp, int weapon_objnum, int consider_target_only)
|
||||
{
|
||||
ai_info *aip;
|
||||
ship_info *sip;
|
||||
@@ -1772,7 +1778,7 @@ int ai_big_maybe_enter_strafe_mode(const object *pl_objp, int weapon_objnum)
|
||||
// Consider attacking a turret, if a turret actually fired the weapon
|
||||
// input: ship_objp => ship that will attack the turret
|
||||
// weapon_objp =>
|
||||
void ai_big_strafe_maybe_attack_turret(const object *ship_objp, const object *weapon_objp)
|
||||
void ai_big_strafe_maybe_attack_turret(object *ship_objp, object *weapon_objp)
|
||||
{
|
||||
ai_info *aip;
|
||||
object *parent_objp;
|
||||
|
||||
+3
-2
@@ -17,13 +17,14 @@ struct ai_info;
|
||||
struct vec3d;
|
||||
class ship_subsys;
|
||||
|
||||
void ai_big_ship(object *objp);
|
||||
void ai_big_chase();
|
||||
void ai_big_subsys_path_cleanup(ai_info *aip);
|
||||
|
||||
// strafe functions
|
||||
void ai_big_strafe();
|
||||
int ai_big_maybe_enter_strafe_mode(const object *objp, int weapon_objnum);
|
||||
void ai_big_strafe_maybe_attack_turret(const object *ship_objp, const object *weapon_objp);
|
||||
int ai_big_maybe_enter_strafe_mode(object *objp, int weapon_objnum, int consider_target_only=0);
|
||||
void ai_big_strafe_maybe_attack_turret(object *ship_objp, object *weapon_objp);
|
||||
void ai_big_pick_attack_point(object *objp, object *attacker_objp, vec3d *attack_point, float fov=1.0f);
|
||||
void ai_big_pick_attack_point_turret(object *objp, ship_subsys *ssp, vec3d *gpos, vec3d *gvec, vec3d *attack_point, float weapon_travel_dist, float fov=1.0f);
|
||||
|
||||
|
||||
+185
-101
@@ -58,8 +58,6 @@
|
||||
#include "physics/physics.h"
|
||||
#include "playerman/player.h"
|
||||
#include "render/3d.h"
|
||||
#include "scripting/api/objs/wing.h"
|
||||
#include "scripting/scripting.h"
|
||||
#include "ship/afterburner.h"
|
||||
#include "ship/awacs.h"
|
||||
#include "ship/ship.h"
|
||||
@@ -70,7 +68,7 @@
|
||||
#include "weapon/swarm.h"
|
||||
#include "weapon/weapon.h"
|
||||
#include <map>
|
||||
#include <climits>
|
||||
#include <limits.h>
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
@@ -747,8 +745,6 @@ void parse_ai_class()
|
||||
|
||||
set_aic_flag(aicp, "$smart afterburner management:", AI::Profile_Flags::Smart_afterburner_management);
|
||||
|
||||
set_aic_flag(aicp, "$free afterburner use:", AI::Profile_Flags::Free_afterburner_use);
|
||||
|
||||
set_aic_flag(aicp, "$allow rapid secondary dumbfire:", AI::Profile_Flags::Allow_rapid_secondary_dumbfire);
|
||||
|
||||
set_aic_flag(aicp, "$huge turret weapons ignore bombs:", AI::Profile_Flags::Huge_turret_weapons_ignore_bombs);
|
||||
@@ -768,8 +764,6 @@ void parse_ai_class()
|
||||
set_aic_flag(aicp, "$all ships manage shields:", AI::Profile_Flags::All_ships_manage_shields);
|
||||
|
||||
set_aic_flag(aicp, "$ai can slow down when attacking big ships:", AI::Profile_Flags::Ai_can_slow_down_attacking_big_ships);
|
||||
|
||||
set_aic_flag(aicp, "$use actual primary range:", AI::Profile_Flags::Use_actual_primary_range);
|
||||
}
|
||||
|
||||
void reset_ai_class_names()
|
||||
@@ -1138,7 +1132,7 @@ void ai_update_danger_weapon(int attacked_objnum, int weapon_objnum)
|
||||
|
||||
// If rvec != NULL, use it to match bank by calling vm_matrix_interpolate.
|
||||
// (rvec defaults to NULL)
|
||||
void ai_turn_towards_vector(vec3d *dest, object *objp, float turn_time, vec3d *slide_vec, vec3d *rel_pos, float bank_override, int flags, vec3d *rvec, int sexp_flags)
|
||||
void ai_turn_towards_vector(vec3d *dest, object *objp, float frametime, float turn_time, vec3d *slide_vec, vec3d *rel_pos, float bank_override, int flags, vec3d *rvec, int sexp_flags)
|
||||
{
|
||||
matrix curr_orient;
|
||||
vec3d vel_in, vel_out, desired_fvec, src;
|
||||
@@ -1347,7 +1341,6 @@ void ai_object_init(object * obj, int ai_index)
|
||||
aip->wing = -1; // Member of what wing? -1 means none.
|
||||
aip->ai_class = Ship_info[Ships[obj->instance].ship_info_index].ai_class;
|
||||
aip->behavior = AIM_NONE;
|
||||
aip->mode = aip->behavior;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1507,12 +1500,12 @@ void turn_towards_point(object *objp, vec3d *point, vec3d *slide_vec, float bank
|
||||
if (aip->ai_flags[AI::AI_Flags::Formation_object, AI::AI_Flags::Formation_wing]) {
|
||||
if (&Objects[aip->goal_objnum] != objp) {
|
||||
float rotvel_z = objp->phys_info.rotvel.xyz.z;
|
||||
ai_turn_towards_vector(point, objp, Ship_info[Ships[objp->instance].ship_info_index].srotation_time, slide_vec, nullptr, bank_override, 0);
|
||||
ai_turn_towards_vector(point, objp, flFrametime, Ship_info[Ships[objp->instance].ship_info_index].srotation_time, slide_vec, NULL, bank_override, 0);
|
||||
objp->phys_info.rotvel.xyz.z = rotvel_z;
|
||||
}
|
||||
} else {
|
||||
// normal turn
|
||||
ai_turn_towards_vector(point, objp, Ship_info[Ships[objp->instance].ship_info_index].srotation_time, slide_vec, nullptr, bank_override, 0);
|
||||
ai_turn_towards_vector(point, objp, flFrametime, Ship_info[Ships[objp->instance].ship_info_index].srotation_time, slide_vec, NULL, bank_override, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1527,7 +1520,7 @@ void turn_away_from_point(object *objp, vec3d *point, float bank_override)
|
||||
vm_vec_sub(&opposite_point, &objp->pos, point);
|
||||
vm_vec_add2(&opposite_point, &objp->pos);
|
||||
|
||||
ai_turn_towards_vector(&opposite_point, objp, Ship_info[Ships[objp->instance].ship_info_index].srotation_time, nullptr, nullptr, bank_override, AITTV_FAST);
|
||||
ai_turn_towards_vector(&opposite_point, objp, flFrametime, Ship_info[Ships[objp->instance].ship_info_index].srotation_time, NULL, NULL, bank_override, AITTV_FAST);
|
||||
}
|
||||
|
||||
|
||||
@@ -1796,7 +1789,7 @@ float get_wing_lowest_av_ab_speed(object *objp)
|
||||
|
||||
wingnum = aip->wing;
|
||||
|
||||
if (((shipp->flags[Ship::Ship_Flags::Afterburner_locked]) || !(sip->flags[Ship::Info_Flags::Afterburner])) || (shipp->current_max_speed < 5.0f) || (objp->phys_info.afterburner_max_vel.xyz.z <= shipp->current_max_speed) || !(aip->ai_flags[AI::AI_Flags::Free_afterburner_use] || aip->ai_profile_flags[AI::Profile_Flags::Free_afterburner_use])) {
|
||||
if (((shipp->flags[Ship::Ship_Flags::Afterburner_locked]) || !(sip->flags[Ship::Info_Flags::Afterburner])) || (shipp->current_max_speed < 5.0f) || (objp->phys_info.afterburner_max_vel.xyz.z <= shipp->current_max_speed) || !(aip->ai_flags[AI::AI_Flags::Free_afterburner_use])) {
|
||||
lowest_max_av_ab_speed = shipp->current_max_speed;
|
||||
}
|
||||
else
|
||||
@@ -1821,7 +1814,7 @@ float get_wing_lowest_av_ab_speed(object *objp)
|
||||
if ((oaip->mode == AIM_WAYPOINTS) && (oaip->wing == wingnum) && (oaip->ai_flags[AI::AI_Flags::Formation_object, AI::AI_Flags::Formation_wing])) {
|
||||
|
||||
float cur_max;
|
||||
if ((oshipp->flags[Ship::Ship_Flags::Afterburner_locked]) || !(osip->flags[Ship::Info_Flags::Afterburner]) || (o->phys_info.afterburner_max_vel.xyz.z <= oshipp->current_max_speed) || !(oaip->ai_flags[AI::AI_Flags::Free_afterburner_use] || oaip->ai_profile_flags[AI::Profile_Flags::Free_afterburner_use])) {
|
||||
if ((oshipp->flags[Ship::Ship_Flags::Afterburner_locked]) || !(osip->flags[Ship::Info_Flags::Afterburner]) || (o->phys_info.afterburner_max_vel.xyz.z <= oshipp->current_max_speed) || !(oaip->ai_flags[AI::AI_Flags::Free_afterburner_use])) {
|
||||
cur_max = oshipp->current_max_speed;
|
||||
}
|
||||
else
|
||||
@@ -3455,6 +3448,35 @@ float compute_time_to_enemy(float dist_to_enemy, object *pobjp)
|
||||
return time_to_enemy + flFrametime;
|
||||
}
|
||||
|
||||
// Stuff *dot and *tts.
|
||||
// *dot is always computed. If dot is less than zero, the magnitude is
|
||||
// incorrect, not having been divided by distance.
|
||||
// If *dot is > 0.0f, then tts is computed. This is the time it will take object
|
||||
// *objp to get to *pos, assuming it moves right at it.
|
||||
void fds_aux(float *dot, float *tts, vec3d *pos, float dtime, object *objp)
|
||||
{
|
||||
vec3d v2s;
|
||||
|
||||
vm_vec_sub(&v2s, pos, &objp->pos);
|
||||
*dot = vm_vec_dot(&v2s, &objp->orient.vec.fvec);
|
||||
|
||||
if (*dot > 0.0f) {
|
||||
float dist;
|
||||
|
||||
dist = vm_vec_dist(&objp->pos, pos);
|
||||
|
||||
if (dist > 0.1f)
|
||||
*dot /= dist;
|
||||
else
|
||||
*dot = 1.0f;
|
||||
|
||||
if (objp->phys_info.speed > 0.1f)
|
||||
*tts = dist / objp->phys_info.speed;
|
||||
else
|
||||
*tts = dist * 100.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
void ai_set_positions(object *pl_objp, object *en_objp, ai_info *aip, vec3d *player_pos, vec3d *enemy_pos)
|
||||
{
|
||||
@@ -3870,7 +3892,7 @@ float ai_path_0()
|
||||
}
|
||||
|
||||
if (dist_to_goal > 0.1f)
|
||||
ai_turn_towards_vector(&gcvp, Pl_objp, sip->srotation_time, slop_vec, nullptr, 0.0f, 0);
|
||||
ai_turn_towards_vector(&gcvp, Pl_objp, flFrametime, sip->srotation_time, slop_vec, NULL, 0.0f, 0);
|
||||
|
||||
// Code to control speed is MUCH less forgiving in path following than in waypoint
|
||||
// following. Must be very close to path or might hit objects.
|
||||
@@ -4012,10 +4034,10 @@ float ai_path_1()
|
||||
if (r <= 1.0f) {
|
||||
vec3d midpoint;
|
||||
vm_vec_avg3(&midpoint, &gcvp, &closest_point, &closest_point);
|
||||
ai_turn_towards_vector(&midpoint, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0, prvec);
|
||||
ai_turn_towards_vector(&midpoint, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0, prvec);
|
||||
}
|
||||
else {
|
||||
ai_turn_towards_vector(&gcvp, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0, prvec);
|
||||
ai_turn_towards_vector(&gcvp, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0, prvec);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4360,11 +4382,11 @@ void ai_fly_to_target_position(vec3d* target_pos, bool* pl_done_p=NULL, bool* pl
|
||||
vm_vector_2_matrix(&Pl_objp->orient, &perp, NULL, NULL);
|
||||
} else {
|
||||
vm_vec_scale_add(&perp, &Pl_objp->pos, &Autopilot_flight_leader->phys_info.vel, 1000.0f);
|
||||
ai_turn_towards_vector(&perp, Pl_objp, sip->srotation_time*3.0f*scale, slop_vec, nullptr, 0.0f, 0);
|
||||
ai_turn_towards_vector(&perp, Pl_objp, flFrametime, sip->srotation_time*3.0f*scale, slop_vec, NULL, 0.0f, 0);
|
||||
}
|
||||
} else {
|
||||
if (dist_to_goal > 0.1f) {
|
||||
ai_turn_towards_vector(target_pos, Pl_objp, sip->srotation_time*3.0f*scale, slop_vec, nullptr, 0.0f, 0);
|
||||
ai_turn_towards_vector(target_pos, Pl_objp, flFrametime, sip->srotation_time*3.0f*scale, slop_vec, NULL, 0.0f, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4418,7 +4440,7 @@ void ai_fly_to_target_position(vec3d* target_pos, bool* pl_done_p=NULL, bool* pl
|
||||
ab_allowed = false;
|
||||
}
|
||||
|
||||
if (!(sip->flags[Ship::Info_Flags::Afterburner]) || (shipp->flags[Ship::Ship_Flags::Afterburner_locked]) || !(aip->ai_flags[AI::AI_Flags::Free_afterburner_use] || aip->ai_profile_flags[AI::Profile_Flags::Free_afterburner_use])) {
|
||||
if (!(sip->flags[Ship::Info_Flags::Afterburner]) || (shipp->flags[Ship::Ship_Flags::Afterburner_locked]) || !(aip->ai_flags[AI::AI_Flags::Free_afterburner_use])) {
|
||||
ab_allowed = false;
|
||||
}
|
||||
|
||||
@@ -4589,11 +4611,6 @@ void ai_waypoints()
|
||||
ai_mission_wing_goal_complete( Ships[Pl_objp->instance].wingnum, &(aip->goals[aip->active_goal]) );
|
||||
mission_log_add_entry( LOG_WAYPOINTS_DONE, Wings[Ships[Pl_objp->instance].wingnum].name, aip->wp_list->get_name(), -1 );
|
||||
}
|
||||
// adds scripting hook for 'On Waypoints Done' --wookieejedi
|
||||
Script_system.SetHookObject("Ship", &Objects[Ships[Pl_objp->instance].objnum]);
|
||||
Script_system.SetHookVar("Wing", 'o', scripting::api::l_Wing.Set(Ships[Pl_objp->instance].wingnum));
|
||||
Script_system.RunCondition(CHA_ONWAYPOINTSDONE);
|
||||
Script_system.RemHookVars(2, "Ship", "Wing");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5034,7 +5051,7 @@ void slide_face_ship()
|
||||
|
||||
dist = vm_vec_normalized_dir(&vec_from_enemy, &Pl_objp->pos, &En_objp->pos);
|
||||
|
||||
ai_turn_towards_vector(&En_objp->pos, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0);
|
||||
ai_turn_towards_vector(&En_objp->pos, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0);
|
||||
|
||||
dot_from_enemy = vm_vec_dot(&vec_from_enemy, &En_objp->orient.vec.fvec);
|
||||
|
||||
@@ -5217,7 +5234,7 @@ vec3d G_predicted_pos, G_fire_pos;
|
||||
// Else
|
||||
// Select Any ol' weapon.
|
||||
// Returns primary_bank index.
|
||||
static int ai_select_primary_weapon_OLD(const object *objp, Weapon::Info_Flags flags)
|
||||
int ai_select_primary_weapon_OLD(object *objp, object *other_objp, Weapon::Info_Flags flags)
|
||||
{
|
||||
ship *shipp = &Ships[objp->instance];
|
||||
ship_weapon *swp = &shipp->weapons;
|
||||
@@ -5308,7 +5325,7 @@ int ai_select_primary_weapon(object *objp, object *other_objp, Weapon::Info_Flag
|
||||
//not using the new AI, use the old version of this function instead.
|
||||
if (!(Ai_info[shipp->ai_index].ai_profile_flags[AI::Profile_Flags::Smart_primary_weapon_selection]))
|
||||
{
|
||||
return ai_select_primary_weapon_OLD(objp, flags);
|
||||
return ai_select_primary_weapon_OLD(objp, other_objp, flags);
|
||||
}
|
||||
|
||||
Assert( shipp->ship_info_index >= 0 && shipp->ship_info_index < static_cast<int>(Ship_info.size()));
|
||||
@@ -5354,7 +5371,7 @@ int ai_select_primary_weapon(object *objp, object *other_objp, Weapon::Info_Flag
|
||||
if (Weapon_info[swp->primary_bank_weapons[i]].wi_flags[Weapon::Info_Flags::Capital_plus])
|
||||
{
|
||||
swp->current_primary_bank = i;
|
||||
nprintf(("AI", "%i: Ship %s selecting weapon %s (capital+) vs target %s\n", Framecount, Ships[objp->instance].ship_name, Weapon_info[swp->primary_bank_weapons[i]].name, Ships[other_objp->instance].ship_name));
|
||||
nprintf(("AI", "%i: Ship %s selecting weapon %s\n", Framecount, Ships[objp->instance].ship_name, Weapon_info[swp->primary_bank_weapons[i]].name));
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@@ -5392,7 +5409,6 @@ int ai_select_primary_weapon(object *objp, object *other_objp, Weapon::Info_Flag
|
||||
i_hullfactor_prev_bank = 0; // Just switch to the first one
|
||||
}
|
||||
swp->current_primary_bank = i_hullfactor_prev_bank; // Select the best weapon
|
||||
nprintf(("AI", "%i: Ship %s selecting weapon %s (no shields) vs target %s\n", Framecount, Ships[objp->instance].ship_name, Weapon_info[swp->primary_bank_weapons[i_hullfactor_prev_bank]].name, (other_objp->type == OBJ_SHIP ? Ships[other_objp->instance].ship_name : "non-ship") ));
|
||||
return i_hullfactor_prev_bank; // Return
|
||||
}
|
||||
|
||||
@@ -5407,7 +5423,6 @@ int ai_select_primary_weapon(object *objp, object *other_objp, Weapon::Info_Flag
|
||||
|
||||
if ((Weapon_info[swp->primary_bank_weapons[bank_index]].wi_flags[Weapon::Info_Flags::Pierce_shields]) && !(Weapon_info[swp->primary_bank_weapons[bank_index]].wi_flags[Weapon::Info_Flags::Capital_plus]))
|
||||
{
|
||||
nprintf(("AI", "%i: Ship %s selecting weapon %s (>10%% shields)\n", Framecount, Ships[objp->instance].ship_name, Weapon_info[swp->primary_bank_weapons[bank_index]].name));
|
||||
return swp->current_primary_bank;
|
||||
}
|
||||
}
|
||||
@@ -5422,7 +5437,6 @@ int ai_select_primary_weapon(object *objp, object *other_objp, Weapon::Info_Flag
|
||||
if ((Weapon_info[weapon_info_index].wi_flags[Weapon::Info_Flags::Pierce_shields]) && !(Weapon_info[swp->primary_bank_weapons[i]].wi_flags[Weapon::Info_Flags::Capital_plus]))
|
||||
{
|
||||
swp->current_primary_bank = i;
|
||||
nprintf(("AI", "%i: Ship %s selecting weapon %s (>10%% shields)\n", Framecount, Ships[objp->instance].ship_name, Weapon_info[swp->primary_bank_weapons[i]].name));
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@@ -5457,7 +5471,6 @@ int ai_select_primary_weapon(object *objp, object *other_objp, Weapon::Info_Flag
|
||||
i_hullfactor_prev_bank = 0; // Just switch to the first one
|
||||
}
|
||||
swp->current_primary_bank = i_hullfactor_prev_bank; // Select the best weapon
|
||||
nprintf(("AI", "%i: Ship %s selecting weapon %s (<50%% shields)\n", Framecount, Ships[objp->instance].ship_name, Weapon_info[swp->primary_bank_weapons[i_hullfactor_prev_bank]].name));
|
||||
return i_hullfactor_prev_bank; // Return
|
||||
}
|
||||
else
|
||||
@@ -5487,7 +5500,6 @@ int ai_select_primary_weapon(object *objp, object *other_objp, Weapon::Info_Flag
|
||||
i_hullfactor_prev_bank = 0; // Just switch to the first one
|
||||
}
|
||||
swp->current_primary_bank = i_hullfactor_prev_bank; // Select the best weapon
|
||||
nprintf(("AI", "%i: Ship %s selecting weapon %s (>50%% shields)\n", Framecount, Ships[objp->instance].ship_name, Weapon_info[swp->primary_bank_weapons[i_hullfactor_prev_bank]].name));
|
||||
return i_hullfactor_prev_bank; // Return
|
||||
}
|
||||
}
|
||||
@@ -5515,9 +5527,7 @@ void set_primary_weapon_linkage(object *objp)
|
||||
// If trying to destroy a big ship (i.e., not disable/disarm), always unleash all weapons
|
||||
if ( Ship_info[Ships[Objects[aip->target_objnum].instance].ship_info_index].is_big_ship() ) {
|
||||
if ( aip->targeted_subsys == NULL ) {
|
||||
if (!sip->flags[Ship::Info_Flags::No_primary_linking] ) {
|
||||
shipp->flags.set(Ship::Ship_Flags::Primary_linked);
|
||||
}
|
||||
shipp->flags.set(Ship::Ship_Flags::Primary_linked);
|
||||
shipp->flags.set(Ship::Ship_Flags::Secondary_dual_fire);
|
||||
return;
|
||||
}
|
||||
@@ -6041,7 +6051,8 @@ int check_ok_to_fire(int objnum, int target_objnum, weapon_info *wip)
|
||||
// --------------------------------------------------------------------------
|
||||
// Fire a secondary weapon.
|
||||
// Maybe choose to fire a different one.
|
||||
int ai_fire_secondary_weapon(object *objp)
|
||||
// priority1 and priority2 are optional parameters with defaults = -1
|
||||
int ai_fire_secondary_weapon(object *objp, int priority1, int priority2)
|
||||
{
|
||||
ship_weapon *swp;
|
||||
ship *shipp;
|
||||
@@ -6061,7 +6072,7 @@ int ai_fire_secondary_weapon(object *objp)
|
||||
Assert( shipp->ship_info_index >= 0 && shipp->ship_info_index < static_cast<int>(Ship_info.size()));
|
||||
|
||||
// Select secondary weapon.
|
||||
current_bank = swp->current_secondary_bank;
|
||||
current_bank = swp->current_secondary_bank; //ai_select_secondary_weapon(objp, swp, priority1, priority2);
|
||||
|
||||
if (current_bank == -1) {
|
||||
return rval;
|
||||
@@ -6528,14 +6539,14 @@ void ai_chase_ct()
|
||||
vm_vec_add2(&tvec, &Pl_objp->orient.vec.rvec);
|
||||
}
|
||||
|
||||
ai_turn_towards_vector(&tvec, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0);
|
||||
ai_turn_towards_vector(&tvec, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0);
|
||||
accelerate_ship(aip, 1.0f);
|
||||
}
|
||||
|
||||
/**
|
||||
* ATTACK submode handler for chase mode.
|
||||
*/
|
||||
static void ai_chase_eb(ai_info *aip, ship_info *sip, vec3d *predicted_enemy_pos)
|
||||
void ai_chase_eb(ai_info *aip, ship_info *sip, vec3d *predicted_enemy_pos, float dist_to_enemy)
|
||||
{
|
||||
vec3d _pep;
|
||||
float dot_to_enemy, dot_from_enemy;
|
||||
@@ -6547,7 +6558,7 @@ static void ai_chase_eb(ai_info *aip, ship_info *sip, vec3d *predicted_enemy_pos
|
||||
if ((dot_to_enemy > dot_from_enemy + 0.1f) || (dot_to_enemy > 0.9f))
|
||||
vm_vec_scale_add(&_pep, &Pl_objp->pos, &En_objp->orient.vec.fvec, 100.0f);
|
||||
|
||||
ai_turn_towards_vector(&_pep, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0);
|
||||
ai_turn_towards_vector(&_pep, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0);
|
||||
|
||||
accelerate_ship(aip, 0.0f);
|
||||
}
|
||||
@@ -6744,7 +6755,7 @@ void attack_set_accel(ai_info *aip, ship_info *sip, float dist_to_enemy, float d
|
||||
|
||||
// Pl_objp (aip) tries to get behind En_objp.
|
||||
// New on 2/21/98: If this ship can move backwards and slide, maybe do that to get behind.
|
||||
static void get_behind_ship(ai_info *aip, ship_info *sip)
|
||||
void get_behind_ship(ai_info *aip, ship_info *sip, float dist_to_enemy)
|
||||
{
|
||||
vec3d new_pos;
|
||||
float dot;
|
||||
@@ -6753,7 +6764,7 @@ static void get_behind_ship(ai_info *aip, ship_info *sip)
|
||||
vm_vec_normalized_dir(&vec_from_enemy, &Pl_objp->pos, &En_objp->pos);
|
||||
|
||||
vm_vec_scale_add(&new_pos, &En_objp->pos, &En_objp->orient.vec.fvec, -100.0f); // Pick point 100 units behind.
|
||||
ai_turn_towards_vector(&new_pos, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0);
|
||||
ai_turn_towards_vector(&new_pos, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0);
|
||||
|
||||
dot = vm_vec_dot(&vec_from_enemy, &En_objp->orient.vec.fvec);
|
||||
|
||||
@@ -6772,7 +6783,7 @@ int avoid_player(object *objp, vec3d *goal_pos)
|
||||
if (aip->ai_flags[AI::AI_Flags::Avoiding_small_ship]) {
|
||||
ship_info *sip = &Ship_info[Ships[objp->instance].ship_info_index];
|
||||
|
||||
ai_turn_towards_vector(&aip->avoid_goal_point, objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0);
|
||||
ai_turn_towards_vector(&aip->avoid_goal_point, objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0);
|
||||
accelerate_ship(aip, 0.5f);
|
||||
return 1;
|
||||
}
|
||||
@@ -6970,7 +6981,7 @@ int maybe_avoid_big_ship(object *objp, object *ignore_objp, ai_info *aip, vec3d
|
||||
|
||||
vec3d v2g;
|
||||
|
||||
ai_turn_towards_vector(&aip->avoid_goal_point, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0);
|
||||
ai_turn_towards_vector(&aip->avoid_goal_point, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0);
|
||||
vm_vec_normalized_dir(&v2g, &aip->avoid_goal_point, &Pl_objp->pos);
|
||||
float dot = vm_vec_dot(&objp->orient.vec.fvec, &v2g);
|
||||
float d2 = (1.0f + dot) * (1.0f + dot);
|
||||
@@ -7062,7 +7073,7 @@ void ai_stealth_find()
|
||||
}
|
||||
}
|
||||
|
||||
ai_turn_towards_vector(&new_pos, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0);
|
||||
ai_turn_towards_vector(&new_pos, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -7072,9 +7083,9 @@ void ai_stealth_find()
|
||||
if (dist_to_enemy > 500.0f) {
|
||||
vec3d rvec;
|
||||
compute_desired_rvec(&rvec, &new_pos, &Pl_objp->pos);
|
||||
ai_turn_towards_vector(&new_pos, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0, &rvec);
|
||||
ai_turn_towards_vector(&new_pos, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0, &rvec);
|
||||
} else {
|
||||
ai_turn_towards_vector(&new_pos, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0);
|
||||
ai_turn_towards_vector(&new_pos, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0);
|
||||
}
|
||||
|
||||
dot_from_enemy = -vm_vec_dot(&vec_to_enemy, &En_objp->orient.vec.fvec);
|
||||
@@ -7202,7 +7213,7 @@ void ai_stealth_sweep()
|
||||
return;
|
||||
}
|
||||
|
||||
ai_turn_towards_vector(&goal_pt, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0);
|
||||
ai_turn_towards_vector(&goal_pt, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0);
|
||||
|
||||
float dot = 1.0f;
|
||||
if (dist_to_goal < 100) {
|
||||
@@ -7262,9 +7273,9 @@ void ai_chase_attack(ai_info *aip, ship_info *sip, vec3d *predicted_enemy_pos, f
|
||||
if (dist_to_enemy > 500.0f) {
|
||||
vec3d rvec;
|
||||
compute_desired_rvec(&rvec, predicted_enemy_pos, &Pl_objp->pos);
|
||||
ai_turn_towards_vector(&new_pos, Pl_objp, sip->srotation_time, nullptr, rel_pos, bank_override, 0, &rvec);
|
||||
ai_turn_towards_vector(&new_pos, Pl_objp, flFrametime, sip->srotation_time, NULL, rel_pos, bank_override, 0, &rvec);
|
||||
} else {
|
||||
ai_turn_towards_vector(&new_pos, Pl_objp, sip->srotation_time, nullptr, rel_pos, bank_override, 0);
|
||||
ai_turn_towards_vector(&new_pos, Pl_objp, flFrametime, sip->srotation_time, NULL, rel_pos, bank_override, 0);
|
||||
}
|
||||
|
||||
attack_set_accel(aip, sip, dist_to_enemy, dot_to_enemy, dot_from_enemy);
|
||||
@@ -7302,7 +7313,7 @@ void ai_chase_es(ai_info *aip, ship_info *sip)
|
||||
|
||||
float bank_override = Pl_objp->phys_info.speed;
|
||||
|
||||
ai_turn_towards_vector(&tvec, Pl_objp, sip->srotation_time, nullptr, nullptr, bank_override, 0);
|
||||
ai_turn_towards_vector(&tvec, Pl_objp, flFrametime/2, sip->srotation_time, NULL, NULL, bank_override, 0);
|
||||
accelerate_ship(aip, 1.0f);
|
||||
}
|
||||
|
||||
@@ -7328,7 +7339,7 @@ void ai_chase_ga(ai_info *aip, ship_info *sip)
|
||||
|
||||
bank_override = Pl_objp->phys_info.speed;
|
||||
|
||||
ai_turn_towards_vector(&tvec, Pl_objp, sip->srotation_time, nullptr, nullptr, bank_override, 0);
|
||||
ai_turn_towards_vector(&tvec, Pl_objp, flFrametime/2, sip->srotation_time, NULL, NULL, bank_override, 0);
|
||||
|
||||
accelerate_ship(aip, 2.0f);
|
||||
|
||||
@@ -7493,6 +7504,32 @@ void ai_set_guard_wing(object *objp, int wingnum)
|
||||
}
|
||||
}
|
||||
|
||||
// Make object *objp guard object *other_objp.
|
||||
// To be called from the goals code.
|
||||
void ai_set_evade_object(object *objp, object *other_objp)
|
||||
{
|
||||
ship *shipp;
|
||||
ai_info *aip;
|
||||
int other_objnum;
|
||||
|
||||
Assert(objp->type == OBJ_SHIP);
|
||||
Assert(objp->instance >= 0);
|
||||
|
||||
shipp = &Ships[objp->instance];
|
||||
|
||||
Assert(shipp->ai_index >= 0);
|
||||
|
||||
aip = &Ai_info[shipp->ai_index];
|
||||
|
||||
other_objnum = OBJ_INDEX(other_objp);
|
||||
Assert(other_objnum >= 0);
|
||||
|
||||
Assert(other_objnum != Ships[aip->shipnum].objnum); // make sure not targeting self
|
||||
aip->target_objnum = other_objnum;
|
||||
|
||||
aip->mode = AIM_EVADE;
|
||||
}
|
||||
|
||||
// Make objp guard other_objp
|
||||
// If other_objp is a member of a wing, objp will guard that whole wing
|
||||
// UNLESS objp is also a member of the wing!
|
||||
@@ -7964,7 +8001,7 @@ void ai_cruiser_chase()
|
||||
|
||||
// kamikaze - ram and explode
|
||||
if (aip->ai_flags[AI::AI_Flags::Kamikaze]) {
|
||||
ai_turn_towards_vector(&En_objp->pos, Pl_objp, turn_time, nullptr, nullptr, 0.0f, 0);
|
||||
ai_turn_towards_vector(&En_objp->pos, Pl_objp, flFrametime, turn_time, NULL, NULL, 0.0f, 0);
|
||||
accelerate_ship(aip, 1.0f);
|
||||
}
|
||||
|
||||
@@ -8004,7 +8041,7 @@ void ai_cruiser_chase()
|
||||
}
|
||||
|
||||
// now move as desired
|
||||
ai_turn_towards_vector(&goal_pos, Pl_objp, turn_time, nullptr, nullptr, 0.0f, 0, rvecp);
|
||||
ai_turn_towards_vector(&goal_pos, Pl_objp, flFrametime, turn_time, NULL, NULL, 0.0f, 0, rvecp);
|
||||
accelerate_ship(aip, accel);
|
||||
|
||||
// maybe switch to new mode
|
||||
@@ -8285,7 +8322,7 @@ void ai_chase()
|
||||
break;
|
||||
|
||||
case SM_EVADE_BRAKE:
|
||||
ai_chase_eb(aip, sip, &predicted_enemy_pos);
|
||||
ai_chase_eb(aip, sip, &predicted_enemy_pos, dist_to_enemy);
|
||||
break;
|
||||
|
||||
case SM_EVADE:
|
||||
@@ -8297,7 +8334,7 @@ void ai_chase()
|
||||
break;
|
||||
|
||||
case SM_GET_BEHIND:
|
||||
get_behind_ship(aip, sip);
|
||||
get_behind_ship(aip, sip, dist_to_enemy);
|
||||
break;
|
||||
|
||||
case SM_GET_AWAY: // Used to get away from opponent to prevent endless circling.
|
||||
@@ -8731,11 +8768,7 @@ void ai_chase()
|
||||
scale = (scale - 0.6f) * 1.5f;
|
||||
else
|
||||
scale = 0.0f;
|
||||
float range = pwip->max_speed * (1.0f + scale);
|
||||
if (aip->ai_profile_flags[AI::Profile_Flags::Use_actual_primary_range]) {
|
||||
range = std::min( {range, pwip->max_speed * pwip->lifetime, pwip->weapon_range} );
|
||||
}
|
||||
if (dist_to_enemy < range) {
|
||||
if (dist_to_enemy < pwip->max_speed * (1.0f + scale)) {
|
||||
if(ai_fire_primary_weapon(Pl_objp) == 1){
|
||||
has_fired = 1;
|
||||
}else{
|
||||
@@ -9296,7 +9329,7 @@ float dock_orient_and_approach(object *docker_objp, int docker_index, object *do
|
||||
{
|
||||
float dot, accel;
|
||||
float turn_time = Ship_info[Ships[docker_objp->instance].ship_info_index].srotation_time;
|
||||
ai_turn_towards_vector(&goal_point, docker_objp, turn_time, nullptr, nullptr, 0.0f, 0);
|
||||
ai_turn_towards_vector(&goal_point, docker_objp, flFrametime, turn_time, NULL, NULL, 0.0f, 0);
|
||||
|
||||
dot = vm_vec_dot(&docker_objp->orient.vec.fvec, &away_vec);
|
||||
accel = 0.1f;
|
||||
@@ -9931,10 +9964,10 @@ void ai_big_guard()
|
||||
}
|
||||
|
||||
// got the point, now let's go there
|
||||
ai_turn_towards_vector(&goal_pt, Pl_objp, Ship_info[Ships[Pl_objp->instance].ship_info_index].srotation_time, nullptr, nullptr, 0.0f, 0);
|
||||
ai_turn_towards_vector(&goal_pt, Pl_objp, flFrametime, Ship_info[Ships[Pl_objp->instance].ship_info_index].srotation_time, NULL, NULL, 0.0f, 0);
|
||||
accelerate_ship(aip, 1.0f);
|
||||
|
||||
if ((aip->ai_flags[AI::AI_Flags::Free_afterburner_use] || aip->ai_profile_flags[AI::Profile_Flags::Free_afterburner_use]) && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) && (cur_guard_rad > 1.1f * max_guard_dist)) {
|
||||
if ((aip->ai_flags[AI::AI_Flags::Free_afterburner_use]) && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) && (cur_guard_rad > 1.1f * max_guard_dist)) {
|
||||
vec3d v2g;
|
||||
float dot_to_goal_point;
|
||||
|
||||
@@ -10055,9 +10088,9 @@ void ai_guard()
|
||||
|
||||
// quite far away, so try to go straight to
|
||||
compute_desired_rvec(&rvec, &goal_point, &Pl_objp->pos);
|
||||
ai_turn_towards_vector(&goal_point, Pl_objp, Ship_info[shipp->ship_info_index].srotation_time, nullptr, nullptr, 0.0f, 0, &rvec);
|
||||
ai_turn_towards_vector(&goal_point, Pl_objp, flFrametime, Ship_info[shipp->ship_info_index].srotation_time, NULL, NULL, 0.0f, 0, &rvec);
|
||||
|
||||
if ((aip->ai_flags[AI::AI_Flags::Free_afterburner_use] || aip->ai_profile_flags[AI::Profile_Flags::Free_afterburner_use]) && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) && (accel_scale * (0.25f + dist_to_goal_point/700.0f) > 0.8f)) {
|
||||
if ((aip->ai_flags[AI::AI_Flags::Free_afterburner_use]) && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) && (accel_scale * (0.25f + dist_to_goal_point/700.0f) > 0.8f)) {
|
||||
if (ai_maybe_fire_afterburner(Pl_objp, aip)) {
|
||||
afterburners_start(Pl_objp);
|
||||
aip->afterburner_stop_time = Missiontime + 3*F1_0;
|
||||
@@ -10680,8 +10713,8 @@ void ai_dock()
|
||||
char *goal_ship_class_name = goal_sip->name;
|
||||
char *goal_dock_path_name = model_get(goal_sip->model_num)->paths[aip->mp_index].name;
|
||||
|
||||
mprintf(("Ship class %s has only %i points on dock path \"%s\". Recommended minimum number of points is 4. "\
|
||||
"Docking along that path will look strange. You may wish to edit the model.", goal_ship_class_name, aip->path_length, goal_dock_path_name));
|
||||
Warning(LOCATION, "Ship class %s has only %i points on dock path \"%s\". Recommended minimum number of points is 4. "\
|
||||
"Docking along that path will look strange. You may wish to edit the model.", goal_ship_class_name, aip->path_length, goal_dock_path_name);
|
||||
}
|
||||
|
||||
aip->submode = AIS_DOCK_1;
|
||||
@@ -10806,7 +10839,7 @@ void ai_dock()
|
||||
|
||||
if (aip->submode == AIS_DOCK_3) {
|
||||
// Play a ship docking attach sound
|
||||
snd_play_3d( gamesnd_get_game_sound(GameSounds::DOCK_ATTACH), &Pl_objp->pos, &View_position );
|
||||
snd_play_3d( gamesnd_get_game_sound(SND_DOCK_ATTACH), &Pl_objp->pos, &View_position );
|
||||
|
||||
// start the dock animation
|
||||
model_anim_start_type(shipp, TRIGGER_TYPE_DOCKED, docker_index, 1);
|
||||
@@ -10933,7 +10966,7 @@ void ai_dock()
|
||||
ai_find_path(Pl_objp, OBJ_INDEX(goal_objp), path_num, 0);
|
||||
|
||||
// Play a ship docking detach sound
|
||||
snd_play_3d( gamesnd_get_game_sound(GameSounds::DOCK_DETACH), &Pl_objp->pos, &View_position );
|
||||
snd_play_3d( gamesnd_get_game_sound(SND_DOCK_DETACH), &Pl_objp->pos, &View_position );
|
||||
|
||||
aip->submode = AIS_UNDOCK_1;
|
||||
aip->submode_start_time = Missiontime;
|
||||
@@ -10953,7 +10986,7 @@ void ai_dock()
|
||||
// play the depart sound, but only once, since this mode is called multiple times per frame
|
||||
if ( !(aigp->flags[AI::Goal_Flags::Depart_sound_played]))
|
||||
{
|
||||
snd_play_3d( gamesnd_get_game_sound(GameSounds::DOCK_DEPART), &Pl_objp->pos, &View_position );
|
||||
snd_play_3d( gamesnd_get_game_sound(SND_DOCK_DEPART), &Pl_objp->pos, &View_position );
|
||||
aigp->flags.set(AI::Goal_Flags::Depart_sound_played);
|
||||
}
|
||||
|
||||
@@ -11352,7 +11385,7 @@ float gwlr_1(object *objp, ai_info *aip)
|
||||
/**
|
||||
* Compute the largest radius of a ship forming on *objp's wing.
|
||||
*/
|
||||
static float gwlr_object_1(object *objp)
|
||||
float gwlr_object_1(object *objp, ai_info *aip)
|
||||
{
|
||||
float max_radius;
|
||||
object *o;
|
||||
@@ -11385,7 +11418,7 @@ float get_wing_largest_radius(object *objp, int formation_object_flag)
|
||||
aip = &Ai_info[shipp->ai_index];
|
||||
|
||||
if (formation_object_flag) {
|
||||
return gwlr_object_1(objp);
|
||||
return gwlr_object_1(objp, aip);
|
||||
} else {
|
||||
return gwlr_1(objp, aip);
|
||||
}
|
||||
@@ -11527,6 +11560,53 @@ void render_wing_phantoms_all()
|
||||
|
||||
#endif
|
||||
|
||||
// Hook from goals code to AI.
|
||||
// Force a wing to fly in formation.
|
||||
// Sets AIF_FORMATION bit in ai_flags.
|
||||
// wingnum Wing to force to fly in formation
|
||||
void ai_fly_in_formation(int wingnum)
|
||||
{
|
||||
object *objp;
|
||||
ship *shipp;
|
||||
ship_obj *so;
|
||||
|
||||
for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
|
||||
objp = &Objects[so->objnum];
|
||||
Assert((objp->instance >= 0) && (objp->instance < MAX_SHIPS));
|
||||
|
||||
shipp = &Ships[objp->instance];
|
||||
Assert((shipp->ai_index >= 0) && (shipp->ai_index < MAX_AI_INFO));
|
||||
|
||||
if (Ai_info[shipp->ai_index].wing == wingnum) {
|
||||
Ai_info[shipp->ai_index].ai_flags.set(AI::AI_Flags::Formation_wing);
|
||||
Ai_info[shipp->ai_index].ai_flags.remove(AI::AI_Flags::Formation_object);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Hook from goals code to AI.
|
||||
// Force a wing to abandon formation flying.
|
||||
// Clears AIF_FORMATION bit in ai_flags.
|
||||
// wingnum Wing to force to fly in formation
|
||||
void ai_disband_formation(int wingnum)
|
||||
{
|
||||
object *objp;
|
||||
ship *shipp;
|
||||
ship_obj *so;
|
||||
|
||||
for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
|
||||
objp = &Objects[so->objnum];
|
||||
Assert((objp->instance >= 0) && (objp->instance < MAX_SHIPS));
|
||||
|
||||
shipp = &Ships[objp->instance];
|
||||
Assert((shipp->ai_index >= 0) && (shipp->ai_index < MAX_AI_INFO));
|
||||
|
||||
if (Ai_info[shipp->ai_index].wing == wingnum) {
|
||||
Ai_info[shipp->ai_index].ai_flags.remove(AI::AI_Flags::Formation_wing);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float Leader_chaos = 0.0f;
|
||||
int Chaos_frame = -1;
|
||||
|
||||
@@ -11728,7 +11808,7 @@ int ai_formation()
|
||||
|
||||
ship_info *sip = &Ship_info[shipp->ship_info_index];
|
||||
bool ab_allowed = false;
|
||||
if ((sip->flags[Ship::Info_Flags::Afterburner]) && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) && (aip->ai_flags[AI::AI_Flags::Free_afterburner_use] || aip->ai_profile_flags[AI::Profile_Flags::Free_afterburner_use])) {
|
||||
if ((sip->flags[Ship::Info_Flags::Afterburner]) && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) && (aip->ai_flags[AI::AI_Flags::Free_afterburner_use])) {
|
||||
ab_allowed = true;
|
||||
} else {
|
||||
if (Pl_objp->phys_info.flags & PF_AFTERBURNER_ON)
|
||||
@@ -12111,7 +12191,7 @@ void ai_maybe_launch_cmeasure(object *objp, ai_info *aip)
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
static void ai_preprocess_ignore_objnum(ai_info *aip)
|
||||
void ai_preprocess_ignore_objnum(object *objp, ai_info *aip)
|
||||
{
|
||||
if (aip->ai_flags[AI::AI_Flags::Temporary_ignore])
|
||||
{
|
||||
@@ -12944,7 +13024,7 @@ void ai_execute_behavior(ai_info *aip)
|
||||
ship *shipp = &Ships[aip->shipnum];
|
||||
ship_info *sip = &Ship_info[shipp->ship_info_index];
|
||||
|
||||
if (strnicmp(shipp->ship_name, INSTRUCTOR_SHIP_NAME, strlen(INSTRUCTOR_SHIP_NAME)) != 0) {
|
||||
if (strnicmp(shipp->ship_name, INSTRUCTOR_SHIP_NAME, strlen(INSTRUCTOR_SHIP_NAME))) {
|
||||
if (sip->is_big_or_huge()) {
|
||||
aip->mode = AIM_NONE;
|
||||
} else {
|
||||
@@ -12984,6 +13064,7 @@ void ai_execute_behavior(ai_info *aip)
|
||||
case AIM_NONE:
|
||||
break;
|
||||
case AIM_BIGSHIP:
|
||||
ai_big_ship(Pl_objp);
|
||||
break;
|
||||
case AIM_PATH: {
|
||||
int path_num;
|
||||
@@ -13301,7 +13382,7 @@ void ai_warp_out(object *objp)
|
||||
case AIS_WARP_2: // Make sure won't collide with any object.
|
||||
if (timestamp_elapsed(aip->force_warp_time)
|
||||
|| (!collide_predict_large_ship(objp, objp->radius*2.0f + 100.0f)
|
||||
|| (Warp_params[shipp->warpout_params_index].warp_type == WT_HYPERSPACE
|
||||
|| (Ship_info[shipp->ship_info_index].warpout_type == WT_HYPERSPACE
|
||||
&& !collide_predict_large_ship(objp, 100000.0f)))) {
|
||||
aip->submode = AIS_WARP_3;
|
||||
aip->submode_start_time = Missiontime;
|
||||
@@ -13344,7 +13425,7 @@ void ai_warp_out(object *objp)
|
||||
break;
|
||||
case AIS_WARP_4: {
|
||||
// Only lets the ship warp after waiting for the warpout engage time
|
||||
if ( (Missiontime / 100) >= (aip->submode_start_time / 100 + Warp_params[shipp->warpout_params_index].warpout_engage_time) ) {
|
||||
if ( (Missiontime / 100) >= (aip->submode_start_time / 100 + Ship_info[shipp->ship_info_index].warpout_engage_time) ) {
|
||||
shipfx_warpout_start(objp);
|
||||
aip->submode = AIS_WARP_5;
|
||||
aip->submode_start_time = Missiontime;
|
||||
@@ -13360,7 +13441,7 @@ void ai_warp_out(object *objp)
|
||||
|
||||
// Return object index of weapon that could produce a shockwave that should be known about to *objp.
|
||||
// Return nearest one.
|
||||
static int ai_find_shockwave_weapon(const object *objp)
|
||||
int ai_find_shockwave_weapon(object *objp, ai_info *aip)
|
||||
{
|
||||
missile_obj *mo;
|
||||
float nearest_dist = 999999.9f;
|
||||
@@ -13426,7 +13507,7 @@ void ai_announce_ship_dying(object *dying_objp)
|
||||
|
||||
// Return object index of weapon that could produce a shockwave that should be known about to *objp.
|
||||
// Return nearest one.
|
||||
static int ai_find_shockwave_ship(object *objp)
|
||||
int ai_find_shockwave_ship(object *objp, ai_info *aip)
|
||||
{
|
||||
ship_obj *so;
|
||||
float nearest_dist = 999999.9f;
|
||||
@@ -13469,7 +13550,7 @@ int aas_1(object *objp, ai_info *aip, vec3d *safe_pos)
|
||||
// If we don't currently know of a weapon to avoid, try to find one.
|
||||
// If we can't find one, then clear the bit so we don't keep coming here.
|
||||
if (aip->shockwave_object == -1) {
|
||||
int shockwave_weapon = ai_find_shockwave_weapon(objp);
|
||||
int shockwave_weapon = ai_find_shockwave_weapon(objp, aip);
|
||||
if (shockwave_weapon == -1) {
|
||||
aip->ai_flags.remove(AI::AI_Flags::Avoid_shockwave_weapon);
|
||||
return 0;
|
||||
@@ -13558,7 +13639,7 @@ int aas_1(object *objp, ai_info *aip, vec3d *safe_pos)
|
||||
}
|
||||
} else if (aip->ai_flags[AI::AI_Flags::Avoid_shockwave_ship]) {
|
||||
if (aip->shockwave_object == -1) {
|
||||
int shockwave_ship = ai_find_shockwave_ship(objp);
|
||||
int shockwave_ship = ai_find_shockwave_ship(objp, aip);
|
||||
if (shockwave_ship == -1) {
|
||||
aip->ai_flags.remove(AI::AI_Flags::Avoid_shockwave_ship);
|
||||
return 0;
|
||||
@@ -13788,7 +13869,7 @@ int maybe_big_ship_collide_recover_frame(object *objp, ai_info *aip)
|
||||
vec3d v2g;
|
||||
|
||||
if (aip->ai_flags[AI::AI_Flags::Big_ship_collide_recover_1]) {
|
||||
ai_turn_towards_vector(&aip->big_recover_pos_1, objp, Ship_info[Ships[objp->instance].ship_info_index].srotation_time, nullptr, nullptr, 0.0f, 0, nullptr);
|
||||
ai_turn_towards_vector(&aip->big_recover_pos_1, objp, flFrametime, Ship_info[Ships[objp->instance].ship_info_index].srotation_time, NULL, NULL, 0.0f, 0, NULL);
|
||||
dist = vm_vec_normalized_dir(&v2g, &aip->big_recover_pos_1, &objp->pos);
|
||||
dot = vm_vec_dot(&objp->orient.vec.fvec, &v2g);
|
||||
accelerate_ship(aip, dot);
|
||||
@@ -13802,7 +13883,7 @@ int maybe_big_ship_collide_recover_frame(object *objp, ai_info *aip)
|
||||
return 1;
|
||||
|
||||
} else if (aip->ai_flags[AI::AI_Flags::Big_ship_collide_recover_2]) {
|
||||
ai_turn_towards_vector(&aip->big_recover_pos_2, objp, Ship_info[Ships[objp->instance].ship_info_index].srotation_time, nullptr, nullptr, 0.0f, 0, nullptr);
|
||||
ai_turn_towards_vector(&aip->big_recover_pos_2, objp, flFrametime, Ship_info[Ships[objp->instance].ship_info_index].srotation_time, NULL, NULL, 0.0f, 0, NULL);
|
||||
dist = vm_vec_normalized_dir(&v2g, &aip->big_recover_pos_2, &objp->pos);
|
||||
dot = vm_vec_dot(&objp->orient.vec.fvec, &v2g);
|
||||
accelerate_ship(aip, dot);
|
||||
@@ -13922,7 +14003,7 @@ void ai_frame(int objnum)
|
||||
if (maybe_big_ship_collide_recover_frame(Pl_objp, aip))
|
||||
return;
|
||||
|
||||
ai_preprocess_ignore_objnum(aip);
|
||||
ai_preprocess_ignore_objnum(Pl_objp, aip);
|
||||
target_objnum = set_target_objnum(aip, aip->target_objnum);
|
||||
|
||||
Assert(objnum != target_objnum);
|
||||
@@ -14077,7 +14158,7 @@ void ai_frame(int objnum)
|
||||
}
|
||||
}
|
||||
|
||||
static void ai_control_info_check(ai_info *aip)
|
||||
void ai_control_info_check( object *obj, ai_info *aip )
|
||||
{
|
||||
if(aip->ai_override_flags.none_set())
|
||||
return;
|
||||
@@ -14178,7 +14259,7 @@ void ai_process( object * obj, int ai_index, float frametime )
|
||||
|
||||
if (rfc == 1) {
|
||||
// Wanderer - sexp based override goes here - only if rfc is valid though
|
||||
ai_control_info_check(aip);
|
||||
ai_control_info_check(obj, aip);
|
||||
vec3d copy_desired_rotvel = obj->phys_info.rotvel;
|
||||
physics_read_flying_controls( &obj->orient, &obj->phys_info, &AI_ci, frametime);
|
||||
// if obj is in formation and not flight leader, don't update rotvel
|
||||
@@ -14713,10 +14794,10 @@ int firing_aspect_seeking_bomb(object *objp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// *objp collided with big ship *big_objp at some global point.
|
||||
// Make it fly away from the collision point.
|
||||
// *objp collided with big ship *big_objp at global point *collide_pos
|
||||
// Make it fly away from the collision point.
|
||||
// collision_normal is NULL, when a collision is imminent and we just want to bug out.
|
||||
void big_ship_collide_recover_start(object *objp, object *big_objp, vec3d *collision_normal)
|
||||
void big_ship_collide_recover_start(object *objp, object *big_objp, vec3d *collide_pos, vec3d *collision_normal)
|
||||
{
|
||||
ai_info *aip;
|
||||
|
||||
@@ -14805,9 +14886,9 @@ void ai_update_lethality(object *pship_obj, object *other_obj, float damage)
|
||||
|
||||
|
||||
/**
|
||||
* Object *objp_ship was hit by either weapon *objp_weapon or collided into by ship hit_objp
|
||||
* Object *objp_ship was hit by either weapon *objp_weapon or collided into by ship hit_objp at point *hitpos.
|
||||
*/
|
||||
void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hit_normal)
|
||||
void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hitpos, int shield_quadrant, vec3d *hit_normal)
|
||||
{
|
||||
int hitter_objnum = -2;
|
||||
object *objp_hitter = NULL;
|
||||
@@ -14849,7 +14930,7 @@ void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hit_normal)
|
||||
// And the current object is _not_ a big ship
|
||||
if (!Ship_info[Ships[objp_ship->instance].ship_info_index].is_big_or_huge()) {
|
||||
// Recover from hitting a big ship. Note, if two big ships collide, they just pound away at each other. Oh well. Recovery looks dumb and it's very late.
|
||||
big_ship_collide_recover_start(objp_ship, hit_objp, hit_normal);
|
||||
big_ship_collide_recover_start(objp_ship, hit_objp, hitpos, hit_normal);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14986,7 +15067,7 @@ void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hit_normal)
|
||||
return;
|
||||
|
||||
if ( (hit_objp->type == OBJ_WEAPON) && !(aip->ai_flags[AI::AI_Flags::No_dynamic]) ) {
|
||||
if ( ai_big_maybe_enter_strafe_mode(objp_ship, OBJ_INDEX(hit_objp)) )
|
||||
if ( ai_big_maybe_enter_strafe_mode(objp_ship, OBJ_INDEX(hit_objp), 1) )
|
||||
return;
|
||||
}
|
||||
break;
|
||||
@@ -15106,7 +15187,10 @@ void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hit_normal)
|
||||
|
||||
// Ship shipnum has been destroyed.
|
||||
// Cleanup.
|
||||
void ai_ship_destroy(int shipnum)
|
||||
// the parameter 'method' is used to tell is this ship was destroyed or it departed normally.
|
||||
// This function will get called in either case, and there are things that should be done if
|
||||
// the ship actually gets destroyed which shouldn't get done if it departed.
|
||||
void ai_ship_destroy(int shipnum, Ship::Exit_Flags method)
|
||||
{
|
||||
int objnum;
|
||||
object *other_objp;
|
||||
@@ -15357,7 +15441,7 @@ int ai_issue_rearm_request(object *requester_objp)
|
||||
// we aren't able to do anything!
|
||||
else {
|
||||
Assert(result == 4);
|
||||
UNREACHABLE("This case should have already been caught by the is_support_allowed precheck!");
|
||||
Assertion(false, "This case should have already been caught by the is_support_allowed precheck!");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -15426,7 +15510,7 @@ int ai_return_path_num_from_dockbay(object *dockee_objp, int dockbay_index)
|
||||
/**
|
||||
* Actually go ahead and fire the synaptics.
|
||||
*/
|
||||
static void cheat_fire_synaptic(object *objp, ship *shipp)
|
||||
void cheat_fire_synaptic(object *objp, ship *shipp, ai_info *aip)
|
||||
{
|
||||
ship_weapon *swp;
|
||||
swp = &shipp->weapons;
|
||||
@@ -15448,7 +15532,7 @@ static void cheat_fire_synaptic(object *objp, ship *shipp)
|
||||
// if they're near one or more enemies
|
||||
// every so often
|
||||
// fire a synaptic if they have one.
|
||||
void maybe_cheat_fire_synaptic(object *objp)
|
||||
void maybe_cheat_fire_synaptic(object *objp, ai_info *aip)
|
||||
{
|
||||
// Only do in subspace missions.
|
||||
if (!(The_mission.flags[Mission::Mission_Flags::Subspace]))
|
||||
@@ -15480,7 +15564,7 @@ void maybe_cheat_fire_synaptic(object *objp)
|
||||
int count = num_nearby_fighters(iff_get_attackee_mask(obj_team(objp)), &objp->pos, 1500.0f);
|
||||
|
||||
if (count > 0)
|
||||
cheat_fire_synaptic(objp, shipp);
|
||||
cheat_fire_synaptic(objp, shipp, aip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+51
-58
@@ -62,32 +62,31 @@ char Ai_dock_names[MAX_AI_DOCK_NAMES][NAME_LENGTH];
|
||||
// Used in objecttypes.tbl to define custom ship types
|
||||
ai_goal_list Ai_goal_names[] =
|
||||
{
|
||||
{ "Attack ship", AI_GOAL_CHASE, 0 },
|
||||
{ "Dock", AI_GOAL_DOCK, 0 },
|
||||
{ "Waypoints", AI_GOAL_WAYPOINTS, 0 },
|
||||
{ "Waypoints once", AI_GOAL_WAYPOINTS_ONCE, 0 },
|
||||
{ "Depart", AI_GOAL_WARP, 0 },
|
||||
{ "Attack subsys", AI_GOAL_DESTROY_SUBSYSTEM, 0 },
|
||||
{ "Form on wing", AI_GOAL_FORM_ON_WING, 0 },
|
||||
{ "Undock", AI_GOAL_UNDOCK, 0 },
|
||||
{ "Attack wing", AI_GOAL_CHASE_WING, 0 },
|
||||
{ "Guard ship", AI_GOAL_GUARD, 0 },
|
||||
{ "Disable ship", AI_GOAL_DISABLE_SHIP, 0 },
|
||||
{ "Disarm ship", AI_GOAL_DISARM_SHIP, 0 },
|
||||
{ "Attack any", AI_GOAL_CHASE_ANY, 0 },
|
||||
{ "Ignore ship", AI_GOAL_IGNORE, 0 },
|
||||
{ "Ignore ship (new)", AI_GOAL_IGNORE_NEW, 0 },
|
||||
{ "Guard wing", AI_GOAL_GUARD_WING, 0 },
|
||||
{ "Evade ship", AI_GOAL_EVADE_SHIP, 0 },
|
||||
{ "Stay near ship", AI_GOAL_STAY_NEAR_SHIP, 0 },
|
||||
{ "keep safe dist", AI_GOAL_KEEP_SAFE_DISTANCE, 0 },
|
||||
{ "Rearm ship", AI_GOAL_REARM_REPAIR, 0 },
|
||||
{ "Stay still", AI_GOAL_STAY_STILL, 0 },
|
||||
{ "Play dead", AI_GOAL_PLAY_DEAD, 0 },
|
||||
{ "Play dead (persistent)", AI_GOAL_PLAY_DEAD_PERSISTENT, 0 },
|
||||
{ "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", AI_GOAL_CHASE, 0 },
|
||||
{ "Dock", AI_GOAL_DOCK, 0 },
|
||||
{ "Waypoints", AI_GOAL_WAYPOINTS, 0 },
|
||||
{ "Waypoints once", AI_GOAL_WAYPOINTS_ONCE, 0 },
|
||||
{ "Depart", AI_GOAL_WARP, 0 },
|
||||
{ "Attack subsys", AI_GOAL_DESTROY_SUBSYSTEM, 0 },
|
||||
{ "Form on wing", AI_GOAL_FORM_ON_WING, 0 },
|
||||
{ "Undock", AI_GOAL_UNDOCK, 0 },
|
||||
{ "Attack wing", AI_GOAL_CHASE_WING, 0 },
|
||||
{ "Guard ship", AI_GOAL_GUARD, 0 },
|
||||
{ "Disable ship", AI_GOAL_DISABLE_SHIP, 0 },
|
||||
{ "Disarm ship", AI_GOAL_DISARM_SHIP, 0 },
|
||||
{ "Attack any", AI_GOAL_CHASE_ANY, 0 },
|
||||
{ "Ignore ship", AI_GOAL_IGNORE, 0 },
|
||||
{ "Ignore ship (new)", AI_GOAL_IGNORE_NEW, 0 },
|
||||
{ "Guard wing", AI_GOAL_GUARD_WING, 0 },
|
||||
{ "Evade ship", AI_GOAL_EVADE_SHIP, 0 },
|
||||
{ "Stay near ship", AI_GOAL_STAY_NEAR_SHIP, 0 },
|
||||
{ "keep safe dist", AI_GOAL_KEEP_SAFE_DISTANCE, 0 },
|
||||
{ "Rearm ship", AI_GOAL_REARM_REPAIR, 0 },
|
||||
{ "Stay still", AI_GOAL_STAY_STILL, 0 },
|
||||
{ "Play dead", AI_GOAL_PLAY_DEAD, 0 },
|
||||
{ "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 },
|
||||
};
|
||||
|
||||
int Num_ai_goals = sizeof(Ai_goal_names) / sizeof(ai_goal_list);
|
||||
@@ -126,7 +125,7 @@ const char *Ai_goal_text(int goal)
|
||||
case AI_GOAL_REARM_REPAIR:
|
||||
return XSTR( "rearm ", 484);
|
||||
case AI_GOAL_FLY_TO_SHIP:
|
||||
return XSTR( "rendezvous with ", 1597);
|
||||
return XSTR( "rendezvous with ", -1);
|
||||
}
|
||||
|
||||
// Avoid compiler warning
|
||||
@@ -415,7 +414,7 @@ void ai_goal_purge_invalid_goals( ai_goal *aigp, ai_goal *goal_list, ai_info *ai
|
||||
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 )
|
||||
if ( stricmp(purge_goal->target_name, Ship_info[Ships[ship_index].ship_info_index].name) )
|
||||
continue;
|
||||
}
|
||||
// standard goals operating on either wings or ships
|
||||
@@ -427,7 +426,7 @@ void ai_goal_purge_invalid_goals( ai_goal *aigp, ai_goal *goal_list, ai_info *ai
|
||||
// don't match, we can continue; if the wing is valid, don't process if the wing numbers
|
||||
// are different.
|
||||
if ( purge_wing == -1 ) {
|
||||
if ( stricmp(purge_goal->target_name, name ) != 0 )
|
||||
if ( stricmp(purge_goal->target_name, name ) )
|
||||
continue;
|
||||
} else if ( purge_wing != wingnum )
|
||||
continue;
|
||||
@@ -733,12 +732,6 @@ void ai_add_goal_sub_scripting(int type, int mode, int submode, int priority, ch
|
||||
aigp->target_signature = Objects[Weapons[submode].objnum].signature;
|
||||
}
|
||||
|
||||
if ( mode == AI_GOAL_WAYPOINTS_ONCE || mode == AI_GOAL_WAYPOINTS ) {
|
||||
// should be the same as setting via sexp, see ai_add_goal_sub_sexp
|
||||
// set to null so the AI code can setup the new waypoint list, see ai_mission_goal_achievable
|
||||
aigp->wp_list = nullptr;
|
||||
}
|
||||
|
||||
if ( target_name != NULL )
|
||||
aigp->target_name = ai_get_goal_target_name( target_name, &aigp->target_name_index );
|
||||
else
|
||||
@@ -944,11 +937,6 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_goal *aigp, char *actor_name )
|
||||
aigp->ai_mode = AI_GOAL_PLAY_DEAD;
|
||||
break;
|
||||
|
||||
case OP_AI_PLAY_DEAD_PERSISTENT:
|
||||
aigp->priority = atoi( CTEXT(CDR(node)) );
|
||||
aigp->ai_mode = AI_GOAL_PLAY_DEAD_PERSISTENT;
|
||||
break;
|
||||
|
||||
case OP_AI_KEEP_SAFE_DISTANCE:
|
||||
aigp->priority = atoi( CTEXT(CDR(node)) );
|
||||
aigp->ai_mode = AI_GOAL_KEEP_SAFE_DISTANCE;
|
||||
@@ -1138,10 +1126,6 @@ int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp )
|
||||
goalmode = AI_GOAL_PLAY_DEAD;
|
||||
priority = ( CDR(node) >= 0 ) ? atoi( CTEXT( CDR( node ) ) ) : -1;
|
||||
break;
|
||||
case OP_AI_PLAY_DEAD_PERSISTENT:
|
||||
goalmode = AI_GOAL_PLAY_DEAD_PERSISTENT;
|
||||
priority = ( CDR(node) >= 0 ) ? atoi( CTEXT( CDR( node ) ) ) : -1;
|
||||
break;
|
||||
case OP_AI_KEEP_SAFE_DISTANCE:
|
||||
priority = ( CDR(node) >= 0 ) ? atoi( CTEXT( CDR( node ) ) ) : -1;
|
||||
goalmode = AI_GOAL_KEEP_SAFE_DISTANCE;
|
||||
@@ -1279,7 +1263,7 @@ void ai_add_wing_goal_sexp(int sexp, int type, int wingnum)
|
||||
// this name can be a shipname or a wingname)
|
||||
// docker_point and dockee_point are used for the AI_GOAL_DOCK command to tell two ships where to dock
|
||||
// immediate means to process this order right away
|
||||
void ai_add_goal_ship_internal( ai_info *aip, int goal_type, char *name, int /*docker_point*/, int /*dockee_point*/, int immediate )
|
||||
void ai_add_goal_ship_internal( ai_info *aip, int goal_type, char *name, int docker_point, int dockee_point, int immediate )
|
||||
{
|
||||
int gindex;
|
||||
ai_goal *aigp;
|
||||
@@ -1356,6 +1340,25 @@ void ai_add_goal_ship_internal( ai_info *aip, int goal_type, char *name, int /*
|
||||
ai_process_mission_orders( Ships[aip->shipnum].objnum, aip );
|
||||
}
|
||||
|
||||
// function to add an internal goal to a wing. Mike K says that the goal doesn't need to persist
|
||||
// across waves of the wing so we merely need to add the goal to each ship in the wing. Certain
|
||||
// goal are simply not valid for wings (like dock, undock). Immediate parameter gets passed to add_ship_goal
|
||||
// to say whether or not we should process this goal right away
|
||||
void ai_add_goal_wing_internal( wing *wingp, int goal_type, char *name, int immediate )
|
||||
{
|
||||
int i;
|
||||
|
||||
// be sure we are not trying to issue dock or undock goals to wings
|
||||
Assert ( (goal_type != AI_GOAL_DOCK) && (goal_type != AI_GOAL_UNDOCK) );
|
||||
|
||||
for (i = 0; i < wingp->current_count; i++) {
|
||||
int num = wingp->ship_index[i];
|
||||
if ( num == -1 ) // ship must have been destroyed or departed
|
||||
continue;
|
||||
ai_add_goal_ship_internal( &Ai_info[Ships[num].ai_index], goal_type, name, -1, -1, immediate);
|
||||
}
|
||||
}
|
||||
|
||||
// this function copies goals from a wing to an ai_info * from a ship.
|
||||
void ai_copy_mission_wing_goal( ai_goal *aigp, ai_info *aip )
|
||||
{
|
||||
@@ -1398,7 +1401,7 @@ int ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
// these orders are always achievable.
|
||||
if ( (aigp->ai_mode == AI_GOAL_KEEP_SAFE_DISTANCE)
|
||||
|| (aigp->ai_mode == AI_GOAL_CHASE_ANY) || (aigp->ai_mode == AI_GOAL_STAY_STILL)
|
||||
|| (aigp->ai_mode == AI_GOAL_PLAY_DEAD) || (aigp->ai_mode == AI_GOAL_PLAY_DEAD_PERSISTENT) )
|
||||
|| (aigp->ai_mode == AI_GOAL_PLAY_DEAD) )
|
||||
return AI_GOAL_ACHIEVABLE;
|
||||
|
||||
// warp (depart) only achievable if there's somewhere to depart to
|
||||
@@ -1892,12 +1895,9 @@ int ai_goal_priority_compare(const void *a, const void *b)
|
||||
// check whether or not the goal override flag is set. If it is set, then push this goal higher
|
||||
// in the list
|
||||
|
||||
// Goober5000: the ONLY goals we do not override are play-dead and play-dead-persistent,
|
||||
// because the override flag needs to work in any other situation
|
||||
|
||||
else if ( (ga->flags[AI::Goal_Flags::Goal_override]) && !(gb->flags[AI::Goal_Flags::Goal_override]) && !(gb->ai_mode == AI_GOAL_PLAY_DEAD) && !(gb->ai_mode == AI_GOAL_PLAY_DEAD_PERSISTENT) )
|
||||
else if ( (ga->flags[AI::Goal_Flags::Goal_override]) && !(gb->flags[AI::Goal_Flags::Goal_override]) )
|
||||
return -1;
|
||||
else if ( !(ga->flags[AI::Goal_Flags::Goal_override]) && (gb->flags[AI::Goal_Flags::Goal_override]) && !(ga->ai_mode == AI_GOAL_PLAY_DEAD) && !(ga->ai_mode == AI_GOAL_PLAY_DEAD_PERSISTENT))
|
||||
else if ( !(ga->flags[AI::Goal_Flags::Goal_override]) && (gb->flags[AI::Goal_Flags::Goal_override]) )
|
||||
return 1;
|
||||
|
||||
// now normal priority processing
|
||||
@@ -2290,13 +2290,6 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
|
||||
aip->submode_start_time = Missiontime;
|
||||
break;
|
||||
|
||||
case AI_GOAL_PLAY_DEAD_PERSISTENT:
|
||||
// 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:
|
||||
// for form on wing, we need to clear out all goals for this ship, and then call the form
|
||||
// on wing AI code
|
||||
|
||||
+5
-5
@@ -58,17 +58,16 @@ struct ai_goal;
|
||||
#define AI_GOAL_FLY_TO_SHIP (1<<23) // 0x00800000
|
||||
#define AI_GOAL_IGNORE_NEW (1<<24) // 0x01000000
|
||||
#define AI_GOAL_CHASE_SHIP_CLASS (1<<25) // 0x02000000
|
||||
#define AI_GOAL_PLAY_DEAD_PERSISTENT (1<<26) // 0x03000000
|
||||
|
||||
// now the masks for ship types
|
||||
|
||||
// Goober5000: added AI_GOAL_STAY_NEAR_SHIP and AI_GOAL_KEEP_SAFE_DISTANCE as valid for fighters
|
||||
//WMC - Don't need these anymore. Whee!
|
||||
/*
|
||||
#define AI_GOAL_ACCEPT_FIGHTER ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_CHASE | AI_GOAL_WAYPOINTS | AI_GOAL_WAYPOINTS_ONCE | AI_GOAL_WARP | AI_GOAL_DESTROY_SUBSYSTEM | AI_GOAL_CHASE_WING | AI_GOAL_GUARD | AI_GOAL_DISABLE_SHIP | AI_GOAL_DISARM_SHIP | AI_GOAL_CHASE_ANY | AI_GOAL_IGNORE | AI_GOAL_IGNORE_NEW | AI_GOAL_GUARD_WING | AI_GOAL_EVADE_SHIP | AI_GOAL_STAY_STILL | AI_GOAL_PLAY_DEAD | AI_GOAL_PLAY_DEAD_PERSISTENT | AI_GOAL_STAY_NEAR_SHIP | AI_GOAL_KEEP_SAFE_DISTANCE )
|
||||
#define AI_GOAL_ACCEPT_FIGHTER ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_CHASE | AI_GOAL_WAYPOINTS | AI_GOAL_WAYPOINTS_ONCE | AI_GOAL_WARP | AI_GOAL_DESTROY_SUBSYSTEM | AI_GOAL_CHASE_WING | AI_GOAL_GUARD | AI_GOAL_DISABLE_SHIP | AI_GOAL_DISARM_SHIP | AI_GOAL_CHASE_ANY | AI_GOAL_IGNORE | AI_GOAL_IGNORE_NEW | AI_GOAL_GUARD_WING | AI_GOAL_EVADE_SHIP | AI_GOAL_STAY_STILL | AI_GOAL_PLAY_DEAD | AI_GOAL_STAY_NEAR_SHIP | AI_GOAL_KEEP_SAFE_DISTANCE )
|
||||
#define AI_GOAL_ACCEPT_BOMBER ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_ACCEPT_FIGHTER | AI_GOAL_STAY_NEAR_SHIP )
|
||||
#define AI_GOAL_ACCEPT_STEALTH ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_ACCEPT_FIGHTER | AI_GOAL_STAY_NEAR_SHIP )
|
||||
#define AI_GOAL_ACCEPT_TRANSPORT ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_CHASE | AI_GOAL_CHASE_WING | AI_GOAL_DOCK | AI_GOAL_WAYPOINTS | AI_GOAL_WAYPOINTS_ONCE | AI_GOAL_WARP | AI_GOAL_UNDOCK | AI_GOAL_STAY_STILL | AI_GOAL_PLAY_DEAD | AI_GOAL_PLAY_DEAD_PERSISTENT | AI_GOAL_STAY_NEAR_SHIP )
|
||||
#define AI_GOAL_ACCEPT_TRANSPORT ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_CHASE | AI_GOAL_CHASE_WING | AI_GOAL_DOCK | AI_GOAL_WAYPOINTS | AI_GOAL_WAYPOINTS_ONCE | AI_GOAL_WARP | AI_GOAL_UNDOCK | AI_GOAL_STAY_STILL | AI_GOAL_PLAY_DEAD| AI_GOAL_STAY_NEAR_SHIP )
|
||||
#define AI_GOAL_ACCEPT_FREIGHTER ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_ACCEPT_TRANSPORT | AI_GOAL_STAY_NEAR_SHIP )
|
||||
#define AI_GOAL_ACCEPT_CRUISER ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_ACCEPT_FREIGHTER | AI_GOAL_STAY_NEAR_SHIP )
|
||||
#define AI_GOAL_ACCEPT_CORVETTE ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_ACCEPT_CRUISER | AI_GOAL_STAY_NEAR_SHIP )
|
||||
@@ -76,7 +75,7 @@ struct ai_goal;
|
||||
#define AI_GOAL_ACCEPT_AWACS ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_ACCEPT_CRUISER | AI_GOAL_STAY_NEAR_SHIP )
|
||||
#define AI_GOAL_ACCEPT_CAPITAL ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_ACCEPT_CRUISER & ~(AI_GOAL_DOCK | AI_GOAL_UNDOCK) | AI_GOAL_STAY_NEAR_SHIP )
|
||||
#define AI_GOAL_ACCEPT_SUPERCAP ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_ACCEPT_CAPITAL | AI_GOAL_STAY_NEAR_SHIP )
|
||||
#define AI_GOAL_ACCEPT_SUPPORT ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_DOCK | AI_GOAL_UNDOCK | AI_GOAL_WAYPOINTS | AI_GOAL_WAYPOINTS_ONCE | AI_GOAL_STAY_NEAR_SHIP | AI_GOAL_KEEP_SAFE_DISTANCE | AI_GOAL_STAY_STILL | AI_GOAL_PLAY_DEAD | AI_GOAL_PLAY_DEAD_PERSISTENT )
|
||||
#define AI_GOAL_ACCEPT_SUPPORT ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_DOCK | AI_GOAL_UNDOCK | AI_GOAL_WAYPOINTS | AI_GOAL_WAYPOINTS_ONCE | AI_GOAL_STAY_NEAR_SHIP | AI_GOAL_KEEP_SAFE_DISTANCE | AI_GOAL_STAY_STILL | AI_GOAL_PLAY_DEAD)
|
||||
#define AI_GOAL_ACCEPT_ESCAPEPOD ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_ACCEPT_TRANSPORT| AI_GOAL_STAY_NEAR_SHIP )
|
||||
*/
|
||||
|
||||
@@ -103,7 +102,7 @@ extern int ai_goal_num(ai_goal *goals);
|
||||
extern void ai_add_ship_goal_scripting(int mode, int submode, int priority, char *shipname, ai_info *aip);
|
||||
extern void ai_add_ship_goal_sexp( int sexp, int type, ai_info *aip );
|
||||
extern void ai_add_wing_goal_sexp( int sexp, int type, int wingnum );
|
||||
extern void ai_add_goal_sub_sexp( int sexp, int type, ai_goal *aigp, char *actor_name );
|
||||
extern void ai_add_goal_sub_sexp( int sexp, int type, ai_goal *aigp );
|
||||
|
||||
extern int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp );
|
||||
extern void ai_remove_wing_goal_sexp(int sexp, int wingnum);
|
||||
@@ -128,5 +127,6 @@ extern char *ai_add_dock_name(const char *str);
|
||||
extern int ai_query_goal_valid( int ship, int ai_goal_type );
|
||||
|
||||
extern void ai_add_goal_ship_internal( ai_info *aip, int goal_type, char *name, int docker_point, int dockee_point, int immediate = 1 );
|
||||
extern void ai_add_goal_wing_internal( wing *wingp, int goal_type, char *name, int immediate = 1 );
|
||||
|
||||
#endif
|
||||
+10
-12
@@ -24,7 +24,7 @@
|
||||
#include "weapon/swarm.h"
|
||||
#include "weapon/weapon.h"
|
||||
|
||||
#include <climits>
|
||||
#include <limits.h>
|
||||
|
||||
|
||||
// How close a turret has to be point at its target before it
|
||||
@@ -243,7 +243,7 @@ int bomb_headed_towards_ship(object *bomb_objp, object *ship_objp)
|
||||
* @note All non-negative return values are expressed in what I like to call "widx"s.
|
||||
* @return -1 if unable to find a weapon for the target at all.
|
||||
*/
|
||||
int turret_select_best_weapon(ship_subsys *turret, object * /*target*/)
|
||||
int turret_select_best_weapon(ship_subsys *turret, object *target)
|
||||
{
|
||||
//TODO: Fill this out with extraodinary gun-picking algorithms
|
||||
if(turret->weapons.num_primary_banks > 0)
|
||||
@@ -1290,9 +1290,7 @@ void ship_get_global_turret_gun_info(object *objp, ship_subsys *ssp, vec3d *gpos
|
||||
model_instance_find_world_point(&tmp_pos, &avg, Ships[objp->instance].model_instance_num, tp->turret_gun_sobj, &objp->orient, &objp->pos);
|
||||
|
||||
if (targetp == nullptr) {
|
||||
ship* shipp = &Ships[Objects[ssp->parent_objnum].instance];
|
||||
Assertion(ssp->turret_enemy_objnum >= 0, "The turret enemy object number %d for %s on ship name %s is invalid.", ssp->turret_enemy_objnum, ssp->sub_name,
|
||||
(shipp->has_display_name()) ? shipp->display_name.c_str() : shipp->ship_name);
|
||||
Assertion(ssp->turret_enemy_objnum >= 0, "The turret enemy object number %d for %s on ship number %d is invalid.", ssp->turret_enemy_objnum, ssp->sub_name, ssp->parent_objnum);
|
||||
object *lep = &Objects[ssp->turret_enemy_objnum];
|
||||
|
||||
int best_weapon_tidx = turret_select_best_weapon(ssp, lep);
|
||||
@@ -1303,9 +1301,9 @@ void ship_get_global_turret_gun_info(object *objp, ship_subsys *ssp, vec3d *gpos
|
||||
|
||||
weapon_info *wip = get_turret_weapon_wip(&ssp->weapons, best_weapon_tidx);
|
||||
|
||||
float weapon_system_strength = ship_get_subsystem_strength(shipp, SUBSYSTEM_WEAPONS);
|
||||
float weapon_system_strength = ship_get_subsystem_strength(&Ships[ssp->parent_objnum], SUBSYSTEM_WEAPONS);
|
||||
|
||||
turret_ai_update_aim(&Ai_info[shipp->ai_index], &Objects[ssp->turret_enemy_objnum], ssp);
|
||||
turret_ai_update_aim(&Ai_info[Ships[ssp->parent_objnum].ai_index], &Objects[ssp->turret_enemy_objnum], ssp);
|
||||
|
||||
if ((ssp->targeted_subsys != nullptr) && !(ssp->flags[Ship::Subsystem_Flags::No_SS_targeting])) {
|
||||
vm_vec_unrotate(&enemy_point, &ssp->targeted_subsys->system_info->pnt, &Objects[ssp->turret_enemy_objnum].orient);
|
||||
@@ -1876,7 +1874,7 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
|
||||
turret->last_fired_weapon_info_index = turret_weapon_class;
|
||||
|
||||
Script_system.SetHookObjects(4, "Ship", &Objects[parent_objnum], "Weapon", nullptr, "Beam", objp, "Target", &Objects[turret->turret_enemy_objnum]);
|
||||
Script_system.RunCondition(CHA_ONTURRETFIRED, &Objects[parent_objnum]);
|
||||
Script_system.RunCondition(CHA_ONTURRETFIRED, 0, NULL, &Objects[parent_objnum]);
|
||||
Script_system.RemHookVars(4, "Ship", "Weapon", "Beam", "Target");
|
||||
}
|
||||
|
||||
@@ -2011,7 +2009,7 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
|
||||
wp->turret_subsys = turret;
|
||||
|
||||
Script_system.SetHookObjects(4, "Ship", &Objects[parent_objnum], "Weapon", objp, "Beam", nullptr, "Target", &Objects[turret->turret_enemy_objnum]);
|
||||
Script_system.RunCondition(CHA_ONTURRETFIRED, &Objects[parent_objnum]);
|
||||
Script_system.RunCondition(CHA_ONTURRETFIRED, 0, NULL, &Objects[parent_objnum]);
|
||||
Script_system.RemHookVars(4, "Ship", "Weapon", "Beam", "Target");
|
||||
|
||||
// if the gun is a flak gun
|
||||
@@ -2050,7 +2048,7 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
|
||||
}
|
||||
}
|
||||
|
||||
if ( wip->launch_snd.isValid() ) {
|
||||
if ( wip->launch_snd != -1 ) {
|
||||
// Don't play turret firing sound if turret sits on player ship... it gets annoying.
|
||||
if ( parent_objnum != OBJ_INDEX(Player_obj) || (turret->flags[Ship::Subsystem_Flags::Play_sound_for_player]) ) {
|
||||
snd_play_3d( gamesnd_get_game_sound(wip->launch_snd), turret_pos, &View_position );
|
||||
@@ -2128,7 +2126,7 @@ void turret_swarm_fire_from_turret(turret_swarm_info *tsi)
|
||||
tsi->turret->last_fired_weapon_info_index = tsi->weapon_class;
|
||||
|
||||
Script_system.SetHookObjects(4, "Ship", &Objects[tsi->parent_objnum], "Weapon", &Objects[weapon_objnum], "Beam", nullptr, "Target", &Objects[tsi->turret->turret_enemy_objnum]);
|
||||
Script_system.RunCondition(CHA_ONTURRETFIRED, &Objects[tsi->parent_objnum]);
|
||||
Script_system.RunCondition(CHA_ONTURRETFIRED, 0, NULL, &Objects[tsi->parent_objnum]);
|
||||
Script_system.RemHookVars(4, "Ship", "Weapon", "Beam", "Target");
|
||||
|
||||
// muzzle flash?
|
||||
@@ -2137,7 +2135,7 @@ void turret_swarm_fire_from_turret(turret_swarm_info *tsi)
|
||||
}
|
||||
|
||||
// maybe sound
|
||||
if ( Weapon_info[tsi->weapon_class].launch_snd.isValid() ) {
|
||||
if ( Weapon_info[tsi->weapon_class].launch_snd != -1 ) {
|
||||
// Don't play turret firing sound if turret sits on player ship... it gets annoying.
|
||||
if ( tsi->parent_objnum != OBJ_INDEX(Player_obj) ) {
|
||||
snd_play_3d( gamesnd_get_game_sound(Weapon_info[tsi->weapon_class].launch_snd), &turret_pos, &View_position );
|
||||
|
||||
+171
-2
@@ -274,9 +274,9 @@ int anim_show_next_frame(anim_instance *instance, float frametime)
|
||||
percent_through = instance->time_elapsed / time;
|
||||
|
||||
if(instance->direction == ANIM_DIRECT_FORWARD)
|
||||
new_frame_num = instance->start_at - 1 + (int) lround(percent_through * n_frames);
|
||||
new_frame_num = instance->start_at - 1 + fl2i(percent_through * n_frames + 0.5f);
|
||||
else
|
||||
new_frame_num = instance->start_at - 1 - (int) lround(percent_through * n_frames);
|
||||
new_frame_num = instance->start_at - 1 - fl2i(percent_through * n_frames + 0.5f);
|
||||
|
||||
frame_save = instance->frame_num;
|
||||
|
||||
@@ -519,6 +519,19 @@ int anim_show_next_frame(anim_instance *instance, float frametime)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stop an anim instance that is on the anim_render_list from playing
|
||||
*/
|
||||
int anim_stop_playing(anim_instance* instance)
|
||||
{
|
||||
Assert(instance != NULL);
|
||||
|
||||
if ( anim_playing(instance) ) {
|
||||
anim_release_render_instance(instance);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Free a particular animation instance that is on the anim_render_list.
|
||||
* Do not call this function to free an animation instance in general (use
|
||||
@@ -853,6 +866,20 @@ int anim_free(anim *ptr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return if an anim is playing or not.
|
||||
*/
|
||||
int anim_playing(anim_instance *ai)
|
||||
{
|
||||
Assert(ai != NULL);
|
||||
if ( ai->frame == NULL )
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Called at the beginning of a mission to initialize any mission dependent anim data.
|
||||
* @todo Redundant?
|
||||
@@ -869,6 +896,138 @@ void anim_level_close()
|
||||
anim_release_all_instances();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write the frames of a .ani file out to disk as .pcx files.
|
||||
* @details Use naming convention: filename0000.pcx, filename0001.pcx etc.
|
||||
*
|
||||
* @return If success 0, or if failed -1
|
||||
*/
|
||||
int anim_write_frames_out(char *filename)
|
||||
{
|
||||
anim *source_anim;
|
||||
anim_instance *ai;
|
||||
char root_name[256], pcxname[256];
|
||||
char buf[64];
|
||||
int i,j;
|
||||
ubyte **row_data;
|
||||
|
||||
strcpy_s(root_name, filename);
|
||||
root_name[strlen(filename)-4] = 0;
|
||||
|
||||
source_anim = anim_load(filename);
|
||||
if ( source_anim == NULL )
|
||||
return -1;
|
||||
|
||||
ai = init_anim_instance(source_anim, 16);
|
||||
|
||||
row_data = (ubyte**)vm_malloc((source_anim->height+1) * 4);
|
||||
|
||||
for ( i = 0; i < source_anim->total_frames; i++ ) {
|
||||
anim_get_next_raw_buffer(ai, 0, 0, 16);
|
||||
strcpy_s(pcxname, root_name);
|
||||
sprintf(buf,"%04d",i);
|
||||
strcat_s(pcxname, buf);
|
||||
|
||||
for ( j = 0; j < source_anim->height; j++ ) {
|
||||
row_data[j] = &ai->frame[j*source_anim->width];
|
||||
}
|
||||
|
||||
|
||||
pcx_write_bitmap( pcxname,
|
||||
source_anim->width,
|
||||
source_anim->height,
|
||||
row_data,
|
||||
source_anim->palette);
|
||||
|
||||
printf(".");
|
||||
|
||||
}
|
||||
printf("\n");
|
||||
vm_free(row_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Display information and statistics about a .ani file.
|
||||
* @details This is called when -i switch is on when running ac.exe
|
||||
*/
|
||||
void anim_display_info(char *real_filename)
|
||||
{
|
||||
CFILE *fp;
|
||||
anim A;
|
||||
float percent;
|
||||
int i, uncompressed, compressed, *key_frame_nums=NULL, tmp;
|
||||
char filename[MAX_FILENAME_LEN];
|
||||
|
||||
strcpy_s( filename, real_filename );
|
||||
char *p = strchr( filename, '.' );
|
||||
if ( p ) {
|
||||
*p = 0;
|
||||
}
|
||||
strcat_s( filename, ".ani" );
|
||||
|
||||
fp = cfopen(filename, "rb");
|
||||
if ( !fp ) {
|
||||
printf("Fatal error opening %s", filename);
|
||||
return;
|
||||
}
|
||||
|
||||
anim_read_header(&A, fp);
|
||||
|
||||
if (A.width < 0 || A.height < 0) {
|
||||
Error(LOCATION, "Ani file %s has a faulty header and cannot be loaded.", filename);
|
||||
}
|
||||
|
||||
// read the keyframe frame nums and offsets
|
||||
key_frame_nums = (int*)vm_malloc(sizeof(int)*A.num_keys);
|
||||
Assert(key_frame_nums != NULL);
|
||||
if (key_frame_nums == NULL)
|
||||
return;
|
||||
|
||||
for ( i = 0; i < A.num_keys; i++ ) {
|
||||
key_frame_nums[i] = 0;
|
||||
cfread(&key_frame_nums[i], 2, 1, fp);
|
||||
cfread(&tmp, 4, 1, fp);
|
||||
}
|
||||
|
||||
cfread(&compressed, 4, 1, fp);
|
||||
|
||||
uncompressed = A.width * A.height * A.total_frames; // 8 bits per pixel
|
||||
percent = i2fl(compressed) / uncompressed * 100.0f;
|
||||
|
||||
printf("%% of uncompressed size: %.0f%%\n", percent);
|
||||
printf("Width: %d\n", A.width);
|
||||
printf("Height: %d\n", A.height);
|
||||
printf("Total Frames: %d\n", A.total_frames);
|
||||
|
||||
#ifndef NDEBUG
|
||||
printf("Key Frames: %d\n", A.num_keys);
|
||||
if ( A.num_keys > 1 && (A.total_frames != A.num_keys) ) {
|
||||
printf("key list: (");
|
||||
for ( i = 0; i < A.num_keys; i++ ) {
|
||||
if ( i < A.num_keys-1 )
|
||||
printf("%d, ", key_frame_nums[i]);
|
||||
else
|
||||
printf("%d)\n", key_frame_nums[i]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
printf("FPS: %d\n", A.fps);
|
||||
|
||||
#ifndef NDEBUG
|
||||
printf("Transparent RGB: (%u,%u,%u)\n", A.xparent_r, A.xparent_g, A.xparent_b);
|
||||
#endif
|
||||
|
||||
printf("ac version: %d\n", A.version);
|
||||
|
||||
if ( key_frame_nums != NULL ) {
|
||||
vm_free(key_frame_nums);
|
||||
}
|
||||
|
||||
cfclose(fp);
|
||||
}
|
||||
|
||||
void anim_reverse_direction(anim_instance *ai)
|
||||
{
|
||||
int temp;
|
||||
@@ -902,6 +1061,16 @@ void anim_reverse_direction(anim_instance *ai)
|
||||
}
|
||||
}
|
||||
|
||||
void anim_pause(anim_instance *ai)
|
||||
{
|
||||
ai->paused = 1;
|
||||
}
|
||||
|
||||
void anim_unpause(anim_instance *ai)
|
||||
{
|
||||
ai->paused = 0;
|
||||
}
|
||||
|
||||
void anim_ignore_next_frametime()
|
||||
{
|
||||
Anim_ignore_frametime=1;
|
||||
|
||||
@@ -54,13 +54,19 @@ void anim_render_one(int screen_id, anim_instance *ani, float frametime);
|
||||
void anim_play_init(anim_play_struct *aps, anim *a_info, int x, int y, int max_x = -1, int max_y = -1);
|
||||
anim_instance *anim_play(anim_play_struct *aps);
|
||||
void anim_ignore_next_frametime();
|
||||
int anim_stop_playing(anim_instance* anim_instance);
|
||||
int anim_show_next_frame(anim_instance *instance, float frametime);
|
||||
void anim_release_all_instances(int screen_id = 0);
|
||||
void anim_release_render_instance(anim_instance* instance);
|
||||
anim *anim_load(const char *name, int cf_dir_type = CF_TYPE_ANY, int file_mapped = PAGE_FROM_DISK);
|
||||
int anim_free(anim *ptr);
|
||||
int anim_playing(anim_instance *ai);
|
||||
int anim_write_frames_out(char *filename);
|
||||
void anim_display_info(char *filename);
|
||||
void anim_read_header(anim *ptr, CFILE *fp);
|
||||
void anim_reverse_direction(anim_instance *ai); // called automatically for ping-ponging, and can also be called externally
|
||||
void anim_pause(anim_instance *ai);
|
||||
void anim_unpause(anim_instance *ai);
|
||||
|
||||
int anim_instance_is_streamed(anim_instance *ai);
|
||||
unsigned char anim_instance_get_byte(anim_instance *ai, int offset);
|
||||
|
||||
@@ -78,6 +78,52 @@ void free_anim_instance(anim_instance *inst)
|
||||
vm_free(inst);
|
||||
}
|
||||
|
||||
int anim_get_next_frame(anim_instance *inst)
|
||||
{
|
||||
int bm, bitmap_flags;
|
||||
int aabitmap = 0;
|
||||
int bpp = 16;
|
||||
|
||||
if ( anim_instance_is_streamed(inst) ) {
|
||||
if ( inst->file_offset <= 0 ) {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if (!inst->data)
|
||||
return -1;
|
||||
}
|
||||
|
||||
inst->frame_num++;
|
||||
if (inst->frame_num >= inst->parent->total_frames) {
|
||||
inst->data = NULL;
|
||||
inst->file_offset = inst->parent->file_offset;
|
||||
return -1;
|
||||
}
|
||||
|
||||
bitmap_flags = 0;
|
||||
|
||||
bpp = 16;
|
||||
if(inst->aa_color != NULL){
|
||||
bitmap_flags |= BMP_AABITMAP;
|
||||
aabitmap = 1;
|
||||
bpp = 8;
|
||||
}
|
||||
|
||||
anim_check_for_palette_change(inst);
|
||||
|
||||
BM_SELECT_TEX_FORMAT();
|
||||
|
||||
if ( anim_instance_is_streamed(inst) ) {
|
||||
inst->file_offset = unpack_frame_from_file(inst, inst->frame, inst->parent->width*inst->parent->height, inst->parent->palette_translation, aabitmap, bpp);
|
||||
} else {
|
||||
inst->data = unpack_frame(inst, inst->data, inst->frame, inst->parent->width*inst->parent->height, inst->parent->palette_translation, aabitmap, bpp);
|
||||
}
|
||||
|
||||
bm = bm_create(bpp, inst->parent->width, inst->parent->height, inst->frame, bitmap_flags);
|
||||
bm_unload(bm);
|
||||
return bm;
|
||||
}
|
||||
|
||||
ubyte *anim_get_next_raw_buffer(anim_instance *inst, int xlate_pal, int aabitmap, int bpp)
|
||||
{
|
||||
if ( anim_instance_is_streamed(inst) ) {
|
||||
@@ -116,6 +162,321 @@ ubyte *anim_get_next_raw_buffer(anim_instance *inst, int xlate_pal, int aabitmap
|
||||
return inst->frame;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Pack key frame
|
||||
*
|
||||
* @param frame Frame pixel data to pack
|
||||
* @param save Memory to store packed data to
|
||||
* @param size Number of bytes to pack
|
||||
* @param max Maximum number of packed bytes (size of buffer)
|
||||
* @param compress_type Compress type
|
||||
* @return Actual number of bytes data packed to or -1 if error
|
||||
*/
|
||||
int pack_key_frame(ubyte *frame, ubyte *save, long size, long max, int compress_type)
|
||||
{
|
||||
int last = -32768, count = 0;
|
||||
long packed_size = 1;
|
||||
|
||||
switch ( compress_type ) {
|
||||
case PACKING_METHOD_RLE_KEY:
|
||||
*save++ = PACKING_METHOD_RLE_KEY;
|
||||
while (size--) {
|
||||
if (*frame != last || count > 255) {
|
||||
if (packed_size + 3 >= max)
|
||||
return -1;
|
||||
|
||||
if (count < 3) {
|
||||
if (last == packer_code) {
|
||||
*save++ = (ubyte)packer_code;
|
||||
*save++ = (ubyte)(count - 1);
|
||||
packed_size += 2;
|
||||
|
||||
} else
|
||||
while (count--) {
|
||||
*save++ = (ubyte)last;
|
||||
packed_size++;
|
||||
}
|
||||
|
||||
} else {
|
||||
*save++ = (ubyte)packer_code;
|
||||
*save++ = (ubyte)(count - 1);
|
||||
*save++ = (ubyte)last;
|
||||
packed_size += 3;
|
||||
}
|
||||
|
||||
count = 0;
|
||||
last = *frame;
|
||||
}
|
||||
|
||||
count++;
|
||||
frame++;
|
||||
}
|
||||
|
||||
if (packed_size + 3 >= max)
|
||||
return -1;
|
||||
|
||||
if (count < 3) {
|
||||
if (last == packer_code) {
|
||||
*save++ = (ubyte)packer_code;
|
||||
*save++ = (ubyte)(count - 1);
|
||||
packed_size += 2;
|
||||
|
||||
} else
|
||||
while (count--) {
|
||||
*save++ = (ubyte)last;
|
||||
packed_size++;
|
||||
}
|
||||
|
||||
} else {
|
||||
*save++ = (ubyte)packer_code;
|
||||
*save++ = (ubyte)(count - 1);
|
||||
*save++ = (ubyte)last;
|
||||
packed_size += 3;
|
||||
}
|
||||
break;
|
||||
|
||||
case PACKING_METHOD_STD_RLE_KEY: {
|
||||
ubyte *dest_start;
|
||||
int i;
|
||||
|
||||
dest_start = save;
|
||||
count = 1;
|
||||
|
||||
last = *frame++;
|
||||
*save++ = PACKING_METHOD_STD_RLE_KEY;
|
||||
for (i=1; i < size; i++ ) {
|
||||
|
||||
if ( *frame != last ) {
|
||||
if ( count ) {
|
||||
|
||||
if (packed_size + 2 >= max)
|
||||
return -1;
|
||||
|
||||
if ( (count == 1) && !(last & STD_RLE_CODE) ) {
|
||||
*save++ = (ubyte)last;
|
||||
packed_size++;
|
||||
Assert( last != STD_RLE_CODE );
|
||||
}
|
||||
else {
|
||||
count |= STD_RLE_CODE;
|
||||
*save++ = (ubyte)count;
|
||||
*save++ = (ubyte)last;
|
||||
packed_size += 2;
|
||||
}
|
||||
}
|
||||
|
||||
last = *frame;
|
||||
count = 0;
|
||||
}
|
||||
|
||||
count++;
|
||||
frame++;
|
||||
|
||||
if ( count == 127 ) {
|
||||
count |= STD_RLE_CODE;
|
||||
*save++ = (ubyte)count;
|
||||
*save++ = (ubyte)last;
|
||||
packed_size += 2;
|
||||
count = 0;
|
||||
}
|
||||
} // end for
|
||||
|
||||
if (count) {
|
||||
|
||||
if (packed_size + 2 >= max)
|
||||
return -1;
|
||||
|
||||
if ( (count == 1) && !(last & STD_RLE_CODE) ) {
|
||||
*save++ = (ubyte)last;
|
||||
packed_size++;
|
||||
Assert( last != STD_RLE_CODE );
|
||||
}
|
||||
else {
|
||||
count |= STD_RLE_CODE;
|
||||
*save++ = (ubyte)count;
|
||||
*save++ = (ubyte)last;
|
||||
packed_size += 2;
|
||||
}
|
||||
}
|
||||
|
||||
Assert(packed_size == (save-dest_start) );
|
||||
return packed_size;
|
||||
}
|
||||
|
||||
default:
|
||||
Assert(0);
|
||||
return -1;
|
||||
break;
|
||||
} // end switch
|
||||
|
||||
return packed_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Pack frame
|
||||
*
|
||||
* @param frame Frame pixel data to pack
|
||||
* @param frame2 Previous frame's pixel data
|
||||
* @param save Memory to store packed data to
|
||||
* @param size Number of bytes to pack
|
||||
* @param max Maximum number of packed bytes (size of buffer)
|
||||
* @param compress_type Compress type
|
||||
* @return Actual number of bytes data packed to or -1 if error
|
||||
*/
|
||||
int pack_frame(ubyte *frame, ubyte *frame2, ubyte *save, long size, long max, int compress_type)
|
||||
{
|
||||
int pixel, last = -32768, count = 0, i;
|
||||
long packed_size = 1;
|
||||
|
||||
switch ( compress_type ) {
|
||||
case PACKING_METHOD_RLE: // Hoffoss RLE regular frame
|
||||
*save++ = PACKING_METHOD_RLE;
|
||||
while (size--) {
|
||||
if (*frame != *frame2++)
|
||||
pixel = *frame;
|
||||
else
|
||||
pixel = transparent_code;
|
||||
|
||||
if (pixel != last || count > 255) {
|
||||
if (packed_size + 3 >= max)
|
||||
return -1;
|
||||
|
||||
if (count < 3) {
|
||||
if (last == packer_code) {
|
||||
*save++ = (ubyte)packer_code;
|
||||
*save++ = (ubyte)(count - 1);
|
||||
packed_size += 2;
|
||||
|
||||
} else
|
||||
while (count--) {
|
||||
*save++ = (ubyte)last;
|
||||
packed_size++;
|
||||
}
|
||||
|
||||
} else {
|
||||
*save++ = (ubyte)packer_code;
|
||||
*save++ = (ubyte)(count - 1);
|
||||
*save++ = (ubyte)last;
|
||||
packed_size += 3;
|
||||
}
|
||||
|
||||
count = 0;
|
||||
last = pixel;
|
||||
}
|
||||
|
||||
frame++;
|
||||
count++;
|
||||
}
|
||||
|
||||
if (packed_size + 3 >= max)
|
||||
return -1;
|
||||
|
||||
if (count < 3) {
|
||||
if (last == packer_code) {
|
||||
*save++ = (ubyte)packer_code;
|
||||
*save++ = (ubyte)(count - 1);
|
||||
packed_size += 2;
|
||||
|
||||
} else
|
||||
while (count--) {
|
||||
*save++ = (ubyte)last;
|
||||
packed_size++;
|
||||
}
|
||||
|
||||
} else {
|
||||
*save++ = (ubyte)(packer_code);
|
||||
*save++ = (ubyte)(count - 1);
|
||||
*save++ = (ubyte)(last);
|
||||
packed_size += 3;
|
||||
}
|
||||
break;
|
||||
|
||||
case PACKING_METHOD_STD_RLE: { // high bit count regular RLE frame
|
||||
|
||||
ubyte *dest_start;
|
||||
|
||||
dest_start = save;
|
||||
count = 1;
|
||||
|
||||
if (*frame++ != *frame2++)
|
||||
last = *frame;
|
||||
else
|
||||
last = transparent_code;
|
||||
|
||||
*save++ = PACKING_METHOD_STD_RLE;
|
||||
for (i=1; i < size; i++ ) {
|
||||
|
||||
if (*frame != *frame2++)
|
||||
pixel = *frame;
|
||||
else
|
||||
pixel = transparent_code;
|
||||
|
||||
if ( pixel != last ) {
|
||||
if ( count ) {
|
||||
|
||||
if (packed_size + 2 >= max)
|
||||
return -1;
|
||||
|
||||
if ( (count == 1) && !(last & STD_RLE_CODE) ) {
|
||||
*save++ = (ubyte)last;
|
||||
packed_size++;
|
||||
Assert( last != STD_RLE_CODE );
|
||||
}
|
||||
else {
|
||||
count |= STD_RLE_CODE;
|
||||
*save++ = (ubyte)count;
|
||||
*save++ = (ubyte)last;
|
||||
packed_size += 2;
|
||||
}
|
||||
}
|
||||
|
||||
last = pixel;
|
||||
count = 0;
|
||||
}
|
||||
|
||||
count++;
|
||||
frame++;
|
||||
|
||||
if ( count == 127 ) {
|
||||
count |= STD_RLE_CODE;
|
||||
*save++ = (ubyte)count;
|
||||
*save++ = (ubyte)last;
|
||||
packed_size += 2;
|
||||
count = 0;
|
||||
}
|
||||
} // end for
|
||||
|
||||
if (count) {
|
||||
|
||||
if (packed_size + 2 >= max)
|
||||
return -1;
|
||||
|
||||
if ( (count == 1) && !(last & STD_RLE_CODE) ) {
|
||||
*save++ = (ubyte)last;
|
||||
packed_size++;
|
||||
Assert( last != STD_RLE_CODE );
|
||||
}
|
||||
else {
|
||||
count |= STD_RLE_CODE;
|
||||
*save++ = (ubyte)count;
|
||||
*save++ = (ubyte)last;
|
||||
packed_size += 2;
|
||||
}
|
||||
}
|
||||
|
||||
Assert(packed_size == (save-dest_start) );
|
||||
return packed_size;
|
||||
}
|
||||
|
||||
default:
|
||||
Assert(0);
|
||||
return -1;
|
||||
break;
|
||||
} // end switch
|
||||
|
||||
return packed_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convert a 24 bit value to a 16 bit value
|
||||
* @param bit_24 24 bit value
|
||||
|
||||
@@ -97,12 +97,16 @@ typedef struct anim_instance {
|
||||
int loop_count; // starts at 0, and is incremented each time it loops
|
||||
} anim_instance;
|
||||
|
||||
int pack_key_frame(ubyte *frame, ubyte *save, long size, long max, int compress_type);
|
||||
int pack_frame(ubyte *frame, ubyte *frame2, ubyte *save, long size, long max, int compress_type);
|
||||
|
||||
ubyte *unpack_frame(anim_instance *ai, ubyte *ptr, ubyte *frame, int size, ubyte *pal_translate, int aabitmap, int bpp);
|
||||
int unpack_frame_from_file(anim_instance *ai, ubyte *frame, int size, ubyte *pal_translate, int aabitmap, int bpp);
|
||||
|
||||
void anim_init();
|
||||
anim_instance *init_anim_instance(anim *ptr, int bpp);
|
||||
void free_anim_instance(anim_instance *inst);
|
||||
int anim_get_next_frame(anim_instance *inst);
|
||||
ubyte *anim_get_next_raw_buffer(anim_instance *inst, int xlate_pal, int aabitmap, int bpp);
|
||||
void anim_set_palette(anim *a);
|
||||
void anim_check_for_palette_change(anim_instance *inst);
|
||||
|
||||
+106
-42
@@ -76,7 +76,7 @@ float Asteroid_icon_closeup_zoom;
|
||||
/**
|
||||
* Force updating of pair stuff for asteroid *objp.
|
||||
*/
|
||||
static void asteroid_update_collide(object *objp)
|
||||
void asteroid_update_collide(object *objp)
|
||||
{
|
||||
// Asteroid has wrapped, update collide objnum and flags
|
||||
Asteroids[objp->instance].collide_objnum = -1;
|
||||
@@ -87,7 +87,7 @@ static void asteroid_update_collide(object *objp)
|
||||
/**
|
||||
* Clear out the ::Asteroid_obj_list
|
||||
*/
|
||||
static void asteroid_obj_list_init()
|
||||
void asteroid_obj_list_init()
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -101,7 +101,7 @@ static void asteroid_obj_list_init()
|
||||
* Add a node from the Asteroid_obj_list.
|
||||
* Only called from ::weapon_create()
|
||||
*/
|
||||
static int asteroid_obj_list_add(int objnum)
|
||||
int asteroid_obj_list_add(int objnum)
|
||||
{
|
||||
int index;
|
||||
|
||||
@@ -123,7 +123,7 @@ static int asteroid_obj_list_add(int objnum)
|
||||
* Remove a node from the Asteroid_obj_list.
|
||||
* Only called from ::weapon_delete()
|
||||
*/
|
||||
static void asteroid_obj_list_remove(object * obj)
|
||||
void asteroid_obj_list_remove(object * obj)
|
||||
{
|
||||
int index = obj->instance;
|
||||
|
||||
@@ -138,7 +138,7 @@ static void asteroid_obj_list_remove(object * obj)
|
||||
/**
|
||||
* Prevent speed from getting too huge so it's hard to catch up to an asteroid.
|
||||
*/
|
||||
static float asteroid_cap_speed(int asteroid_info_index, float speed)
|
||||
float asteroid_cap_speed(int asteroid_info_index, float speed)
|
||||
{
|
||||
float max, double_max;
|
||||
|
||||
@@ -164,7 +164,7 @@ static float asteroid_cap_speed(int asteroid_info_index, float speed)
|
||||
* Sum together the following: 1 inside x, 2 inside y, 4 inside z
|
||||
* inside only when sum = 7
|
||||
*/
|
||||
static int asteroid_in_inner_bound_with_axes(asteroid_field *asfieldp, vec3d *pos, float delta)
|
||||
int asteroid_in_inner_bound_with_axes(asteroid_field *asfieldp, vec3d *pos, float delta)
|
||||
{
|
||||
Assert(asfieldp->has_inner_bound);
|
||||
|
||||
@@ -188,7 +188,7 @@ static int asteroid_in_inner_bound_with_axes(asteroid_field *asfieldp, vec3d *po
|
||||
* Check if asteroid is within inner bound
|
||||
* @return 0 if not inside or no inner bound, 1 if inside inner bound
|
||||
*/
|
||||
static int asteroid_in_inner_bound(asteroid_field *asfieldp, vec3d *pos, float delta) {
|
||||
int asteroid_in_inner_bound(asteroid_field *asfieldp, vec3d *pos, float delta) {
|
||||
|
||||
if (!asfieldp->has_inner_bound) {
|
||||
return 0;
|
||||
@@ -202,7 +202,7 @@ static int asteroid_in_inner_bound(asteroid_field *asfieldp, vec3d *pos, float d
|
||||
*
|
||||
* Moves to the other side of the inner box a distance delta from edge of box
|
||||
*/
|
||||
static void inner_bound_pos_fixup(asteroid_field *asfieldp, vec3d *pos)
|
||||
void inner_bound_pos_fixup(asteroid_field *asfieldp, vec3d *pos)
|
||||
{
|
||||
if (!asteroid_in_inner_bound(asfieldp, pos, 0)) {
|
||||
return;
|
||||
@@ -446,7 +446,7 @@ void asteroid_sub_create(object *parent_objp, int asteroid_type, vec3d *relvec)
|
||||
/**
|
||||
* Load in an asteroid model
|
||||
*/
|
||||
static void asteroid_load(int asteroid_info_index, int asteroid_subtype)
|
||||
void asteroid_load(int asteroid_info_index, int asteroid_subtype)
|
||||
{
|
||||
int i;
|
||||
asteroid_info *asip;
|
||||
@@ -487,12 +487,26 @@ static void asteroid_load(int asteroid_info_index, int asteroid_subtype)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Randomly choose a debris model within the current group
|
||||
*/
|
||||
int get_debris_from_same_group(int index) {
|
||||
int group_base, group_offset;
|
||||
|
||||
group_base = (index / NUM_DEBRIS_SIZES) * NUM_DEBRIS_SIZES;
|
||||
group_offset = index - group_base;
|
||||
|
||||
// group base + offset
|
||||
// offset is formed by adding 1 or 2 (since 3 in model group) and mapping back in the 0-2 range
|
||||
return group_base + ((group_offset + rand()%(NUM_DEBRIS_SIZES-1) + 1) % NUM_DEBRIS_SIZES);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a weight that depends on asteroid size.
|
||||
*
|
||||
* The weight is then used to determine the frequencty of different sizes of ship debris
|
||||
*/
|
||||
static int get_debris_weight(int ship_debris_index)
|
||||
int get_debris_weight(int ship_debris_index)
|
||||
{
|
||||
int size = ship_debris_index % NUM_DEBRIS_SIZES;
|
||||
switch (size)
|
||||
@@ -612,7 +626,7 @@ void asteroid_create_all()
|
||||
}
|
||||
|
||||
/**
|
||||
* Init asteroid system for the level, called from ::game_level_init()
|
||||
* Init asteriod system for the level, called from ::game_level_init()
|
||||
*/
|
||||
void asteroid_level_init()
|
||||
{
|
||||
@@ -631,7 +645,7 @@ void asteroid_level_init()
|
||||
*
|
||||
* @return !0 if asteroid should be wrapped, 0 otherwise.
|
||||
*/
|
||||
static int asteroid_should_wrap(object *objp, asteroid_field *asfieldp)
|
||||
int asteroid_should_wrap(object *objp, asteroid_field *asfieldp)
|
||||
{
|
||||
if ( MULTIPLAYER_CLIENT )
|
||||
return 0;
|
||||
@@ -676,7 +690,7 @@ static int asteroid_should_wrap(object *objp, asteroid_field *asfieldp)
|
||||
/**
|
||||
* Wrap an asteroid from one end of the asteroid field to the other
|
||||
*/
|
||||
static void asteroid_wrap_pos(object *objp, asteroid_field *asfieldp)
|
||||
void asteroid_wrap_pos(object *objp, asteroid_field *asfieldp)
|
||||
{
|
||||
if (objp->pos.xyz.x < asfieldp->min_bound.xyz.x) {
|
||||
objp->pos.xyz.x = asfieldp->max_bound.xyz.x + (objp->pos.xyz.x - asfieldp->min_bound.xyz.x);
|
||||
@@ -713,7 +727,7 @@ static void asteroid_wrap_pos(object *objp, asteroid_field *asfieldp)
|
||||
*
|
||||
* @return !0 if this asteroid is a target for any ship, otherwise return 0
|
||||
*/
|
||||
static int asteroid_is_targeted(object *objp)
|
||||
int asteroid_is_targeted(object *objp)
|
||||
{
|
||||
ship_obj *so;
|
||||
object *ship_objp;
|
||||
@@ -734,7 +748,7 @@ static int asteroid_is_targeted(object *objp)
|
||||
/**
|
||||
* Create an asteroid that will hit object *objp in delta_time seconds
|
||||
*/
|
||||
static void asteroid_aim_at_target(object *objp, object *asteroid_objp, float delta_time)
|
||||
void asteroid_aim_at_target(object *objp, object *asteroid_objp, float delta_time)
|
||||
{
|
||||
vec3d predicted_center_pos;
|
||||
vec3d rand_vec;
|
||||
@@ -762,7 +776,7 @@ static void asteroid_aim_at_target(object *objp, object *asteroid_objp, float de
|
||||
*
|
||||
* @param count asteroids already targeted on
|
||||
*/
|
||||
static void maybe_throw_asteroid(int count)
|
||||
void maybe_throw_asteroid(int count)
|
||||
{
|
||||
if (!timestamp_elapsed(Next_asteroid_throw)) {
|
||||
return;
|
||||
@@ -836,7 +850,7 @@ void asteroid_delete( object * obj )
|
||||
* See if we should reposition the asteroid.
|
||||
* Only reposition if oustide the bounding volume and the player isn't looking towards the asteroid.
|
||||
*/
|
||||
static void asteroid_maybe_reposition(object *objp, asteroid_field *asfieldp)
|
||||
void asteroid_maybe_reposition(object *objp, asteroid_field *asfieldp)
|
||||
{
|
||||
// passive field does not wrap
|
||||
if (asfieldp->field_type == FT_PASSIVE) {
|
||||
@@ -889,7 +903,7 @@ static void asteroid_maybe_reposition(object *objp, asteroid_field *asfieldp)
|
||||
}
|
||||
}
|
||||
|
||||
static void lerp(float *goal, float f1, float f2, float scale)
|
||||
void lerp(float *goal, float f1, float f2, float scale)
|
||||
{
|
||||
*goal = (f2 - f1) * scale + f1;
|
||||
}
|
||||
@@ -1143,6 +1157,8 @@ int asteroid_check_collision(object *pasteroid, object *other_obj, vec3d *hitpos
|
||||
|
||||
// SET PHYSICS PARAMETERS
|
||||
// already have (hitpos - heavy) and light_cm_pos
|
||||
// get heavy cm pos - already have light_cm_pos
|
||||
asteroid_hit_info->heavy_collision_cm_pos = zero;
|
||||
|
||||
// get r_heavy and r_light
|
||||
asteroid_hit_info->r_heavy = asteroid_hit_info->hit_pos;
|
||||
@@ -1191,7 +1207,7 @@ void asteroid_render(object * obj, model_draw_list *scene)
|
||||
/**
|
||||
* Create a normalized vector generally in the direction from *hitpos to other_obj->pos
|
||||
*/
|
||||
static void asc_get_relvec(vec3d *relvec, object *other_obj, vec3d *hitpos)
|
||||
void asc_get_relvec(vec3d *relvec, object *other_obj, vec3d *hitpos)
|
||||
{
|
||||
vec3d tvec, rand_vec;
|
||||
int count = 0;
|
||||
@@ -1213,7 +1229,7 @@ static void asc_get_relvec(vec3d *relvec, object *other_obj, vec3d *hitpos)
|
||||
/**
|
||||
* Return multiplier on asteroid radius for fireball
|
||||
*/
|
||||
static float asteroid_get_fireball_scale_multiplier(int num)
|
||||
float asteroid_get_fireball_scale_multiplier(int num)
|
||||
{
|
||||
if (Asteroids[num].flags & AF_USED) {
|
||||
asteroid_info *asip = &Asteroid_info[Asteroids[num].asteroid_type];
|
||||
@@ -1242,7 +1258,7 @@ static float asteroid_get_fireball_scale_multiplier(int num)
|
||||
* Create asteroid explosion
|
||||
* @return expected time for explosion anim to last, in seconds
|
||||
*/
|
||||
static float asteroid_create_explosion(object *objp)
|
||||
float asteroid_create_explosion(object *objp)
|
||||
{
|
||||
int fireball_objnum;
|
||||
float explosion_life, fireball_scale_multiplier;
|
||||
@@ -1261,7 +1277,7 @@ static float asteroid_create_explosion(object *objp)
|
||||
|
||||
fireball_scale_multiplier = asteroid_get_fireball_scale_multiplier(objp->instance);
|
||||
|
||||
fireball_objnum = fireball_create( &objp->pos, fireball_type, FIREBALL_LARGE_EXPLOSION, OBJ_INDEX(objp), objp->radius*fireball_scale_multiplier, false, &objp->phys_info.vel );
|
||||
fireball_objnum = fireball_create( &objp->pos, fireball_type, FIREBALL_LARGE_EXPLOSION, OBJ_INDEX(objp), objp->radius*fireball_scale_multiplier, 0, &objp->phys_info.vel );
|
||||
if ( fireball_objnum > -1 ) {
|
||||
explosion_life = fireball_lifeleft(&Objects[fireball_objnum]);
|
||||
} else {
|
||||
@@ -1274,23 +1290,23 @@ static float asteroid_create_explosion(object *objp)
|
||||
/**
|
||||
* Play sound when asteroid explodes
|
||||
*/
|
||||
static void asteroid_explode_sound(object *objp, int type, int play_loud)
|
||||
void asteriod_explode_sound(object *objp, int type, int play_loud)
|
||||
{
|
||||
gamesnd_id sound_index;
|
||||
int sound_index = -1;
|
||||
float range_factor = 1.0f; // how many times sound should traver farther than normal
|
||||
|
||||
if (type % NUM_DEBRIS_SIZES <= 1)
|
||||
{
|
||||
sound_index = gamesnd_id(GameSounds::ASTEROID_EXPLODE_SMALL);
|
||||
sound_index = SND_ASTEROID_EXPLODE_SMALL;
|
||||
range_factor = 5.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
sound_index = gamesnd_id(GameSounds::ASTEROID_EXPLODE_LARGE);
|
||||
sound_index = SND_ASTEROID_EXPLODE_LARGE;
|
||||
range_factor = 10.0f;
|
||||
}
|
||||
|
||||
Assert(sound_index.isValid());
|
||||
Assert(sound_index != -1);
|
||||
|
||||
if ( !play_loud ) {
|
||||
range_factor = 1.0f;
|
||||
@@ -1302,9 +1318,9 @@ static void asteroid_explode_sound(object *objp, int type, int play_loud)
|
||||
/**
|
||||
* Do the area effect for an asteroid exploding
|
||||
*
|
||||
* @param asteroid_objp object pointer to asteroid causing explosion
|
||||
* @param asteroid_objp object pointer to asteriod causing explosion
|
||||
*/
|
||||
static void asteroid_do_area_effect(object *asteroid_objp)
|
||||
void asteroid_do_area_effect(object *asteroid_objp)
|
||||
{
|
||||
object *ship_objp;
|
||||
float damage, blast;
|
||||
@@ -1366,7 +1382,7 @@ void asteroid_hit( object * pasteroid_obj, object * other_obj, vec3d * hitpos, f
|
||||
|
||||
explosion_life = asteroid_create_explosion(pasteroid_obj);
|
||||
|
||||
asteroid_explode_sound(pasteroid_obj, asp->asteroid_type, play_loud_collision);
|
||||
asteriod_explode_sound(pasteroid_obj, asp->asteroid_type, play_loud_collision);
|
||||
asteroid_do_area_effect(pasteroid_obj);
|
||||
|
||||
asp->final_death_time = timestamp( fl2i(explosion_life*1000.0f)/5 ); // Wait till 30% of vclip time before breaking the asteroid up.
|
||||
@@ -1385,7 +1401,7 @@ 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()) {
|
||||
if ( wip->impact_weapon_expl_effect < 0 ) {
|
||||
particle::create( hitpos, &vmd_zero_vector, 0.0f, Asteroid_impact_explosion_radius, particle::PARTICLE_BITMAP, Asteroid_impact_explosion_ani );
|
||||
}
|
||||
}
|
||||
@@ -1416,6 +1432,35 @@ void asteroid_level_close()
|
||||
DCF_BOOL2(asteroids, Asteroids_enabled, "enables or disables asteroids", "Usage: asteroids [bool]\nTurns asteroid system on/off. If nothing passed, then toggles it.\n");
|
||||
|
||||
|
||||
void hud_target_asteroid()
|
||||
{
|
||||
int i;
|
||||
int start_index = 0, end_index = MAX_ASTEROIDS;
|
||||
|
||||
if (Player_ai->target_objnum != -1) {
|
||||
if (Objects[Player_ai->target_objnum].type == OBJ_ASTEROID) {
|
||||
start_index = Objects[Player_ai->target_objnum].instance+1;
|
||||
end_index = start_index-1;
|
||||
if (end_index < 0)
|
||||
end_index = MAX_ASTEROIDS;
|
||||
}
|
||||
}
|
||||
|
||||
i = start_index;
|
||||
while (i != end_index) {
|
||||
if (i == MAX_ASTEROIDS)
|
||||
i = 0;
|
||||
|
||||
if (Asteroids[i].flags & AF_USED) {
|
||||
Assert(Objects[Asteroids[i].objnum].type == OBJ_ASTEROID);
|
||||
set_target_objnum( Player_ai, Asteroids[i].objnum);
|
||||
break;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of active asteroids
|
||||
*/
|
||||
@@ -1428,7 +1473,7 @@ int asteroid_count()
|
||||
* See if asteroid should split up.
|
||||
* We delay splitting up to allow the explosion animation to play for a bit.
|
||||
*/
|
||||
static void asteroid_maybe_break_up(object *pasteroid_obj)
|
||||
void asteroid_maybe_break_up(object *pasteroid_obj)
|
||||
{
|
||||
asteroid *asp;
|
||||
asteroid_info *asip;
|
||||
@@ -1545,12 +1590,31 @@ static void asteroid_maybe_break_up(object *pasteroid_obj)
|
||||
}
|
||||
asp->final_death_time = timestamp(-1);
|
||||
}
|
||||
Script_system.RunCondition(CHA_DEATH, pasteroid_obj);
|
||||
Script_system.RunCondition(CHA_DEATH, '\0', NULL, pasteroid_obj);
|
||||
Script_system.RemHookVar("Self");
|
||||
}
|
||||
}
|
||||
|
||||
static void asteroid_test_collide(object *pasteroid_obj, object *pship_obj, mc_info *mc, bool lazy = false)
|
||||
int asteroid_get_random_in_cone(vec3d *pos, vec3d *dir, float ang, int danger)
|
||||
{
|
||||
int idx;
|
||||
vec3d asteroid_dir;
|
||||
|
||||
// just pick the first asteroid which satisfies our condition
|
||||
for(idx=0; idx<Num_asteroids; idx++){
|
||||
vm_vec_sub(&asteroid_dir, &Objects[Asteroids[idx].objnum].pos, pos);
|
||||
vm_vec_normalize_quick(&asteroid_dir);
|
||||
|
||||
// if it satisfies the condition
|
||||
if(vm_vec_dot(dir, &asteroid_dir) >= ang){
|
||||
return idx;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void asteroid_test_collide(object *pasteroid_obj, object *pship_obj, mc_info *mc, bool lazy = false)
|
||||
{
|
||||
float asteroid_ray_dist;
|
||||
vec3d asteroid_fvec, terminus;
|
||||
@@ -1592,7 +1656,7 @@ static void asteroid_test_collide(object *pasteroid_obj, object *pship_obj, mc_i
|
||||
*
|
||||
* @return !0 if the asteroid will collide with the escort
|
||||
*/
|
||||
static int asteroid_will_collide(object *pasteroid_obj, object *escort_objp)
|
||||
int asteroid_will_collide(object *pasteroid_obj, object *escort_objp)
|
||||
{
|
||||
mc_info mc;
|
||||
mc_info_init(&mc);
|
||||
@@ -1610,7 +1674,7 @@ static int asteroid_will_collide(object *pasteroid_obj, object *escort_objp)
|
||||
* Warn if asteroid on collision path with ship
|
||||
* @return !0 if we should warn about asteroid hitting ship, otherwise return 0
|
||||
*/
|
||||
static int asteroid_valid_ship_to_warn_collide(ship *shipp)
|
||||
int asteroid_valid_ship_to_warn_collide(ship *shipp)
|
||||
{
|
||||
if ( !(Ship_info[shipp->ship_info_index].is_big_or_huge()) ) {
|
||||
return 0;
|
||||
@@ -1632,7 +1696,7 @@ static int asteroid_valid_ship_to_warn_collide(ship *shipp)
|
||||
* See if asteroid will collide with a large ship on the escort list in the next
|
||||
* ASTEROID_MIN_COLLIDE_TIME seconds.
|
||||
*/
|
||||
static void asteroid_update_collide_flag(object *asteroid_objp)
|
||||
void asteroid_update_collide_flag(object *asteroid_objp)
|
||||
{
|
||||
int i, num_escorts, escort_objnum, will_collide=0;
|
||||
ship *escort_shipp;
|
||||
@@ -1671,7 +1735,7 @@ static void asteroid_update_collide_flag(object *asteroid_objp)
|
||||
/**
|
||||
* Ensure that the collide objnum for the asteroid is still valid
|
||||
*/
|
||||
static void asteroid_verify_collide_objnum(asteroid *asp)
|
||||
void asteroid_verify_collide_objnum(asteroid *asp)
|
||||
{
|
||||
if ( asp->collide_objnum >= 0 ) {
|
||||
if ( Objects[asp->collide_objnum].signature != asp->collide_objsig ) {
|
||||
@@ -1751,7 +1815,7 @@ float asteroid_time_to_impact(object *asteroid_objp)
|
||||
/**
|
||||
* Read in a single asteroid section from asteroid.tbl
|
||||
*/
|
||||
static void asteroid_parse_section(asteroid_info *asip)
|
||||
void asteroid_parse_section(asteroid_info *asip)
|
||||
{
|
||||
required_string("$Name:");
|
||||
stuff_string(asip->name, F_NAME, NAME_LENGTH);
|
||||
@@ -1851,7 +1915,7 @@ to do with the debris of ships that explode, however these
|
||||
are the same debris and asteroids that get flung at a ship
|
||||
that is being protected.
|
||||
*/
|
||||
static void asteroid_parse_tbl()
|
||||
void asteroid_parse_tbl()
|
||||
{
|
||||
char impact_ani_file[MAX_FILENAME_LEN];
|
||||
|
||||
@@ -2002,7 +2066,7 @@ static void asteroid_parse_tbl()
|
||||
/**
|
||||
* Return number of asteroids expected to collide with a ship.
|
||||
*/
|
||||
static int count_incident_asteroids()
|
||||
int count_incident_asteroids()
|
||||
{
|
||||
object *asteroid_objp;
|
||||
int count;
|
||||
@@ -2026,7 +2090,7 @@ static int count_incident_asteroids()
|
||||
* Pick object to throw asteroids at.
|
||||
* Pick any capital or big ship inside the bounds of the asteroid field.
|
||||
*/
|
||||
static int set_asteroid_throw_objnum()
|
||||
int set_asteroid_throw_objnum()
|
||||
{
|
||||
if (Asteroid_field.num_initial_asteroids < 1)
|
||||
return -1;
|
||||
|
||||
@@ -163,6 +163,7 @@ int asteroid_collide_objnum(object *asteroid_objp);
|
||||
float asteroid_time_to_impact(object *asteroid_objp);
|
||||
void asteroid_show_brackets();
|
||||
void asteroid_target_closest_danger();
|
||||
int asteroid_get_random_in_cone(vec3d *pos, vec3d *dir, float ang, int danger = 0);
|
||||
|
||||
// need to extern for multiplayer
|
||||
void asteroid_sub_create(object *parent_objp, int asteroid_type, vec3d *relvec);
|
||||
|
||||
@@ -122,6 +122,31 @@ vec3d *NavPoint::GetPosition()
|
||||
}
|
||||
}
|
||||
|
||||
char* NavPoint::GetInternalName()
|
||||
{
|
||||
char *NavName;
|
||||
char strtmp[33];
|
||||
|
||||
if (flags & NP_WAYPOINT)
|
||||
{
|
||||
NavName = new char[strlen(((waypoint_list*)target_obj)->get_name())+5];
|
||||
memset(NavName, 0, strlen(((waypoint_list*)target_obj)->get_name())+5);
|
||||
strcpy(NavName, ((waypoint_list*)target_obj)->get_name());
|
||||
|
||||
strcat(NavName, ":");
|
||||
sprintf(strtmp, "%d", waypoint_num);
|
||||
strcat(NavName, strtmp);
|
||||
}
|
||||
else
|
||||
{
|
||||
NavName = new char[strlen(((ship*)target_obj)->ship_name)+1];
|
||||
memset(NavName, 0, strlen(((ship*)target_obj)->ship_name)+1);
|
||||
strcpy(NavName, ((ship*)target_obj)->ship_name);
|
||||
}
|
||||
|
||||
return NavName;
|
||||
}
|
||||
|
||||
// ********************************************************************************************
|
||||
bool CanAutopilot(vec3d targetPos, bool send_msg)
|
||||
{
|
||||
@@ -973,6 +998,7 @@ camera* nav_get_set_camera()
|
||||
return nav_camera.getCamera();
|
||||
}
|
||||
|
||||
extern int Cmdline_old_collision_sys;
|
||||
void nav_warp(bool prewarp=false)
|
||||
{
|
||||
/* ok... find our end distance - norm1 is still a unit vector in the
|
||||
@@ -1027,7 +1053,11 @@ void nav_warp(bool prewarp=false)
|
||||
}
|
||||
|
||||
// retime all collision pairs
|
||||
obj_collide_retime_cached_pairs();
|
||||
if ( Cmdline_old_collision_sys ) {
|
||||
obj_all_collisions_retime();
|
||||
} else {
|
||||
obj_collide_retime_cached_pairs();
|
||||
}
|
||||
}
|
||||
|
||||
// ********************************************************************************************
|
||||
@@ -1201,7 +1231,7 @@ void send_autopilot_msg(char *msg, char *snd)
|
||||
audio_handle = -1;
|
||||
}
|
||||
|
||||
if (msg[0] != '\0' && strcmp(msg, "none") != 0)
|
||||
if (msg[0] != '\0' && strcmp(msg, "none"))
|
||||
change_message("autopilot builtin message", msg, -1, 0);
|
||||
|
||||
// load sound
|
||||
@@ -1216,7 +1246,7 @@ void send_autopilot_msg(char *msg, char *snd)
|
||||
audiostream_play(audio_handle, (Master_event_music_volume * aav_music_volume), 0);
|
||||
}
|
||||
|
||||
if (msg[0] != '\0' && strcmp(msg, "none") != 0)
|
||||
if (msg[0] != '\0' && strcmp(msg, "none"))
|
||||
message_training_queue("autopilot builtin message", timestamp(0), 5); // display message for five seconds
|
||||
}
|
||||
|
||||
@@ -1434,6 +1464,22 @@ bool AddNav_Waypoint(char *Nav, char *WP_Path, int node, int flags)
|
||||
}
|
||||
|
||||
// ********************************************************************************************
|
||||
//Change Flags
|
||||
bool Nav_Alt_Flags(char *Nav, int flags)
|
||||
{
|
||||
flags &= ~NP_VALIDTYPE; //clear the NP_SHIP and NP_WAYPOINT bits, make sure they haven't been set
|
||||
|
||||
int nav = FindNav(Nav);
|
||||
|
||||
if (nav != -1)
|
||||
{
|
||||
Navs[nav].flags &= NP_VALIDTYPE; // Clear all bits BUT NP_SHIP or NO_WAYPOINT
|
||||
Navs[nav].flags |= flags; // merge
|
||||
}
|
||||
|
||||
return (nav != -1);
|
||||
}
|
||||
|
||||
//Get Flags
|
||||
int Nav_Get_Flags(char *Nav)
|
||||
{
|
||||
|
||||
@@ -36,6 +36,7 @@ public:
|
||||
int waypoint_num; //only used when flags & NP_WAYPOINT
|
||||
|
||||
vec3d *GetPosition();
|
||||
char* GetInternalName();
|
||||
|
||||
void clear()
|
||||
{
|
||||
@@ -128,6 +129,9 @@ void SelectNav(char *Nav);
|
||||
// Deselects any navpoint selected.
|
||||
void DeselectNav();
|
||||
|
||||
// Set A Nav point to "ZERO"
|
||||
void ZeroNav(int i);
|
||||
|
||||
// Removes a Nav
|
||||
bool DelNavPoint(char *Nav);
|
||||
bool DelNavPoint(int nav);
|
||||
@@ -136,6 +140,9 @@ bool DelNavPoint(int nav);
|
||||
bool AddNav_Ship(char *Nav, char *TargetName, int flags);
|
||||
bool AddNav_Waypoint(char *Nav, char *WP_Path, int node, int flags);
|
||||
|
||||
//Change Flags
|
||||
bool Nav_Alt_Flags(char *Nav, int flags);
|
||||
|
||||
// Sexp Accessors
|
||||
bool Nav_Set_Flag(char *Nav, int flag);
|
||||
bool Nav_UnSet_Flag(char *Nav, int flag);
|
||||
|
||||
+11
-37
@@ -23,16 +23,6 @@
|
||||
|
||||
#include "bmpman/bmpman.h"
|
||||
|
||||
#include <array>
|
||||
|
||||
/**
|
||||
* @brief Container class for graphics API specific bitmap data
|
||||
*/
|
||||
class gr_bitmap_info {
|
||||
public:
|
||||
virtual ~gr_bitmap_info() = 0;
|
||||
};
|
||||
|
||||
union bm_extra_info {
|
||||
struct {
|
||||
// Stuff needed for animations
|
||||
@@ -67,7 +57,9 @@ struct bitmap_entry {
|
||||
char filename[MAX_FILENAME_LEN]; //!< filename for this bitmap
|
||||
|
||||
uint signature; //!< a unique signature identifying the data
|
||||
uint palette_checksum; //!< checksum used to be sure bitmap is in current palette
|
||||
int handle; //!< Handle = id*MAX_BITMAPS + bitmapnum
|
||||
int last_used; //!< When this bitmap was last used
|
||||
|
||||
BM_TYPE type; //!< PCX, USER, ANI, etc
|
||||
BM_TYPE comp_type; //!< What sort of compressed type, BM_TYPE_NONE if not compressed
|
||||
@@ -98,35 +90,17 @@ struct bitmap_entry {
|
||||
#endif
|
||||
};
|
||||
|
||||
struct bitmap_slot {
|
||||
bitmap_entry entry;
|
||||
|
||||
gr_bitmap_info* gr_info = nullptr;
|
||||
};
|
||||
extern bitmap_entry* bm_bitmaps;
|
||||
|
||||
// image specific lock functions
|
||||
void bm_lock_ani( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ubyte flags );
|
||||
void bm_lock_dds( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ubyte flags );
|
||||
void bm_lock_png( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ubyte flags );
|
||||
void bm_lock_apng( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ubyte flags );
|
||||
void bm_lock_jpg( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ubyte flags );
|
||||
void bm_lock_pcx( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ubyte flags );
|
||||
void bm_lock_tga( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ubyte flags );
|
||||
void bm_lock_user( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ubyte flags );
|
||||
void bm_lock_ani( int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, int bpp, ubyte flags );
|
||||
void bm_lock_dds( int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, int bpp, ubyte flags );
|
||||
void bm_lock_png( int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, int bpp, ubyte flags );
|
||||
void bm_lock_apng( int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, int bpp, ubyte flags );
|
||||
void bm_lock_jpg( int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, int bpp, ubyte flags );
|
||||
void bm_lock_pcx( int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, int bpp, ubyte flags );
|
||||
void bm_lock_tga( int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, int bpp, ubyte flags );
|
||||
void bm_lock_user( int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, int bpp, ubyte flags );
|
||||
|
||||
const size_t BM_BLOCK_SIZE = 4096;
|
||||
|
||||
extern SCP_vector<std::array<bitmap_slot, BM_BLOCK_SIZE>> bm_blocks;
|
||||
|
||||
bitmap_slot* bm_get_slot(int handle, bool separate_ani_frames = true);
|
||||
|
||||
inline bitmap_entry* bm_get_entry(int handle, bool separate_ani_frames = true) {
|
||||
return &bm_get_slot(handle, separate_ani_frames)->entry;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* bm_get_gr_info(int handle, bool separate_ani_frames = true) {
|
||||
return static_cast<T*>(bm_get_slot(handle, separate_ani_frames)->gr_info);
|
||||
}
|
||||
|
||||
#endif // __BM_INTERNAL_H__
|
||||
+834
-776
File diff suppressed because it is too large.
Load diff
+102
-33
@@ -32,6 +32,23 @@
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief How many bitmaps the game can handle by default
|
||||
*
|
||||
* @attention MAX_BITMAPS shouldn't need to be bumped again. With the fixed bm_release() and it's proper use even the
|
||||
* largest missions should stay under this number. With the largest retail missions and wasteful content we should
|
||||
* still have about 20% of the slots free. If it still goes over then it's something the artists need to fix.
|
||||
* For instance the Terran Mara fighter, with -spec and -glow and using the Shinepack, needs 117 bitmap slots alone.
|
||||
* 111 of those is just for the glowmaps. This number can be greatly reduced if the number of ani frames for another
|
||||
* LOD than LOD0 has fewer or no ani frames. A 37 frame glow ani for LOD2 is little more than a waste of resources.
|
||||
* Future reports of texture corruption should be initially approached with content as the cause and not code.
|
||||
* If anything we could/should reduce MAX_BITMAPS in the future. Where it's at now should accomidate even the
|
||||
* largest mods. -- Taylor
|
||||
*/
|
||||
#define DEFAULT_MAX_BITMAPS 4750
|
||||
|
||||
extern int MAX_BITMAPS;
|
||||
|
||||
// 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!! ******
|
||||
#define BMP_AABITMAP (1<<0) //!< antialiased bitmap
|
||||
@@ -98,10 +115,6 @@ struct bitmap
|
||||
*/
|
||||
};
|
||||
|
||||
// Forward definition for the graphics API
|
||||
struct bitmap_entry;
|
||||
struct bitmap_slot;
|
||||
|
||||
extern size_t bm_texture_ram; //!< how many bytes of textures are used.
|
||||
|
||||
extern int Bm_paging; //!< Bool type that indicates if BMPMAN is currently paging.
|
||||
@@ -113,7 +126,12 @@ extern const BM_TYPE bm_ani_type_list[]; //!< List of valid bitmap animation t
|
||||
extern const char *bm_ani_ext_list[]; //!< List of extensions for those types
|
||||
extern const int BM_ANI_NUM_TYPES; //!< Calculated number of bitmap animation types
|
||||
|
||||
extern int GLOWMAP; //!< References a map that is a fully lit version of its index -Bobboau
|
||||
extern int SPECMAP; //!< References a map that is for specular mapping -Bobboau
|
||||
extern int ENVMAP; //!< References a map that is for environment mapping -Bobboau
|
||||
extern int NORMMAP; //!< Normal mapping
|
||||
extern int HEIGHTMAP; //!< Height map for normal mapping
|
||||
extern int MISCMAP; //!< Utility map, to be utilized for various things shader authors can come up with
|
||||
|
||||
/**
|
||||
* @brief Initilizes the bitmap manager
|
||||
@@ -125,6 +143,22 @@ void bm_init();
|
||||
*/
|
||||
void bm_close();
|
||||
|
||||
/**
|
||||
* Gets the cache slot of the bitmap indexed by handle.
|
||||
*
|
||||
* @details if the bitmap is an ani, gets the first frame
|
||||
*
|
||||
* @returns The cache slot index of the bitmap if handle is valid
|
||||
*
|
||||
* @note If the handle is invalid, an Assert() fails
|
||||
*/
|
||||
int bm_get_cache_slot(int bitmap_id, int separate_ani_frames);
|
||||
|
||||
/**
|
||||
* @brief Gets the next available bitmap slot.
|
||||
*/
|
||||
int bm_get_next_handle();
|
||||
|
||||
#define BMP_FLAG_RENDER_TARGET_STATIC (1<<0)
|
||||
#define BMP_FLAG_RENDER_TARGET_DYNAMIC (1<<1)
|
||||
#define BMP_FLAG_CUBEMAP (1<<2)
|
||||
@@ -162,6 +196,9 @@ public:
|
||||
|
||||
bool valid();
|
||||
|
||||
float get_channel_red(float u, float v);
|
||||
float get_channel_green(float u, float v);
|
||||
float get_channel_blue(float u, float v);
|
||||
float get_channel_alpha(float u, float v);
|
||||
};
|
||||
|
||||
@@ -303,6 +340,13 @@ int bm_load_either(const char *filename, int *nframes = NULL, int *fps = NULL, i
|
||||
*/
|
||||
bitmap* bm_lock(int handle, int bpp, ubyte flags, bool nodebug = false);
|
||||
|
||||
/**
|
||||
* @brief Returns a unique signiature for the bitmap indexed by handle
|
||||
*
|
||||
* @details A signature will change when the bitmap's data changes
|
||||
*/
|
||||
uint bm_get_signature(int handle);
|
||||
|
||||
/**
|
||||
* @brief Returns the image type of the given bitmap handle
|
||||
*/
|
||||
@@ -368,6 +412,13 @@ void bm_get_filename(int bitmapnum, char *filename);
|
||||
*/
|
||||
const char *bm_get_filename(int handle);
|
||||
|
||||
/**
|
||||
* @brief Loads all data for all bitmaps that have been requested to be loaded
|
||||
*
|
||||
* @note This function is not defined.
|
||||
*/
|
||||
void bm_gfx_load_all();
|
||||
|
||||
/**
|
||||
* @brief Unloads all used bitmaps, should only ever be called by game_shutdown()
|
||||
*
|
||||
@@ -386,6 +437,15 @@ void bm_unload_all();
|
||||
*/
|
||||
void bm_get_palette(int handle, ubyte *pal, char *name);
|
||||
|
||||
/**
|
||||
* @brief Hack to get a pixel from a bitmap
|
||||
*
|
||||
* @details only works good in 8bpp mode
|
||||
*
|
||||
* @note This function is not defined.
|
||||
*/
|
||||
void bm_gfx_get_pixel(int bitmap, float u, float v, ubyte *r, ubyte *g, ubyte *b);
|
||||
|
||||
/**
|
||||
* @brief (DEBUG) Gets memory size, in bytes, of the locked bitmaps
|
||||
*
|
||||
@@ -444,6 +504,15 @@ void bm_page_in_xparent_texture(int bitmapnum, int num_frames = 1);
|
||||
*/
|
||||
void bm_page_in_aabitmap(int bitmapnum, int num_frames = 1);
|
||||
|
||||
/**
|
||||
* @brief Unloads the bitmap indexed by handle that was previously paged-in
|
||||
*
|
||||
* @returns 0 If the bitmap had already been released, or
|
||||
* @returns 0 If the handle is invalid, or
|
||||
* @returns 1 If successful
|
||||
*/
|
||||
bool bm_page_out(int handle);
|
||||
|
||||
/**
|
||||
* @brief Sets BMPMAN's memory mode
|
||||
*
|
||||
@@ -492,6 +561,16 @@ void BM_SELECT_ALPHA_TEX_FORMAT();
|
||||
*/
|
||||
extern void(*bm_set_components)(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a);
|
||||
|
||||
/**
|
||||
* @brief Functional pointer that references any of the bm_set_components_32 functions.
|
||||
*
|
||||
* @details The bm_set_components functions packs the RGBA values into the ubyte array referenced by pixel, whose
|
||||
* format differs according to its bpp value and presence of an alpha channel. The RGBA values are scaled accordingly.
|
||||
*
|
||||
* @see bm_set_components
|
||||
*/
|
||||
extern void(*bm_set_components_32)(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a);
|
||||
|
||||
/**
|
||||
* @brief Sets the 16bpp screen pixel to the specified RGBA value
|
||||
*
|
||||
@@ -499,6 +578,13 @@ extern void(*bm_set_components)(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyt
|
||||
*/
|
||||
void bm_set_components_argb_16_screen(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a);
|
||||
|
||||
/**
|
||||
* @brief Sets the 32bpp screen pixel to the specified RGBA value
|
||||
*
|
||||
* @see bm_set_components
|
||||
*/
|
||||
void bm_set_components_argb_32_screen(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a);
|
||||
|
||||
/**
|
||||
* @brief Sets the 16bpp texture pixel to the specified RGBA value
|
||||
*
|
||||
@@ -520,7 +606,15 @@ void bm_set_components_argb_32_tex(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, u
|
||||
*/
|
||||
void bm_get_components(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a);
|
||||
|
||||
extern int UNLITMAP; //this holds a reference to a map that is optional used instead of the base map for unlit rendering
|
||||
extern int GLOWMAP; //this holds a reference to a map that is a fully lit version of its index -Bobboau
|
||||
extern int SPECMAP; //this holds a reference to a map that is for specular mapping -Bobboau
|
||||
extern int SPECGLOSSMAP; //this holds a reference to a map that is for specular mapping -Bobboau
|
||||
extern int ENVMAP; //this holds a reference to a map that is for environment mapping -Bobboau
|
||||
extern int NORMMAP; // normal mapping
|
||||
extern int HEIGHTMAP; // height map for normal mapping
|
||||
extern int AMBIENTMAP; // ambient occluion map. red channel affects ambient lighting, green channel affects diffuse and specular
|
||||
extern int MISCMAP; // Utility map, to be utilized for various things shader authors can come up with
|
||||
|
||||
/**
|
||||
* @brief Returns the compression type of the bitmap indexed by handle
|
||||
@@ -532,6 +626,10 @@ int bm_is_compressed(int handle);
|
||||
*/
|
||||
int bm_get_tcache_type(int handle);
|
||||
|
||||
/**
|
||||
* @brief Gets the size, in bytes, taken up by the bitmap indexed by handle
|
||||
*/
|
||||
size_t bm_get_size(int handle);
|
||||
|
||||
/**
|
||||
* @brief Gets the number of mipmaps of the indexed texture
|
||||
@@ -643,33 +741,4 @@ int bm_get_array_index(const int handle);
|
||||
*/
|
||||
int bmpman_count_bitmaps();
|
||||
|
||||
/**
|
||||
* @brief Counts how many slots are available to the bmpman system
|
||||
*
|
||||
* Since the number of slots is dynamic now, this should be used for determining the total amount of available slots at
|
||||
* the moment.
|
||||
*
|
||||
* @warning This is entirely for debugging and logging purposes. It should not be used in actual engine code.
|
||||
*
|
||||
* @return The number of available slots
|
||||
*/
|
||||
int bmpman_count_available_slots();
|
||||
|
||||
/**
|
||||
* @brief Checks if the given filename is a valid effect or texture file name
|
||||
*
|
||||
* @note At least one of @c single_frame or @c animation must be true since the result would make no sense otherwise. It
|
||||
* is also valid to set both parmeters to @c true.
|
||||
*
|
||||
* @todo This currently just tries to load the file but could be improved by not actually loading the file in the future.
|
||||
*
|
||||
* @param file The file name to check
|
||||
* @param single_frame If set to @c true then single frames are valid files
|
||||
* @param animation If set to @c true then animations are valid files
|
||||
* @return @c true if the file name is valid, @c false otherwise
|
||||
*/
|
||||
bool bm_validate_filename(const SCP_string& file, bool single_frame, bool animation);
|
||||
|
||||
SDL_Surface* bm_to_sdl_surface(int handle);
|
||||
|
||||
#endif
|
||||
+18
-24
@@ -7,10 +7,9 @@
|
||||
#include "math/vecmat.h"
|
||||
#include "mod_table/mod_table.h"
|
||||
#include "model/model.h" //polymodel, model_get
|
||||
#include "options/Option.h"
|
||||
#include "parse/parselo.h"
|
||||
#include "playerman/player.h" //player_get_padlock_orient
|
||||
#include "ship/ship.h" //compute_slew_matrix
|
||||
#include "ship/ship.h" //compute_slew_matrix
|
||||
|
||||
//*************************IMPORTANT GLOBALS*************************
|
||||
float VIEWER_ZOOM_DEFAULT = 0.75f; // Default viewer zoom, 0.625 as per multi-lateral agreement on 3/24/97
|
||||
@@ -25,23 +24,6 @@ SCP_vector<camera*> Cameras;
|
||||
camid Current_camera;
|
||||
camid Main_camera;
|
||||
|
||||
static SCP_string fov_display(float val)
|
||||
{
|
||||
auto degrees = fl_degrees(val);
|
||||
SCP_string out;
|
||||
sprintf(out, u8"%.1f\u00B0", degrees);
|
||||
return out;
|
||||
}
|
||||
auto FovOption = options::OptionBuilder<float>("Graphics.FOV", "Field Of View", "The vertical field of view.")
|
||||
.category("Graphics")
|
||||
.range(0.436332f, 1.5708f)
|
||||
.bind_to(&VIEWER_ZOOM_DEFAULT)
|
||||
.display(fov_display)
|
||||
.default_val(0.75f)
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.importance(60)
|
||||
.finish();
|
||||
|
||||
//*************************CLASS: camera*************************
|
||||
//This is where the camera class beings! :D
|
||||
camera::camera(const char *in_name, int in_signature)
|
||||
@@ -163,7 +145,7 @@ void camera::set_object_target(object *objp, int n_object_target_submodel)
|
||||
* Custom function receives the already-modified current position value.
|
||||
* It should be replaced or added to as the custom function modifier sees fit.
|
||||
*/
|
||||
void camera::set_custom_position_function(void (*n_func_custom_position)(camera* /*cam*/, vec3d* /*camera_pos*/))
|
||||
void camera::set_custom_position_function(void (*n_func_custom_position)(camera *cam, vec3d *camera_pos))
|
||||
{
|
||||
func_custom_position = n_func_custom_position;
|
||||
}
|
||||
@@ -172,7 +154,7 @@ void camera::set_custom_position_function(void (*n_func_custom_position)(camera*
|
||||
* Custom function receives the already-modified current orientation value.
|
||||
* It should be replaced or added to as the custom function modifier sees fit.
|
||||
*/
|
||||
void camera::set_custom_orientation_function(void (*n_func_custom_orientation)(camera* /*cam*/, matrix* /*camera_ori*/))
|
||||
void camera::set_custom_orientation_function(void (*n_func_custom_orientation)(camera *cam, matrix *camera_ori))
|
||||
{
|
||||
func_custom_orientation = n_func_custom_orientation;
|
||||
}
|
||||
@@ -203,6 +185,13 @@ void camera::set_position(vec3d *in_position, float in_translation_time, float i
|
||||
pos_z.setAVD(in_position->xyz.z, in_translation_time, in_translation_acceleration_time, in_translation_deceleration_time, in_end_velocity);
|
||||
}
|
||||
|
||||
void camera::set_translation_velocity(vec3d *in_velocity, float in_acceleration_time)
|
||||
{
|
||||
pos_x.setVD(in_acceleration_time, in_acceleration_time, in_velocity->xyz.x);
|
||||
pos_y.setVD(in_acceleration_time, in_acceleration_time, in_velocity->xyz.y);
|
||||
pos_z.setVD(in_acceleration_time, in_acceleration_time, in_velocity->xyz.z);
|
||||
}
|
||||
|
||||
void camera::set_rotation(matrix *in_orientation, float in_rotation_time, float in_rotation_acceleration_time, float in_rotation_deceleration_time)
|
||||
{
|
||||
if(in_orientation != NULL && in_rotation_time == 0.0f && in_rotation_acceleration_time == 0.0f && in_rotation_deceleration_time == 0.0f)
|
||||
@@ -256,7 +245,12 @@ void camera::set_rotation_facing(vec3d *in_target, float in_rotation_time, float
|
||||
set_rotation(&temp_matrix, in_rotation_time, in_rotation_acceleration_time, in_rotation_deceleration_time);
|
||||
}
|
||||
|
||||
void camera::do_frame(float /*in_frametime*/)
|
||||
void camera::set_rotation_velocity(angles *in_rotation_rate, float in_acceleration_time)
|
||||
{
|
||||
Error(LOCATION, "This function is disabled until further notice.");
|
||||
}
|
||||
|
||||
void camera::do_frame(float in_frametime)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -808,7 +802,7 @@ void subtitle::clone(const subtitle &sub)
|
||||
post_shaded = sub.post_shaded;
|
||||
}
|
||||
|
||||
subtitle& subtitle::operator=(const subtitle &sub)
|
||||
const subtitle &subtitle::operator=(const subtitle &sub)
|
||||
{
|
||||
if (this != &sub) {
|
||||
if (image_id != -1) {
|
||||
@@ -968,7 +962,7 @@ size_t cam_get_num()
|
||||
/**
|
||||
* Looks up camera by name, returns -1 on failure
|
||||
*/
|
||||
camid cam_lookup(const char* name)
|
||||
camid cam_lookup(char *name)
|
||||
{
|
||||
size_t i, size=Cameras.size();
|
||||
for(i = 0; i < size; i++)
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
class camera
|
||||
{
|
||||
friend class avd_camera;
|
||||
protected:
|
||||
char name[NAME_LENGTH];
|
||||
int sig;
|
||||
@@ -59,13 +60,15 @@ public:
|
||||
void set_fov(float in_fov, float in_fov_time = 0.0f, float in_fov_acceleration_time = 0.0f, float in_deceleration_time = 0.0f);
|
||||
|
||||
void set_position(vec3d *in_position = NULL, float in_translation_time = 0.0f, float in_translation_acceleration_time = 0.0f, float in_translation_deceleration_time = 0.0f, float in_end_velocity = 0.0f);
|
||||
void set_translation_velocity(vec3d *in_velocity, float in_acceleration_time = 0.0f);
|
||||
|
||||
void set_rotation(matrix *in_orientation = NULL, float in_rotation_time = 0.0f, float in_rotation_acceleration_time = 0.0f, float in_rotation_deceleration_time = 0.0f);
|
||||
void set_rotation(angles *in_angles, float in_rotation_time = 0.0f, float in_rotation_acceleration_time = 0.0f, float in_rotation_deceleration_time = 0.0f);
|
||||
void set_rotation_facing(vec3d *in_target, float in_rotation_time = 0.0f, float in_rotation_acceleration_time = 0.0f, float in_rotation_deceleration_time = 0.0f);
|
||||
void set_rotation_velocity(angles *in_rotation_rate, float in_acceleration_time = 0.0f);
|
||||
|
||||
//Get
|
||||
const char* get_name() { return name; }
|
||||
char *get_name() {return name;}
|
||||
int get_signature() {return sig;}
|
||||
object *get_object_host();
|
||||
int get_object_host_submodel();
|
||||
@@ -140,7 +143,7 @@ public:
|
||||
~subtitle();
|
||||
|
||||
subtitle(const subtitle &sub) { clone(sub); }
|
||||
subtitle& operator=(const subtitle &sub);
|
||||
const subtitle &operator=(const subtitle &sub);
|
||||
|
||||
void do_frame(float frametime);
|
||||
bool is_post_shaded( ) { return post_shaded; }
|
||||
@@ -160,7 +163,7 @@ camid cam_create(const char *n_name, vec3d *n_pos, vec3d *n_norm, object *n_obje
|
||||
void cam_delete(camid cid);
|
||||
bool cam_set_camera(camid cid);
|
||||
void cam_reset_camera();
|
||||
camid cam_lookup(const char* name);
|
||||
camid cam_lookup(char *name);
|
||||
camid cam_get_camera(uint index);
|
||||
camid cam_get_current();
|
||||
size_t cam_get_num();
|
||||
|
||||
+384
-245
File diff suppressed because it is too large.
Load diff
+60
-149
@@ -13,11 +13,10 @@
|
||||
#define __CFILE_H__
|
||||
|
||||
|
||||
#include <time.h>
|
||||
#include "globalincs/pstypes.h"
|
||||
|
||||
#include <ctime>
|
||||
#include <stdexcept>
|
||||
#include <memory>
|
||||
|
||||
|
||||
#define CF_EOF (-1)
|
||||
@@ -26,8 +25,10 @@
|
||||
#define CF_SEEK_CUR (1)
|
||||
#define CF_SEEK_END (2)
|
||||
|
||||
// Opaque file handle
|
||||
struct CFILE;
|
||||
typedef struct CFILE {
|
||||
int id; // Index into cfile.cpp specific structure
|
||||
int version; // version of this file
|
||||
} CFILE;
|
||||
|
||||
// extra info that can be returned when getting a file listing
|
||||
typedef struct {
|
||||
@@ -78,11 +79,9 @@ typedef struct {
|
||||
#define CF_TYPE_SCRIPTS 35
|
||||
#define CF_TYPE_FICTION 36
|
||||
#define CF_TYPE_FREDDOCS 37
|
||||
#define CF_TYPE_INTERFACE_MARKUP 38
|
||||
#define CF_TYPE_INTERFACE_CSS 39
|
||||
|
||||
#define CF_MAX_PATH_TYPES \
|
||||
40 // Can be as high as you'd like //DTP; yeah but beware alot of things uses CF_MAX_PATH_TYPES
|
||||
#define CF_MAX_PATH_TYPES 38 // Can be as high as you'd like //DTP; yeah but beware alot of things uses CF_MAX_PATH_TYPES
|
||||
|
||||
|
||||
// TRUE if type is specified and valid
|
||||
#define CF_TYPE_SPECIFIED(path_type) (((path_type)>CF_TYPE_INVALID) && ((path_type)<CF_MAX_PATH_TYPES))
|
||||
@@ -96,63 +95,8 @@ typedef struct {
|
||||
#define CF_SORT_TIME 2
|
||||
#define CF_SORT_REVERSE 3
|
||||
|
||||
/**
|
||||
* @brief Contains a collection of flags for specifying from where a CFILE should be opened
|
||||
*
|
||||
* There are two types of flags. CF_LOCATION_GAME_ROOT and CF_LOCATION_USER_ROOT specify in which basic root directory
|
||||
* CFile should search for files.
|
||||
*
|
||||
* The remaining flags control what type of location may be used for the operation. It's possible to restrict the
|
||||
* location to the primary mod, the remaining mods or the top-level root directory.
|
||||
*/
|
||||
enum CFileLocationFlags {
|
||||
CF_LOCATION_ROOT_GAME = 1 << 0, //!< The game root location. This is the location of the game data (e.g. FS2 retail)
|
||||
/**
|
||||
* @brief The user directories.
|
||||
*
|
||||
* If the engine is in portable mode then using this flag exclusively will result in a failure to open files!
|
||||
*/
|
||||
CF_LOCATION_ROOT_USER = 1 << 1,
|
||||
|
||||
/**
|
||||
* @brief The memory root
|
||||
*
|
||||
* This contains all the built-in files available to the engine.
|
||||
*/
|
||||
CF_LOCATION_ROOT_MEMORY = 1 << 2,
|
||||
|
||||
/**
|
||||
* @brief Mask for extracting root type from a location bit field
|
||||
*/
|
||||
CF_LOCATION_ROOT_MASK = 0xFFFF,
|
||||
|
||||
CF_LOCATION_TYPE_ROOT = 1 << 16, //!< The basic, top-level root location
|
||||
/**
|
||||
* @brief The primary mod location.
|
||||
*
|
||||
* This is the mod that appears first on the command line. If there are no mods then the root location is considered
|
||||
* to be the primary mod
|
||||
*/
|
||||
CF_LOCATION_TYPE_PRIMARY_MOD = 1 << 17,
|
||||
/**
|
||||
* @brief The remaining mods.
|
||||
*
|
||||
* If there are no mods on the command line then this might not include any valid location.
|
||||
*/
|
||||
CF_LOCATION_TYPE_SECONDARY_MODS = 1 << 18,
|
||||
|
||||
/**
|
||||
* @brief Bitmask for extracting the type from a location bit field
|
||||
*/
|
||||
CF_LOCATION_TYPE_MASK = 0xFFFF0000,
|
||||
|
||||
/**
|
||||
* @brief A combination of all flags
|
||||
*
|
||||
* This should be used when the default behavior without any location filtering is desired.
|
||||
*/
|
||||
CF_LOCATION_ALL = CF_LOCATION_ROOT_MASK | CF_LOCATION_TYPE_MASK
|
||||
};
|
||||
#define cfread_fix(file) (fix)cfread_int(file)
|
||||
#define cfwrite_fix(i,file) cfwrite_int(i,file)
|
||||
|
||||
// callback function used for get_file_list() to filter files to be added to list. Return 1
|
||||
// to add file to list, or 0 to not add it.
|
||||
@@ -165,52 +109,54 @@ extern const char *Get_file_list_child;
|
||||
|
||||
// cfile directory. valid after cfile_init() returns successfully
|
||||
#define CFILE_ROOT_DIRECTORY_LEN 256
|
||||
|
||||
namespace cfile {
|
||||
enum class ModRootType { Unknown, Folder, Package };
|
||||
|
||||
enum class LocationType { Unknown, SecondaryMod, PrimaryMod, GameRoot };
|
||||
|
||||
struct ModRoot {
|
||||
ModRootType type = ModRootType::Unknown;
|
||||
SCP_string path;
|
||||
LocationType location_type = LocationType::Unknown;
|
||||
bool user_location = false;
|
||||
};
|
||||
} // namespace cfile
|
||||
extern char Cfile_root_dir[CFILE_ROOT_DIRECTORY_LEN];
|
||||
extern char Cfile_user_dir[CFILE_ROOT_DIRECTORY_LEN];
|
||||
#ifdef SCP_UNIX
|
||||
extern char Cfile_user_dir_legacy[CFILE_ROOT_DIRECTORY_LEN];
|
||||
#endif
|
||||
|
||||
//================= LOW-LEVEL FUNCTIONS ==================
|
||||
int cfile_init(const SCP_vector<cfile::ModRoot>& modRoots);
|
||||
int cfile_init(const char *exe_dir, const char *cdrom_dir=NULL);
|
||||
void cfile_close();
|
||||
|
||||
// Call this if pack files got added or removed or the
|
||||
// cdrom changed. This will refresh the list of filenames
|
||||
// stored in packfiles and on the cdrom.
|
||||
void cfile_refresh();
|
||||
|
||||
// add an extension to a filename if it doesn't already have it
|
||||
char *cf_add_ext(const char *filename, const char *ext);
|
||||
|
||||
// return CF_TYPE (directory location type) of a CFILE you called cfopen() successfully on.
|
||||
int cf_get_dir_type(CFILE *cfile);
|
||||
|
||||
|
||||
// Opens the file. If no path is given, use the extension to look into the
|
||||
// default path. If mode is NULL, delete the file.
|
||||
CFILE* _cfopen(const char* source_file, int line, const char* filename, const char* mode, int type = CFILE_NORMAL,
|
||||
int dir_type = CF_TYPE_ANY, bool localize = false, uint32_t location_flags = CF_LOCATION_ALL);
|
||||
// default path. If mode is NULL, delete the file.
|
||||
CFILE *_cfopen(const char* source_file, int line, const char *filename, const char *mode,
|
||||
int type = CFILE_NORMAL, int dir_type = CF_TYPE_ANY, bool localize = false);
|
||||
#define cfopen(...) _cfopen(LOCATION, __VA_ARGS__) // Pass source location to the function
|
||||
|
||||
// like cfopen(), but it accepts a fully qualified path only (ie, the result of a cf_find_file_location() call)
|
||||
// NOTE: only supports reading files!!
|
||||
CFILE *_cfopen_special(const char* source_file, int line, const char *file_path, const char *mode,
|
||||
const size_t size, const size_t offset, const void* data, int dir_type = CF_TYPE_ANY);
|
||||
const size_t size, const size_t offset, int dir_type = CF_TYPE_ANY);
|
||||
#define cfopen_special(...) _cfopen_special(LOCATION, __VA_ARGS__) // Pass source location to the function
|
||||
|
||||
// Flush the open file buffer
|
||||
int cflush(CFILE *cfile);
|
||||
|
||||
// version number of opened file. Will be 0 unless you put something else here after you
|
||||
// open a file. Once set, you can use minimum version numbers with the read functions.
|
||||
void cf_set_version( CFILE * cfile, int version );
|
||||
|
||||
// will throw an error if cfread*() functions read past this mark
|
||||
// converted to raw offsets when used, but gets passed actual length from current position
|
||||
// setting 'len' to zero will disable the check
|
||||
void cf_set_max_read_len(CFILE *cfile, size_t len);
|
||||
|
||||
// Deletes a file. Returns 0 on error, 1 if successful
|
||||
int cf_delete(const char *filename, int dir_type, uint32_t location_flags = CF_LOCATION_ALL);
|
||||
int cf_delete(const char *filename, int dir_type);
|
||||
|
||||
// Same as _access function to read a file's access bits
|
||||
int cf_access(const char *filename, int dir_type, int mode);
|
||||
@@ -244,6 +190,10 @@ int cfread(void *buf, int elsize, int nelem, CFILE *fp);
|
||||
// cfwrite() writes to the file
|
||||
int cfwrite(const void *buf, int elsize, int nelem, CFILE *cfile);
|
||||
|
||||
// Reads/writes RLE compressed data.
|
||||
int cfread_compressed(void *buf, int elsize, int nelem, CFILE *cfile);
|
||||
int cfwrite_compressed(void *param_buf, int param_elsize, int param_nelem, CFILE *cfile);
|
||||
|
||||
// Moves the file pointer
|
||||
int cfseek(CFILE *fp, int offset, int where);
|
||||
|
||||
@@ -266,7 +216,7 @@ char *cfgets(char *buf, int n, CFILE *cfile);
|
||||
int cfeof(CFILE *cfile);
|
||||
|
||||
// Return the data pointer associated with the CFILE structure (for memory mapped files)
|
||||
const void *cf_returndata(CFILE *cfile);
|
||||
void *cf_returndata(CFILE *cfile);
|
||||
|
||||
// get the 2 byte checksum of the passed filename - return 0 if operation failed, 1 if succeeded
|
||||
int cf_chksum_short(const char *filename, ushort *chksum, int max_size = -1, int cf_type = CF_TYPE_ANY );
|
||||
@@ -295,6 +245,7 @@ uint cf_add_chksum_long(uint seed, ubyte *buffer, size_t size);
|
||||
// convenient for misc checksumming purposes ------------------------------------------
|
||||
|
||||
//================= HIGH LEVEL FUNCTIONS ==================
|
||||
int cfexist(const char *filename); // Returns true if file exists on disk (1) or in hog (2).
|
||||
|
||||
// rename a file, utilizing the extension to determine where file is.
|
||||
#define CF_RENAME_SUCCESS 0 // successfully renamed the file
|
||||
@@ -312,15 +263,17 @@ int cfile_flush_dir(int type);
|
||||
// functions for reading from cfile
|
||||
// These are all high level, built up from
|
||||
// cfread.
|
||||
int cfgetc(CFILE *fp);
|
||||
char *cfgets(char *buf, size_t n, CFILE *fp);
|
||||
char cfread_char(CFILE* file, char deflt = 0);
|
||||
ubyte cfread_ubyte(CFILE* file, ubyte deflt = 0);
|
||||
short cfread_short(CFILE* file, short deflt = 0);
|
||||
ushort cfread_ushort(CFILE* file, ushort deflt = 0);
|
||||
int cfread_int(CFILE* file, int deflt = 0);
|
||||
uint cfread_uint(CFILE* file, uint deflt = 0);
|
||||
float cfread_float(CFILE* file, float deflt = 0.0f);
|
||||
void cfread_vector(vec3d* vec, CFILE* file, vec3d* deflt = nullptr);
|
||||
char cfread_char(CFILE *file, int ver = 0, char deflt = 0);
|
||||
ubyte cfread_ubyte(CFILE *file, int ver = 0, ubyte deflt = 0);
|
||||
short cfread_short(CFILE *file, int ver = 0, short deflt = 0);
|
||||
ushort cfread_ushort(CFILE *file, int ver = 0, ushort deflt = 0);
|
||||
int cfread_int(CFILE *file, int ver = 0, int deflt = 0);
|
||||
uint cfread_uint(CFILE *file, int ver = 0, uint deflt = 0);
|
||||
float cfread_float(CFILE *file, int ver = 0, float deflt = 0.0f);
|
||||
void cfread_vector(vec3d *vec, CFILE *file, int ver = 0, vec3d *deflt = NULL);
|
||||
void cfread_angles(angles *ang, CFILE *file, int ver = 0, angles *deflt = NULL);
|
||||
|
||||
// Reads variable length, null-termined string. Will only read up
|
||||
// to n characters.
|
||||
@@ -336,13 +289,6 @@ void cfread_string(char *buf,int n, CFILE *file);
|
||||
*/
|
||||
void cfread_string_len(char *buf,int n, CFILE *file);
|
||||
|
||||
/**
|
||||
* @brief Read a string from the file where the length is stored in the file
|
||||
* @param file The file to read the string from
|
||||
* @return The string that was read
|
||||
*/
|
||||
SCP_string cfread_string_len(CFILE *file);
|
||||
|
||||
// functions for writing cfiles
|
||||
int cfwrite_char(char c, CFILE *file);
|
||||
int cfwrite_float(float f, CFILE *file);
|
||||
@@ -351,6 +297,8 @@ int cfwrite_uint(uint i, CFILE *file);
|
||||
int cfwrite_short(short s, CFILE *file);
|
||||
int cfwrite_ushort(ushort s, CFILE *file);
|
||||
int cfwrite_ubyte(ubyte u, CFILE *file);
|
||||
int cfwrite_vector(vec3d *vec, CFILE *file);
|
||||
int cfwrite_angles(angles *ang, CFILE *file);
|
||||
|
||||
// writes variable length, null-termined string.
|
||||
int cfwrite_string(const char *buf, CFILE *file);
|
||||
@@ -363,26 +311,12 @@ int cfwrite_string(const char *buf, CFILE *file);
|
||||
*/
|
||||
int cfwrite_string_len(const char *buf, CFILE *file);
|
||||
|
||||
int cf_get_file_list(SCP_vector<SCP_string>& list, int pathtype, const char* filter, int sort = CF_SORT_NONE,
|
||||
SCP_vector<file_list_info>* info = nullptr, uint32_t location_flags = CF_LOCATION_ALL);
|
||||
int cf_get_file_list(int max, char** list, int type, const char* filter, int sort = CF_SORT_NONE,
|
||||
file_list_info* info = nullptr, uint32_t location_flags = CF_LOCATION_ALL);
|
||||
int cf_get_file_list_preallocated(int max, char arr[][MAX_FILENAME_LEN], char** list, int type, const char* filter,
|
||||
int sort = CF_SORT_NONE, file_list_info* info = nullptr,
|
||||
uint32_t location_flags = CF_LOCATION_ALL);
|
||||
int cf_get_file_list( SCP_vector<SCP_string> &list, int pathtype, const char *filter, int sort = CF_SORT_NONE, SCP_vector<file_list_info> *info = NULL );
|
||||
int cf_get_file_list( int max, char **list, int type, const char *filter, int sort = CF_SORT_NONE, file_list_info *info = NULL );
|
||||
int cf_get_file_list_preallocated( int max, char arr[][MAX_FILENAME_LEN], char **list, int type, const char *filter, int sort = CF_SORT_NONE, file_list_info *info = NULL );
|
||||
void cf_sort_filenames( int n, char **list, int sort, file_list_info *info = NULL );
|
||||
void cf_sort_filenames( SCP_vector<SCP_string> &list, int sort, SCP_vector<file_list_info> *info = NULL );
|
||||
|
||||
struct CFileLocation {
|
||||
bool found = false;
|
||||
SCP_string full_name;
|
||||
size_t size = 0;
|
||||
size_t offset = 0;
|
||||
const void* data_ptr = nullptr;
|
||||
|
||||
explicit CFileLocation(bool found_in = false) : found(found_in) {}
|
||||
};
|
||||
|
||||
// Searches for a file. Follows all rules and precedence and searches
|
||||
// CD's and pack files.
|
||||
// Input: filespace - Filename & extension
|
||||
@@ -392,17 +326,7 @@ struct CFileLocation {
|
||||
// size - File size
|
||||
// offset - Offset into pack file. 0 if not a packfile.
|
||||
// Returns: If not found returns 0.
|
||||
CFileLocation cf_find_file_location(const char* filespec, int pathtype, bool localize = false,
|
||||
uint32_t location_flags = CF_LOCATION_ALL);
|
||||
|
||||
struct CFileLocationExt : public CFileLocation {
|
||||
int extension_index = -1;
|
||||
|
||||
explicit CFileLocationExt(int extension_index_in = -1)
|
||||
: CFileLocation(extension_index_in >= 0), extension_index(extension_index_in)
|
||||
{
|
||||
}
|
||||
};
|
||||
int cf_find_file_location( const char *filespec, int pathtype, int max_out, char *pack_filename, size_t *size, size_t *offset, bool localize = false);
|
||||
|
||||
// Searches for a file. Follows all rules and precedence and searches
|
||||
// CD's and pack files. Searches all locations in order for first filename using ext filter list.
|
||||
@@ -416,8 +340,7 @@ struct CFileLocationExt : public CFileLocation {
|
||||
// offset - Offset into pack file. 0 if not a packfile.
|
||||
// Returns: If not found returns -1, else returns offset into ext_list.
|
||||
// (NOTE: This function is exponentially slow, so don't use it unless truely needed!!)
|
||||
CFileLocationExt cf_find_file_location_ext(const char* filename, const int ext_num, const char** ext_list, int pathtype,
|
||||
bool localize = false);
|
||||
int cf_find_file_location_ext(const char *filename, const int ext_num, const char **ext_list, int pathtype, int max_out = 0, char *pack_filename = NULL, size_t *size = NULL, size_t *offset = NULL, bool localize = false);
|
||||
|
||||
// Functions to change directories
|
||||
int cfile_chdir(const char *dir);
|
||||
@@ -432,8 +355,6 @@ int cfile_push_chdir(int type);
|
||||
// restore directory on top of the stack
|
||||
int cfile_pop_dir();
|
||||
|
||||
int cfile_get_path_type(const SCP_string& dir);
|
||||
|
||||
namespace cfile
|
||||
{
|
||||
// exceptions and other errors
|
||||
@@ -444,13 +365,16 @@ namespace cfile
|
||||
{
|
||||
}
|
||||
|
||||
explicit cfile_error(const std::string &excuse) : m_excuse(excuse)
|
||||
cfile_error(const std::string &excuse) : m_excuse(excuse)
|
||||
{
|
||||
}
|
||||
|
||||
~cfile_error() SCP_NOEXCEPT override {}
|
||||
~cfile_error() throw()
|
||||
{
|
||||
}
|
||||
|
||||
const char *what() const SCP_NOEXCEPT override {
|
||||
virtual const char *what() const throw()
|
||||
{
|
||||
return m_excuse.c_str();
|
||||
}
|
||||
|
||||
@@ -461,7 +385,7 @@ namespace cfile
|
||||
class max_read_length : public cfile_error
|
||||
{
|
||||
public:
|
||||
explicit max_read_length(const std::string &excuse) : cfile_error(excuse)
|
||||
max_read_length(const std::string &excuse) : cfile_error(excuse)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -472,17 +396,4 @@ namespace cfile
|
||||
|
||||
}
|
||||
|
||||
// This allows to use std::unique_ptr with CFILE
|
||||
namespace std {
|
||||
template <>
|
||||
struct default_delete<CFILE> {
|
||||
void operator()(CFILE* ptr)
|
||||
{
|
||||
if (cf_is_valid(ptr)) {
|
||||
cfclose(ptr);
|
||||
}
|
||||
}
|
||||
};
|
||||
} // namespace std
|
||||
|
||||
#endif /* __CFILE_H__ */
|
||||
+87
-86
@@ -11,9 +11,9 @@
|
||||
|
||||
#define _CFILE_INTERNAL
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
@@ -36,20 +36,24 @@
|
||||
|
||||
void cf_init_lowlevel_read_code( CFILE * cfile, size_t lib_offset, size_t size, size_t pos )
|
||||
{
|
||||
Assert(cfile != nullptr);
|
||||
Assert(cfile != NULL);
|
||||
|
||||
cfile->lib_offset = lib_offset;
|
||||
cfile->raw_position = pos;
|
||||
cfile->size = size;
|
||||
Cfile_block *cb;
|
||||
Assert(cfile->id >= 0 && cfile->id < MAX_CFILE_BLOCKS);
|
||||
cb = &Cfile_block_list[cfile->id];
|
||||
|
||||
if ( cfile->fp ) {
|
||||
if ( cfile->lib_offset ) {
|
||||
fseek( cfile->fp, (long)cfile->lib_offset, SEEK_SET );
|
||||
cb->lib_offset = lib_offset;
|
||||
cb->raw_position = pos;
|
||||
cb->size = size;
|
||||
|
||||
if ( cb->fp ) {
|
||||
if ( cb->lib_offset ) {
|
||||
fseek( cb->fp, (long)cb->lib_offset, SEEK_SET );
|
||||
}
|
||||
|
||||
#if defined(CHECK_POSITION) && !defined(NDEBUG)
|
||||
auto raw_position = ftell(cfile->fp) - cfile->lib_offset;
|
||||
Assert(raw_position == cfile->raw_position);
|
||||
auto raw_position = ftell(cb->fp) - cb->lib_offset;
|
||||
Assert(raw_position == cb->raw_position);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -66,16 +70,25 @@ int cfeof(CFILE *cfile)
|
||||
{
|
||||
Assert(cfile != NULL);
|
||||
|
||||
int result = 0;
|
||||
Cfile_block *cb;
|
||||
Assert(cfile->id >= 0 && cfile->id < MAX_CFILE_BLOCKS);
|
||||
cb = &Cfile_block_list[cfile->id];
|
||||
|
||||
int result;
|
||||
|
||||
result = 0;
|
||||
|
||||
// cfeof() not supported for memory-mapped files
|
||||
Assert( !cb->data );
|
||||
|
||||
Assert(cb->fp != NULL);
|
||||
|
||||
#if defined(CHECK_POSITION) && !defined(NDEBUG)
|
||||
if (cfile->fp) {
|
||||
auto raw_position = ftell(cfile->fp) - cfile->lib_offset;
|
||||
Assert(raw_position == cfile->raw_position);
|
||||
}
|
||||
auto raw_position = ftell(cb->fp) - cb->lib_offset;
|
||||
Assert(raw_position == cb->raw_position);
|
||||
#endif
|
||||
|
||||
if (cfile->raw_position >= cfile->size ) {
|
||||
if (cb->raw_position >= cb->size ) {
|
||||
result = 1;
|
||||
} else {
|
||||
result = 0;
|
||||
@@ -92,18 +105,24 @@ int cfeof(CFILE *cfile)
|
||||
int cftell( CFILE * cfile )
|
||||
{
|
||||
Assert(cfile != NULL);
|
||||
Cfile_block *cb;
|
||||
Assert(cfile->id >= 0 && cfile->id < MAX_CFILE_BLOCKS);
|
||||
cb = &Cfile_block_list[cfile->id];
|
||||
|
||||
// Doesn't work for memory mapped files
|
||||
Assert( !cb->data );
|
||||
|
||||
Assert(cb->fp != NULL);
|
||||
|
||||
#if defined(CHECK_POSITION) && !defined(NDEBUG)
|
||||
if (cfile->fp) {
|
||||
auto raw_position = ftell(cfile->fp) - cfile->lib_offset;
|
||||
Assert(raw_position == cfile->raw_position);
|
||||
}
|
||||
auto raw_position = ftell(cb->fp) - cb->lib_offset;
|
||||
Assert(raw_position == cb->raw_position);
|
||||
#endif
|
||||
|
||||
// The rest of the code still uses ints, do an overflow check to detect cases where this fails
|
||||
Assertion(cfile->raw_position <= static_cast<size_t>(std::numeric_limits<int>::max()),
|
||||
Assertion(cb->raw_position <= static_cast<size_t>(std::numeric_limits<int>::max()),
|
||||
"Integer overflow in cftell, a file is probably too large (but I don't know which one).");
|
||||
return (int) cfile->raw_position;
|
||||
return (int) cb->raw_position;
|
||||
}
|
||||
|
||||
|
||||
@@ -116,23 +135,28 @@ int cfseek( CFILE *cfile, int offset, int where )
|
||||
{
|
||||
|
||||
Assert(cfile != NULL);
|
||||
Cfile_block *cb;
|
||||
Assert(cfile->id >= 0 && cfile->id < MAX_CFILE_BLOCKS);
|
||||
cb = &Cfile_block_list[cfile->id];
|
||||
|
||||
|
||||
// TODO: seek to offset in memory mapped file
|
||||
Assert( !cfile->mem_mapped );
|
||||
Assert( !cb->data );
|
||||
Assert( cb->fp != NULL );
|
||||
|
||||
size_t goal_position;
|
||||
|
||||
switch( where ) {
|
||||
case CF_SEEK_SET:
|
||||
goal_position = offset+cfile->lib_offset;
|
||||
goal_position = offset+cb->lib_offset;
|
||||
break;
|
||||
case CF_SEEK_CUR:
|
||||
{
|
||||
goal_position = cfile->raw_position+offset+cfile->lib_offset;
|
||||
goal_position = cb->raw_position+offset+cb->lib_offset;
|
||||
}
|
||||
break;
|
||||
case CF_SEEK_END:
|
||||
goal_position = cfile->size+offset+cfile->lib_offset;
|
||||
goal_position = cb->size+offset+cb->lib_offset;
|
||||
break;
|
||||
default:
|
||||
Int3();
|
||||
@@ -140,24 +164,16 @@ int cfseek( CFILE *cfile, int offset, int where )
|
||||
}
|
||||
|
||||
// Make sure we don't seek beyond the end of the file
|
||||
CAP(goal_position, cfile->lib_offset, cfile->lib_offset + cfile->size);
|
||||
CAP(goal_position, cb->lib_offset, cb->lib_offset + cb->size);
|
||||
|
||||
int result = 0;
|
||||
|
||||
if (cfile->fp) {
|
||||
// If we have a file pointer we can also seek in that file
|
||||
result = fseek(cfile->fp, (long)goal_position, SEEK_SET );
|
||||
Assertion(goal_position >= cfile->lib_offset, "Invalid offset values detected while seeking! Goal was " SIZE_T_ARG ", lib_offset is " SIZE_T_ARG ".", goal_position, cfile->lib_offset);
|
||||
}
|
||||
// If we only have a data pointer this will do all the work
|
||||
cfile->raw_position = goal_position - cfile->lib_offset;
|
||||
Assertion(cfile->raw_position <= cfile->size, "Invalid raw_position value detected!");
|
||||
int result = fseek(cb->fp, (long)goal_position, SEEK_SET );
|
||||
Assertion(goal_position >= cb->lib_offset, "Invalid offset values detected while seeking! Goal was " SIZE_T_ARG ", lib_offset is " SIZE_T_ARG ".", goal_position, cb->lib_offset);
|
||||
cb->raw_position = goal_position - cb->lib_offset;
|
||||
Assertion(cb->raw_position <= cb->size, "Invalid raw_position value detected!");
|
||||
|
||||
#if defined(CHECK_POSITION) && !defined(NDEBUG)
|
||||
if (cfile->fp) {
|
||||
auto tmp_offset = ftell(cfile->fp) - cfile->lib_offset;
|
||||
Assert(tmp_offset == cfile->raw_position);
|
||||
}
|
||||
auto tmp_offset = ftell(cb->fp) - cb->lib_offset;
|
||||
Assert(tmp_offset==cb->raw_position);
|
||||
#endif
|
||||
|
||||
return result;
|
||||
@@ -179,17 +195,26 @@ int cfread(void *buf, int elsize, int nelem, CFILE *cfile)
|
||||
if(buf == NULL || size <= 0)
|
||||
return 0;
|
||||
|
||||
if ( (cfile->raw_position+size) > cfile->size ) {
|
||||
Assertion(cfile->raw_position <= cfile->size, "Invalid raw_position value detected!");
|
||||
size = cfile->size - cfile->raw_position;
|
||||
Cfile_block *cb = &Cfile_block_list[cfile->id];
|
||||
|
||||
// cfread() not supported for memory-mapped files
|
||||
if(cb->data != NULL)
|
||||
{
|
||||
Warning(LOCATION, "Writing is not supported for mem-mapped files");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( (cb->raw_position+size) > cb->size ) {
|
||||
Assertion(cb->raw_position <= cb->size, "Invalid raw_position value detected!");
|
||||
size = cb->size - cb->raw_position;
|
||||
if ( size < 1 ) {
|
||||
return 0;
|
||||
}
|
||||
//mprintf(( "CFILE: EOF encountered in file\n" ));
|
||||
}
|
||||
|
||||
if (cfile->max_read_len) {
|
||||
if ( cfile->raw_position+size > cfile->max_read_len ) {
|
||||
if (cb->max_read_len) {
|
||||
if ( cb->raw_position+size > cb->max_read_len ) {
|
||||
std::ostringstream s_buf;
|
||||
s_buf << "Attempted to read " << size << "-byte(s) beyond length limit";
|
||||
|
||||
@@ -197,24 +222,15 @@ int cfread(void *buf, int elsize, int nelem, CFILE *cfile)
|
||||
}
|
||||
}
|
||||
|
||||
size_t bytes_read;
|
||||
if (cfile->data != nullptr) {
|
||||
// This is a file from memory
|
||||
bytes_read = size;
|
||||
memcpy(buf, reinterpret_cast<const char*>(cfile->data) + cfile->raw_position, size);
|
||||
} else {
|
||||
bytes_read = fread( buf, 1, size, cfile->fp );
|
||||
}
|
||||
size_t bytes_read = fread( buf, 1, size, cb->fp );
|
||||
if ( bytes_read > 0 ) {
|
||||
cfile->raw_position += bytes_read;
|
||||
Assertion(cfile->raw_position <= cfile->size, "Invalid raw_position value detected!");
|
||||
cb->raw_position += bytes_read;
|
||||
Assertion(cb->raw_position <= cb->size, "Invalid raw_position value detected!");
|
||||
}
|
||||
|
||||
#if defined(CHECK_POSITION) && !defined(NDEBUG)
|
||||
if (cfile->fp) {
|
||||
auto tmp_offset = ftell(cfile->fp) - cfile->lib_offset;
|
||||
Assert(tmp_offset==cfile->raw_position);
|
||||
}
|
||||
auto tmp_offset = ftell(cb->fp) - cb->lib_offset;
|
||||
Assert(tmp_offset==cb->raw_position);
|
||||
#endif
|
||||
|
||||
return (int)(bytes_read / elsize);
|
||||
@@ -229,38 +245,23 @@ int cfread_lua_number(double *buf, CFILE *cfile)
|
||||
if(buf == NULL)
|
||||
return 0;
|
||||
|
||||
Cfile_block *cb = &Cfile_block_list[cfile->id];
|
||||
|
||||
// cfread() not supported for memory-mapped files
|
||||
if(cfile->data != nullptr)
|
||||
if(cb->data != NULL)
|
||||
{
|
||||
Warning(LOCATION, "Writing is not supported for mem-mapped files");
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t advance = 0;
|
||||
int items_read;
|
||||
if (cfile->fp) {
|
||||
long orig_pos = ftell(cfile->fp);
|
||||
items_read = fscanf(cfile->fp, LUA_NUMBER_SCAN, buf);
|
||||
advance = (size_t) (ftell(cfile->fp)-orig_pos);
|
||||
} else {
|
||||
int read;
|
||||
// %n returns the number of bytes currently read so we append that to the scan format at the end so it will return
|
||||
// how many bytes we have consumed
|
||||
items_read = sscanf(reinterpret_cast<const char*>(cfile->data), LUA_NUMBER_SCAN "%n", buf, &read);
|
||||
if (items_read == 2) {
|
||||
// We need to correct the items read counter since we read one additional item
|
||||
items_read = 1;
|
||||
}
|
||||
advance = (size_t) read;
|
||||
}
|
||||
cfile->raw_position += advance;
|
||||
Assertion(cfile->raw_position <= cfile->size, "Invalid raw_position value detected!");
|
||||
long orig_pos = ftell(cb->fp);
|
||||
int items_read = fscanf(cb->fp, LUA_NUMBER_SCAN, buf);
|
||||
cb->raw_position += ftell(cb->fp)-orig_pos;
|
||||
Assertion(cb->raw_position <= cb->size, "Invalid raw_position value detected!");
|
||||
|
||||
#if defined(CHECK_POSITION) && !defined(NDEBUG)
|
||||
if (cfile->fp) {
|
||||
auto tmp_offset = ftell(cfile->fp) - cfile->lib_offset;
|
||||
Assert(tmp_offset==cfile->raw_position);
|
||||
}
|
||||
auto tmp_offset = ftell(cb->fp) - cb->lib_offset;
|
||||
Assert(tmp_offset==cb->raw_position);
|
||||
#endif
|
||||
|
||||
return items_read;
|
||||
|
||||
+14
-14
@@ -22,30 +22,30 @@
|
||||
#define CFILE_BLOCK_UNUSED 0
|
||||
#define CFILE_BLOCK_USED 1
|
||||
|
||||
struct CFILE {
|
||||
int type = CFILE_BLOCK_UNUSED; // CFILE_BLOCK_UNUSED, CFILE_BLOCK_USED
|
||||
int dir_type; // directory location
|
||||
FILE* fp; // File pointer if opening an individual file
|
||||
const void* data; // Pointer for memory-mapped file access. NULL if not mem-mapped.
|
||||
bool mem_mapped; // Flag for memory mapped files (if data is not null and this is false it means that it's an embedded file)
|
||||
typedef struct Cfile_block {
|
||||
int type; // CFILE_BLOCK_UNUSED, CFILE_BLOCK_USED
|
||||
int dir_type; // directory location
|
||||
FILE *fp; // File pointer if opening an individual file
|
||||
void *data; // Pointer for memory-mapped file access. NULL if not mem-mapped.
|
||||
#ifdef _WIN32
|
||||
HANDLE hInFile; // Handle from CreateFile()
|
||||
HANDLE hMapFile; // Handle from CreateFileMapping()
|
||||
#else
|
||||
size_t data_length; // length of data for mmap
|
||||
// int fd; // file descriptor
|
||||
size_t data_length; // length of data for mmap
|
||||
#endif
|
||||
size_t lib_offset;
|
||||
size_t raw_position;
|
||||
size_t size; // for packed files
|
||||
|
||||
size_t max_read_len; // max read offset, for special error handling
|
||||
size_t lib_offset;
|
||||
size_t raw_position;
|
||||
size_t size; // for packed files
|
||||
|
||||
size_t max_read_len; // max read offset, for special error handling
|
||||
|
||||
const char* source_file;
|
||||
int line_num;
|
||||
};
|
||||
} Cfile_block;
|
||||
|
||||
#define MAX_CFILE_BLOCKS 64
|
||||
extern std::array<CFILE, MAX_CFILE_BLOCKS> Cfile_block_list;
|
||||
extern Cfile_block Cfile_block_list[MAX_CFILE_BLOCKS];
|
||||
|
||||
// Called once to setup the low-level reading code.
|
||||
void cf_init_lowlevel_read_code( CFILE * cfile, size_t lib_offset, size_t size, size_t pos );
|
||||
|
||||
+353
-4
@@ -9,9 +9,9 @@
|
||||
|
||||
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
@@ -200,4 +200,353 @@ void cf_sort_filenames( int n, char **list, int sort, file_list_info *info )
|
||||
}
|
||||
|
||||
nprintf(("Error", "Unknown sorting method %d passed to cf_sort_filenames()\n", sort));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if (0) // these aren't used anywhere now
|
||||
|
||||
// cf_compress - Do Run Length Compression on a block of data. Targa format.
|
||||
//
|
||||
// Usage:
|
||||
// out Buffer to write it out to
|
||||
// in Buffer to compress
|
||||
// bytecount Number of bytes input
|
||||
int cf_compress(char *out, char *in, int bytecount )
|
||||
{
|
||||
int pixcount; // number of pixels in the current packet
|
||||
char *inputpixel=NULL; // current input pixel position
|
||||
char *matchpixel=NULL; // pixel value to match for a run
|
||||
char *flagbyte=NULL; // location of last flag byte to set
|
||||
int rlcount; // current count in r.l. string
|
||||
int rlthresh; // minimum valid run length
|
||||
char *copyloc; // location to begin copying at
|
||||
|
||||
// set the threshold -- the minimum valid run length
|
||||
rlthresh = 2; // Require a 2 pixel span before rle'ing
|
||||
|
||||
// set the first pixel up
|
||||
|
||||
flagbyte = out; // place to put next flag if run
|
||||
inputpixel = in;
|
||||
pixcount = 1;
|
||||
rlcount = 0;
|
||||
copyloc = (char *)0;
|
||||
|
||||
// loop till data processing complete
|
||||
do {
|
||||
|
||||
// if we have accumulated a 128-byte packet, process it
|
||||
if ( pixcount == 129 ) {
|
||||
*flagbyte = 127;
|
||||
|
||||
// set the run flag if this is a run
|
||||
|
||||
if ( rlcount >= rlthresh ) {
|
||||
*flagbyte |= 0x80;
|
||||
pixcount = 2;
|
||||
}
|
||||
|
||||
// copy the data into place
|
||||
++flagbyte;
|
||||
memmove( flagbyte, copyloc, pixcount-1 );
|
||||
flagbyte += pixcount-1;
|
||||
pixcount = 1;
|
||||
|
||||
// set up for next packet
|
||||
continue;
|
||||
}
|
||||
|
||||
// if zeroth byte, handle as special case
|
||||
if ( pixcount == 1 ) {
|
||||
rlcount = 0;
|
||||
copyloc = inputpixel; /* point to 1st guy in packet */
|
||||
matchpixel = inputpixel; /* set pointer to pix to match */
|
||||
pixcount = 2;
|
||||
inputpixel += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// assembling a packet -- look at next pixel
|
||||
|
||||
// current pixel == match pixel?
|
||||
if ( *inputpixel == *matchpixel ) {
|
||||
|
||||
// establishing a run of enough length to
|
||||
// save space by doing it
|
||||
// -- write the non-run length packet
|
||||
// -- start run-length packet
|
||||
|
||||
if ( ++rlcount == rlthresh ) {
|
||||
|
||||
// close a non-run packet
|
||||
|
||||
if ( pixcount > (rlcount+1) ) {
|
||||
// write out length and do not set run flag
|
||||
|
||||
*flagbyte++ = (char)(pixcount - 2 - rlthresh);
|
||||
|
||||
memmove(flagbyte, copyloc, (pixcount-1-rlcount) );
|
||||
flagbyte += (pixcount-1-rlcount);
|
||||
|
||||
copyloc = inputpixel;
|
||||
pixcount = rlcount + 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
// no match -- either break a run or continue without one
|
||||
// if a run exists break it:
|
||||
// write the bytes in the string (1+1)
|
||||
// start the next string
|
||||
|
||||
if ( rlcount >= rlthresh ) {
|
||||
|
||||
*flagbyte++ = (char)(0x80 | rlcount);
|
||||
memmove(flagbyte, copyloc, 1 );
|
||||
flagbyte += 1;
|
||||
pixcount = 1;
|
||||
continue;
|
||||
} else {
|
||||
|
||||
// not a match and currently not a run
|
||||
// - save the current pixel
|
||||
// - reset the run-length flag
|
||||
rlcount = 0;
|
||||
matchpixel = inputpixel;
|
||||
}
|
||||
}
|
||||
pixcount++;
|
||||
inputpixel += 1;
|
||||
} while ( inputpixel < (in + bytecount));
|
||||
|
||||
// quit this buffer without loosing any data
|
||||
if ( --pixcount >= 1 ) {
|
||||
*flagbyte = (char)(pixcount - 1);
|
||||
if ( rlcount >= rlthresh ) {
|
||||
*flagbyte |= 0x80;
|
||||
pixcount = 1;
|
||||
}
|
||||
|
||||
// copy the data into place
|
||||
++flagbyte;
|
||||
memmove(flagbyte, copyloc, pixcount );
|
||||
flagbyte += pixcount;
|
||||
}
|
||||
return(flagbyte-out);
|
||||
}
|
||||
|
||||
|
||||
// cf_decompress - Do Decompression on a run-length encoded block of data. Targa format.
|
||||
//
|
||||
// Usage:
|
||||
// out Buffer to write it out to
|
||||
// in Buffer to compress
|
||||
// bytecount Number of bytes input
|
||||
int cf_decompress(char *out, char *in )
|
||||
{
|
||||
int count;
|
||||
|
||||
char *param_out = out;
|
||||
|
||||
while(1) {
|
||||
|
||||
count = int(*in++);
|
||||
int run_span = count & 0x80;
|
||||
|
||||
count &= (~0x80);
|
||||
|
||||
if ( count > 0 ) {
|
||||
if ( run_span ) {
|
||||
// RLE'd data
|
||||
ubyte c = *in++;
|
||||
|
||||
memset( out, c, count );
|
||||
out += count;
|
||||
} else {
|
||||
memmove( out, in, count );
|
||||
in += count;
|
||||
out += count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return out - param_out;
|
||||
|
||||
}
|
||||
|
||||
#endif // 0
|
||||
|
||||
|
||||
// cfread() reads from a file and decompresses it
|
||||
//
|
||||
// returns: returns the number of full elements read
|
||||
//
|
||||
//
|
||||
int cfread_compressed(void *buf, int elsize, int nelem, CFILE *cfile)
|
||||
{
|
||||
char *out = (char *)buf;
|
||||
|
||||
while(1) {
|
||||
|
||||
ubyte count;
|
||||
|
||||
if ( cfread( &count, 1, 1, cfile ) != 1 ) {
|
||||
break;
|
||||
}
|
||||
|
||||
int run_span = count & 0x80;
|
||||
count &= (~0x80);
|
||||
count++;
|
||||
|
||||
if ( count > 0 ) {
|
||||
if ( run_span ) {
|
||||
// RLE'd data
|
||||
ubyte c;
|
||||
if ( cfread( &c, 1, 1, cfile ) != 1 ) {
|
||||
break;
|
||||
}
|
||||
memset( out, c, count );
|
||||
} else {
|
||||
if ( cfread( out, 1, count, cfile ) != count ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
out += count;
|
||||
if ( out >= (char *)buf + (elsize*nelem)) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (int)((out - (char *)buf)/elsize);
|
||||
}
|
||||
|
||||
int cfwrite_compressed(void *param_buf, int param_elsize, int param_nelem, CFILE *cfile)
|
||||
{
|
||||
char *in = (char *)param_buf;
|
||||
int bytecount = (param_elsize * param_nelem );
|
||||
|
||||
int pixcount; // number of pixels in the current packet
|
||||
char *inputpixel=NULL; // current input pixel position
|
||||
char *matchpixel=NULL; // pixel value to match for a run
|
||||
int rlcount; // current count in r.l. string
|
||||
int rlthresh; // minimum valid run length
|
||||
char *copyloc; // location to begin copying at
|
||||
|
||||
// set the threshold -- the minimum valid run length
|
||||
rlthresh = 2; // Require a 2 pixel span before rle'ing
|
||||
|
||||
// set the first pixel up
|
||||
|
||||
inputpixel = in;
|
||||
pixcount = 1;
|
||||
rlcount = 0;
|
||||
copyloc = (char *)0;
|
||||
|
||||
// loop till data processing complete
|
||||
do {
|
||||
|
||||
// if we have accumulated a 128-byte packet, process it
|
||||
if ( pixcount == 129 ) {
|
||||
ubyte code = 127;
|
||||
|
||||
// set the run flag if this is a run
|
||||
|
||||
if ( rlcount >= rlthresh ) {
|
||||
code |= 0x80;
|
||||
pixcount = 2;
|
||||
}
|
||||
|
||||
cfwrite( &code, 1, 1, cfile );
|
||||
|
||||
// copy the data into place
|
||||
cfwrite( copyloc, 1, pixcount-1, cfile );
|
||||
pixcount = 1;
|
||||
|
||||
// set up for next packet
|
||||
continue;
|
||||
}
|
||||
|
||||
// if zeroth byte, handle as special case
|
||||
if ( pixcount == 1 ) {
|
||||
rlcount = 0;
|
||||
copyloc = inputpixel; /* point to 1st guy in packet */
|
||||
matchpixel = inputpixel; /* set pointer to pix to match */
|
||||
pixcount = 2;
|
||||
inputpixel += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// assembling a packet -- look at next pixel
|
||||
|
||||
// current pixel == match pixel?
|
||||
if ( *inputpixel == *matchpixel ) {
|
||||
|
||||
// establishing a run of enough length to
|
||||
// save space by doing it
|
||||
// -- write the non-run length packet
|
||||
// -- start run-length packet
|
||||
|
||||
if ( ++rlcount == rlthresh ) {
|
||||
|
||||
// close a non-run packet
|
||||
|
||||
if ( pixcount > (rlcount+1) ) {
|
||||
// write out length and do not set run flag
|
||||
|
||||
ubyte code = (ubyte)(pixcount - 2 - rlthresh);
|
||||
cfwrite( &code, 1, 1, cfile );
|
||||
|
||||
cfwrite( copyloc, 1, (pixcount-1-rlcount), cfile );
|
||||
copyloc = inputpixel;
|
||||
pixcount = rlcount + 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
// no match -- either break a run or continue without one
|
||||
// if a run exists break it:
|
||||
// write the bytes in the string (1+1)
|
||||
// start the next string
|
||||
|
||||
if ( rlcount >= rlthresh ) {
|
||||
|
||||
ubyte code = (ubyte)(0x80 | rlcount);
|
||||
cfwrite( &code, 1, 1, cfile );
|
||||
cfwrite( copyloc, 1, 1, cfile );
|
||||
pixcount = 1;
|
||||
continue;
|
||||
} else {
|
||||
|
||||
// not a match and currently not a run
|
||||
// - save the current pixel
|
||||
// - reset the run-length flag
|
||||
rlcount = 0;
|
||||
matchpixel = inputpixel;
|
||||
}
|
||||
}
|
||||
pixcount++;
|
||||
inputpixel += 1;
|
||||
} while ( inputpixel < (in + bytecount));
|
||||
|
||||
// quit this buffer without loosing any data
|
||||
if ( --pixcount >= 1 ) {
|
||||
ubyte code = ubyte(pixcount - 1);
|
||||
|
||||
// set the run flag if this is a run
|
||||
|
||||
if ( rlcount >= rlthresh ) {
|
||||
code |= 0x80;
|
||||
pixcount = 1;
|
||||
}
|
||||
|
||||
cfwrite( &code, 1, 1, cfile );
|
||||
|
||||
// copy the data into place
|
||||
cfwrite( copyloc, 1, pixcount, cfile );
|
||||
}
|
||||
|
||||
return param_nelem;
|
||||
}
|
||||
@@ -1,266 +0,0 @@
|
||||
#define _CFILE_INTERNAL
|
||||
|
||||
#include "cfilemod.h"
|
||||
#include "cfile.h"
|
||||
#include "cmdline/cmdline.h"
|
||||
#include "osapi/osapi.h"
|
||||
#include "cfilesystem.h"
|
||||
|
||||
#ifdef SCP_UNIX
|
||||
#include <glob.h>
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include <fnmatch.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <libgen.h>
|
||||
#endif
|
||||
|
||||
namespace cfile {
|
||||
|
||||
namespace {
|
||||
|
||||
typedef struct cf_root_sort {
|
||||
SCP_string path;
|
||||
int cf_type;
|
||||
} cf_root_sort;
|
||||
|
||||
// packfile sort function
|
||||
bool cf_packfile_sort_func(const cf_root_sort& r1, const cf_root_sort& r2) {
|
||||
// if the 2 directory types are the same, do a string compare
|
||||
if (r1.cf_type == r2.cf_type) {
|
||||
return (stricmp(r1.path.c_str(), r2.path.c_str()) < 0);
|
||||
}
|
||||
|
||||
// otherwise return them in order of CF_TYPE_* precedence
|
||||
return (r1.cf_type < r2.cf_type);
|
||||
}
|
||||
|
||||
// Go through a root and look for pack files
|
||||
void build_pack_list(SCP_vector<ModRoot>& mod_roots,
|
||||
const SCP_string& search_path,
|
||||
LocationType location_type,
|
||||
bool user_location) {
|
||||
char filespec[MAX_PATH_LEN];
|
||||
|
||||
// allocate a temporary array of temporary roots so we can easily sort them
|
||||
SCP_vector<cf_root_sort> temp_roots_sort;
|
||||
|
||||
// now just setup all the root info
|
||||
for (int i = CF_TYPE_ROOT; i < CF_MAX_PATH_TYPES; i++) {
|
||||
strcpy_s(filespec, search_path.c_str());
|
||||
|
||||
if (strlen(Pathtypes[i].path)) {
|
||||
strcat_s(filespec, Pathtypes[i].path);
|
||||
|
||||
if (filespec[strlen(filespec) - 1] != DIR_SEPARATOR_CHAR)
|
||||
strcat_s(filespec, DIR_SEPARATOR_STR);
|
||||
}
|
||||
|
||||
#if defined _WIN32
|
||||
strcat_s( filespec, "*.vp" );
|
||||
|
||||
intptr_t find_handle;
|
||||
_finddata_t find;
|
||||
|
||||
find_handle = _findfirst( filespec, &find );
|
||||
|
||||
if (find_handle != -1) {
|
||||
do {
|
||||
// add the new item
|
||||
if (!(find.attrib & _A_SUBDIR)) {
|
||||
|
||||
// get a temp pointer
|
||||
rptr_sort = &temp_roots_sort[root_index++];
|
||||
|
||||
// fill in all the proper info
|
||||
strcpy_s(rptr_sort->path, root->path);
|
||||
|
||||
if(strlen(Pathtypes[i].path)) {
|
||||
|
||||
strcat_s(rptr_sort->path, Pathtypes[i].path );
|
||||
strcat_s(rptr_sort->path, DIR_SEPARATOR_STR);
|
||||
}
|
||||
|
||||
strcat_s(rptr_sort->path, find.name );
|
||||
rptr_sort->roottype = CF_ROOTTYPE_PACK;
|
||||
rptr_sort->cf_type = i;
|
||||
}
|
||||
|
||||
} while (!_findnext(find_handle, &find));
|
||||
|
||||
_findclose( find_handle );
|
||||
}
|
||||
#elif defined SCP_UNIX
|
||||
strcat_s(filespec, "*.[vV][pP]");
|
||||
glob_t globinfo;
|
||||
|
||||
memset(&globinfo, 0, sizeof(globinfo));
|
||||
|
||||
int status = glob(filespec, 0, NULL, &globinfo);
|
||||
|
||||
if (status == 0) {
|
||||
for (uint j = 0; j < globinfo.gl_pathc; j++) {
|
||||
// Determine if this is a regular file
|
||||
struct stat statbuf;
|
||||
memset(&statbuf, 0, sizeof(statbuf));
|
||||
stat(globinfo.gl_pathv[j], &statbuf);
|
||||
|
||||
if (S_ISREG(statbuf.st_mode)) {
|
||||
|
||||
cf_root_sort sort;
|
||||
|
||||
// fill in all the proper info
|
||||
sort.path = globinfo.gl_pathv[j];
|
||||
sort.cf_type = i;
|
||||
temp_roots_sort.push_back(sort);
|
||||
}
|
||||
}
|
||||
|
||||
globfree(&globinfo);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// sort the roots
|
||||
std::sort(temp_roots_sort.begin(), temp_roots_sort.end(), cf_packfile_sort_func);
|
||||
|
||||
// now insert them all into the real root list properly
|
||||
for (const auto& pack_root : temp_roots_sort) {
|
||||
ModRoot root;
|
||||
root.type = ModRootType::Package;
|
||||
root.path = pack_root.path;
|
||||
root.user_location = user_location;
|
||||
root.location_type = location_type;
|
||||
|
||||
mod_roots.push_back(root);
|
||||
}
|
||||
}
|
||||
|
||||
char normalize_directory_separator(char in) {
|
||||
if (in == '/') {
|
||||
return DIR_SEPARATOR_CHAR;
|
||||
}
|
||||
|
||||
return in;
|
||||
}
|
||||
|
||||
void
|
||||
add_mod_roots(SCP_vector<ModRoot>& mod_roots, const char* mod_cmdline, const SCP_string& rootDirectory, bool user_location) {
|
||||
if (mod_cmdline) {
|
||||
bool primary = true;
|
||||
for (const char* cur_pos = mod_cmdline; strlen(cur_pos) != 0; cur_pos += (strlen(cur_pos) + 1)) {
|
||||
SCP_stringstream ss;
|
||||
ss << rootDirectory;
|
||||
|
||||
if (rootDirectory.back() != DIR_SEPARATOR_CHAR) {
|
||||
ss << DIR_SEPARATOR_CHAR;
|
||||
}
|
||||
|
||||
ss << cur_pos << DIR_SEPARATOR_STR;
|
||||
|
||||
SCP_string rootPath = ss.str();
|
||||
|
||||
// normalize the path to the native path format
|
||||
std::transform(rootPath.begin(), rootPath.end(), rootPath.begin(), normalize_directory_separator);
|
||||
|
||||
ModRoot root;
|
||||
root.type = ModRootType::Folder;
|
||||
root.path = rootPath;
|
||||
root.user_location = user_location;
|
||||
|
||||
if (primary) {
|
||||
root.location_type = LocationType::PrimaryMod;
|
||||
} else {
|
||||
root.location_type = LocationType::SecondaryMod;
|
||||
}
|
||||
|
||||
mod_roots.push_back(root);
|
||||
|
||||
build_pack_list(mod_roots, rootPath, root.location_type, user_location);
|
||||
|
||||
primary = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SCP_vector<ModRoot> getModRootsFromModCmdline(const SCP_string& content_root, const char* mod_cmdline) {
|
||||
SCP_vector<ModRoot> mod_roots;
|
||||
|
||||
if (os_is_legacy_mode()) {
|
||||
// =========================================================================
|
||||
#ifdef WIN32
|
||||
// Nothing to do here, Windows uses the current directory as the base
|
||||
#else
|
||||
add_mod_roots(mod_roots, mod_cmdline, os_get_legacy_user_dir(), true);
|
||||
|
||||
ModRoot root;
|
||||
root.type = ModRootType::Folder;
|
||||
root.path = os_get_legacy_user_dir();
|
||||
root.user_location = true;
|
||||
root.location_type = LocationType::GameRoot;
|
||||
|
||||
// do we already have a slash? as in the case of a root directory install
|
||||
if (root.path.back() != DIR_SEPARATOR_CHAR) {
|
||||
root.path += DIR_SEPARATOR_STR; // put trailing backslash on for easier path construction
|
||||
}
|
||||
|
||||
mod_roots.push_back(root);
|
||||
|
||||
// Next, check any VP files under the current directory.
|
||||
build_pack_list(mod_roots, root.path, root.location_type, root.user_location);
|
||||
#endif
|
||||
// =========================================================================
|
||||
} else if (!Cmdline_portable_mode) {
|
||||
// =========================================================================
|
||||
// now look for mods under the users HOME directory to use before system ones
|
||||
add_mod_roots(mod_roots, mod_cmdline, os_get_config_path(), true);
|
||||
// =========================================================================
|
||||
|
||||
// =========================================================================
|
||||
// set users HOME directory as default for loading and saving files
|
||||
ModRoot root;
|
||||
root.type = ModRootType::Folder;
|
||||
root.path = os_get_config_path();
|
||||
root.user_location = true;
|
||||
root.location_type = LocationType::GameRoot;
|
||||
|
||||
// do we already have a slash? as in the case of a root directory install
|
||||
if (root.path.back() != DIR_SEPARATOR_CHAR) {
|
||||
root.path += DIR_SEPARATOR_STR; // put trailing backslash on for easier path construction
|
||||
}
|
||||
|
||||
mod_roots.push_back(root);
|
||||
|
||||
// Next, check any VP files under the current directory.
|
||||
build_pack_list(mod_roots, root.path, root.location_type, root.user_location);
|
||||
// =========================================================================
|
||||
}
|
||||
|
||||
add_mod_roots(mod_roots, mod_cmdline, content_root, false);
|
||||
|
||||
ModRoot root;
|
||||
root.type = ModRootType::Folder;
|
||||
root.path = content_root;
|
||||
root.user_location = false;
|
||||
root.location_type = LocationType::GameRoot;
|
||||
|
||||
// do we already have a slash? as in the case of a root directory install
|
||||
if (root.path.back() != DIR_SEPARATOR_CHAR) {
|
||||
root.path += DIR_SEPARATOR_STR; // put trailing backslash on for easier path construction
|
||||
}
|
||||
|
||||
mod_roots.push_back(root);
|
||||
|
||||
//======================================================
|
||||
// Next, check any VP files under the current directory.
|
||||
build_pack_list(mod_roots, root.path, root.location_type, root.user_location);
|
||||
|
||||
return mod_roots;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "globalincs/pstypes.h"
|
||||
#include "cfile/cfile.h"
|
||||
|
||||
namespace cfile {
|
||||
|
||||
SCP_vector<ModRoot> getModRootsFromModCmdline(const SCP_string& content_root, const char* mod_cmdline);
|
||||
|
||||
}
|
||||
+506
-405
File diff suppressed because it is too large.
Load diff
@@ -15,7 +15,7 @@
|
||||
#include "cfile/cfile.h"
|
||||
|
||||
// Builds a list of all the files
|
||||
void cf_build_secondary_filelist(const SCP_vector<cfile::ModRoot>& modRoots);
|
||||
void cf_build_secondary_filelist( const char *cdrom_path );
|
||||
void cf_free_secondary_filelist();
|
||||
|
||||
// Internal stuff
|
||||
@@ -29,8 +29,6 @@ typedef struct cf_pathtype {
|
||||
// During cfile_init, verify that Pathtypes[n].index == n for each item
|
||||
extern cf_pathtype Pathtypes[CF_MAX_PATH_TYPES];
|
||||
|
||||
bool cf_check_location_flags(uint32_t check_flags, uint32_t desired_flags);
|
||||
|
||||
// Returns the default storage path for files given a
|
||||
// particular pathtype. In other words, the path to
|
||||
// the unpacked, non-cd'd, stored on hard drive path.
|
||||
@@ -41,9 +39,7 @@ bool cf_check_location_flags(uint32_t check_flags, uint32_t desired_flags);
|
||||
// filename - optional, if set, tacks the filename onto end of path.
|
||||
// Output: path - Fully qualified pathname.
|
||||
//Returns 0 if result would be too long (invalid result)
|
||||
int cf_create_default_path_string(char* path, uint path_max, int pathtype, const char* filename = nullptr,
|
||||
bool localize = false, uint32_t location_flags = CF_LOCATION_ALL);
|
||||
int cf_create_default_path_string(SCP_string& path, int pathtype, const char* filename = nullptr, bool localize = false,
|
||||
uint32_t location_flags = CF_LOCATION_ALL);
|
||||
int cf_create_default_path_string( char *path, uint path_max, int pathtype, const char *filename=NULL, bool localize = false);
|
||||
int cf_create_default_path_string( SCP_string &path, int pathtype, const char *filename=NULL, bool localize = false );
|
||||
|
||||
#endif //_CFILESYSTEM_H
|
||||
+258
-439
File diff suppressed because it is too large.
Load diff
+27
-20
@@ -12,7 +12,6 @@
|
||||
#ifndef FS_CMDLINE_HEADER_FILE
|
||||
#define FS_CMDLINE_HEADER_FILE
|
||||
|
||||
#include "globalincs/pstypes.h"
|
||||
|
||||
int parse_cmdline(int argc, char *argv[]);
|
||||
|
||||
@@ -25,11 +24,11 @@ int parse_cmdline(int argc, char *argv[]);
|
||||
|
||||
|
||||
// RETAIL OPTIONS ----------------------------------------------
|
||||
extern SCP_string Cmdline_connect_addr;
|
||||
extern SCP_string Cmdline_game_name;
|
||||
extern SCP_string Cmdline_game_password;
|
||||
extern SCP_string Cmdline_rank_above;
|
||||
extern SCP_string Cmdline_rank_below;
|
||||
extern char *Cmdline_connect_addr;
|
||||
extern char *Cmdline_game_name;
|
||||
extern char *Cmdline_game_password;
|
||||
extern char *Cmdline_rank_above;
|
||||
extern char *Cmdline_rank_below;
|
||||
extern int Cmdline_cd_check;
|
||||
extern int Cmdline_client_dodamage;
|
||||
extern int Cmdline_closed_game;
|
||||
@@ -47,8 +46,8 @@ extern int Cmdline_timeout;
|
||||
extern int Cmdline_use_last_pilot;
|
||||
extern int Cmdline_window;
|
||||
extern int Cmdline_fullscreen_window;
|
||||
extern SCP_string Cmdline_res;
|
||||
extern SCP_string Cmdline_center_res;
|
||||
extern char *Cmdline_res;
|
||||
extern char *Cmdline_center_res;
|
||||
|
||||
|
||||
// FSO OPTIONS -------------------------------------------------
|
||||
@@ -56,25 +55,35 @@ extern SCP_string Cmdline_center_res;
|
||||
// Graphics related
|
||||
extern double specular_exponent_value;
|
||||
extern float Cmdline_clip_dist;
|
||||
extern float Cmdline_fov;
|
||||
extern float Cmdline_ogl_spec;
|
||||
extern float static_light_factor;
|
||||
extern float static_point_factor;
|
||||
extern float static_tube_factor;
|
||||
extern int Cmdline_ambient_factor;
|
||||
extern int Cmdline_env;
|
||||
extern int Cmdline_missile_lighting;
|
||||
extern int Cmdline_glow;
|
||||
extern int Cmdline_nomotiondebris;
|
||||
extern int Cmdline_noscalevid; // disables fit-to-window for movies - taylor
|
||||
extern int Cmdline_spec;
|
||||
extern int Cmdline_normal;
|
||||
extern int Cmdline_height;
|
||||
extern int Cmdline_enable_3d_shockwave;
|
||||
extern int Cmdline_softparticles;
|
||||
extern int Cmdline_postprocess;
|
||||
extern int Cmdline_bloom_intensity;
|
||||
extern bool Cmdline_fxaa;
|
||||
extern int Cmdline_fxaa_preset;
|
||||
extern bool Cmdline_fb_explosions;
|
||||
extern bool Cmdline_fb_thrusters;
|
||||
extern bool Cmdline_no_batching;
|
||||
extern int Cmdline_shadow_quality;
|
||||
extern int Cmdline_no_deferred_lighting;
|
||||
extern int Cmdline_no_emissive;
|
||||
extern int Cmdline_aniso_level;
|
||||
|
||||
// Game Speed related
|
||||
extern int Cmdline_cache_bitmaps;
|
||||
extern int Cmdline_NoFPSCap;
|
||||
extern int Cmdline_no_vsync;
|
||||
|
||||
@@ -94,21 +103,18 @@ extern int Cmdline_autopilot_interruptable;
|
||||
extern int Cmdline_stretch_menu;
|
||||
|
||||
// Audio related
|
||||
extern int Cmdline_query_speech;
|
||||
extern int Cmdline_voice_recognition;
|
||||
extern int Cmdline_no_enhanced_sound;
|
||||
|
||||
namespace cfile {
|
||||
struct ModRoot;
|
||||
} // namespace cfile
|
||||
|
||||
// MOD related
|
||||
extern SCP_vector<cfile::ModRoot> Cmdline_mod; // DTP for mod support
|
||||
extern char *Cmdline_mod; // DTP for mod support
|
||||
// Multiplayer/Network related
|
||||
extern SCP_string Cmdline_almission; // DTP for autoload mission (for multi only)
|
||||
extern char *Cmdline_almission; // DTP for autoload mission (for multi only)
|
||||
extern int Cmdline_ingamejoin;
|
||||
extern int Cmdline_mpnoreturn;
|
||||
extern SCP_string Cmdline_spew_mission_crcs;
|
||||
extern SCP_string Cmdline_spew_table_crcs;
|
||||
extern char *Cmdline_spew_mission_crcs;
|
||||
extern char *Cmdline_spew_table_crcs;
|
||||
extern int Cmdline_objupd;
|
||||
|
||||
// Launcher related options
|
||||
@@ -124,7 +130,7 @@ extern int Cmdline_mipmap;
|
||||
extern int Cmdline_ati_color_swap;
|
||||
extern int Cmdline_no_3d_sound;
|
||||
extern int Cmdline_drawelements;
|
||||
extern SCP_string Cmdline_keyboard_layout;
|
||||
extern char* Cmdline_keyboard_layout;
|
||||
extern bool Cmdline_gl_finish;
|
||||
extern bool Cmdline_no_geo_sdr_effects;
|
||||
extern bool Cmdline_set_cpu_affinity;
|
||||
@@ -135,10 +141,10 @@ extern bool Cmdline_alternate_registry_path;
|
||||
#endif
|
||||
|
||||
// Developer/Testing related
|
||||
extern SCP_string Cmdline_start_mission;
|
||||
extern char *Cmdline_start_mission;
|
||||
extern int Cmdline_old_collision_sys;
|
||||
extern int Cmdline_dis_collisions;
|
||||
extern int Cmdline_dis_weapons;
|
||||
extern bool Cmdline_output_sexp_info;
|
||||
extern int Cmdline_noparseerrors;
|
||||
extern int Cmdline_extra_warn;
|
||||
extern int Cmdline_bmpman_usage;
|
||||
@@ -151,6 +157,7 @@ extern bool Cmdline_profile_write_file;
|
||||
extern bool Cmdline_no_unfocus_pause;
|
||||
extern bool Cmdline_benchmark_mode;
|
||||
extern bool Cmdline_noninteractive;
|
||||
extern bool Cmdline_json_pilot;
|
||||
extern bool Cmdline_json_profiling;
|
||||
extern bool Cmdline_frame_profile;
|
||||
extern bool Cmdline_show_video_info;
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
{
|
||||
"version": 1,
|
||||
"flags": {
|
||||
"-bool_option": false,
|
||||
"-number_option": 5.8,
|
||||
"-string_option": "asdf",
|
||||
"-mod": [
|
||||
{
|
||||
"type": "folder",
|
||||
"path": "/home/fso/mediavps",
|
||||
"user": true,
|
||||
"location_type": "primary_mod"
|
||||
},
|
||||
{
|
||||
"type": "folder",
|
||||
"path": "/home/fso",
|
||||
"user": true,
|
||||
"location_type": "game_root"
|
||||
},
|
||||
{
|
||||
"type": "folder",
|
||||
"path": "/path/to/fso/mediavps",
|
||||
"user": false,
|
||||
"location_type": "primary_mod"
|
||||
},
|
||||
{
|
||||
"type": "package",
|
||||
"path": "/path/to/fso/mediavps/MVPS-Z.vp",
|
||||
"location_type": "primary_mod"
|
||||
},
|
||||
{
|
||||
"type": "package",
|
||||
"path": "/path/to/fso/mediavps/MVPS-X.vp",
|
||||
"location_type": "primary_mod"
|
||||
},
|
||||
{
|
||||
"type": "folder",
|
||||
"path": "/path/to/fso",
|
||||
"location_type": "game_root"
|
||||
},
|
||||
{
|
||||
"type": "package",
|
||||
"path": "/path/to/fso/retail.vp",
|
||||
"location_type": "game_root"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -53,6 +53,26 @@ void cmeasure_set_ship_launch_vel(object *objp, object *parent_objp, int arand)
|
||||
vm_vec_copy_scale(&objp->phys_info.desired_vel, &objp->orient.vec.fvec, objp->phys_info.max_vel.xyz.z );
|
||||
}
|
||||
|
||||
void cmeasure_select_next(ship *shipp)
|
||||
{
|
||||
Assert(shipp != NULL);
|
||||
int i, new_index;
|
||||
|
||||
for (i = 1; i < Num_weapon_types; i++)
|
||||
{
|
||||
new_index = (shipp->current_cmeasure + i) % Num_weapon_types;
|
||||
|
||||
if(Weapon_info[new_index].wi_flags[Weapon::Info_Flags::Cmeasure])
|
||||
{
|
||||
shipp->current_cmeasure = new_index;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
mprintf(("Countermeasure type set to %i in frame %i\n", shipp->current_cmeasure, Framecount));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief If this is a player countermeasure, let the player know they evaded a missile.
|
||||
* @param objp [description]
|
||||
@@ -72,7 +92,7 @@ void cmeasure_maybe_alert_success(object *objp)
|
||||
|
||||
if ( objp->parent == OBJ_INDEX(Player_obj) ) {
|
||||
hud_start_text_flash(XSTR("Evaded", 1430), 800);
|
||||
snd_play(gamesnd_get_game_sound(ship_get_sound(Player_obj, GameSounds::MISSILE_EVADED_POPUP)));
|
||||
snd_play(gamesnd_get_game_sound(ship_get_sound(Player_obj, SND_MISSILE_EVADED_POPUP)));
|
||||
} else if ( Objects[objp->parent].flags[Object::Object_Flags::Player_ship] ) {
|
||||
send_countermeasure_success_packet( objp->parent );
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ extern int Cmeasures_homing_check;
|
||||
extern int Countermeasures_enabled;
|
||||
|
||||
extern void cmeasure_set_ship_launch_vel(object *objp, object *parent_objp, int arand);
|
||||
extern void cmeasure_select_next(object *objp);
|
||||
extern void cmeasure_maybe_alert_success(object *objp);
|
||||
|
||||
#endif // _CMEASURE_H
|
||||
@@ -38,6 +38,7 @@
|
||||
|
||||
|
||||
|
||||
#define NUM_SYSTEM_KEYS 14
|
||||
#define NUM_BUTTONS 19
|
||||
#define NUM_TABS 4
|
||||
|
||||
@@ -156,6 +157,11 @@ char *Mouse_button_text[NUM_MOUSE_TEXT];
|
||||
char *Mouse_axis_text[NUM_MOUSE_AXIS_TEXT];
|
||||
char *Invert_text[NUM_INVERT_TEXT];
|
||||
|
||||
ubyte System_keys[NUM_SYSTEM_KEYS] = {
|
||||
KEY_ESC, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10,
|
||||
KEY_F11, KEY_F12, KEY_PRINT_SCRN
|
||||
};
|
||||
|
||||
int Control_check_count = 0;
|
||||
|
||||
static int Tab; // which tab we are currently in
|
||||
@@ -350,7 +356,7 @@ DCF_BOOL(show_controls_info, Show_controls_info);
|
||||
|
||||
static int Axes_origin[JOY_NUM_AXES];
|
||||
|
||||
static int joy_get_unscaled_reading(int raw)
|
||||
static int joy_get_unscaled_reading(int raw, int axn)
|
||||
{
|
||||
int rng;
|
||||
|
||||
@@ -609,7 +615,7 @@ int control_config_undo_last()
|
||||
int i, z, tab;
|
||||
|
||||
if (!Config_item_undo) {
|
||||
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
|
||||
gamesnd_play_iface(SND_GENERAL_FAIL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -658,7 +664,7 @@ int control_config_undo_last()
|
||||
free_undo_block();
|
||||
control_config_conflict_check();
|
||||
control_config_list_prepare();
|
||||
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
|
||||
gamesnd_play_iface(SND_USER_SELECT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -709,7 +715,7 @@ int control_config_remove_binding()
|
||||
config_item_undo *ptr;
|
||||
|
||||
if (Selected_line < 0) {
|
||||
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
|
||||
gamesnd_play_iface(SND_GENERAL_FAIL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -717,7 +723,7 @@ int control_config_remove_binding()
|
||||
if (z & JOY_AXIS) {
|
||||
z &= ~JOY_AXIS;
|
||||
if (Axis_map_to[z] < 0) {
|
||||
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
|
||||
gamesnd_play_iface(SND_GENERAL_FAIL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -725,13 +731,13 @@ int control_config_remove_binding()
|
||||
Axis_map_to[z] = -1;
|
||||
control_config_conflict_check();
|
||||
control_config_list_prepare();
|
||||
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
|
||||
gamesnd_play_iface(SND_USER_SELECT);
|
||||
Selected_item = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((Control_config[z].joy_id < 0) && (Control_config[z].key_id < 0)) {
|
||||
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
|
||||
gamesnd_play_iface(SND_GENERAL_FAIL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -749,7 +755,7 @@ int control_config_remove_binding()
|
||||
|
||||
control_config_conflict_check();
|
||||
control_config_list_prepare();
|
||||
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
|
||||
gamesnd_play_iface(SND_USER_SELECT);
|
||||
Selected_item = -1;
|
||||
return 0;
|
||||
}
|
||||
@@ -760,7 +766,7 @@ int control_config_clear_other()
|
||||
config_item_undo *ptr;
|
||||
|
||||
if (Selected_line < 0) {
|
||||
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
|
||||
gamesnd_play_iface(SND_GENERAL_FAIL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -770,7 +776,7 @@ int control_config_clear_other()
|
||||
|
||||
z &= ~JOY_AXIS;
|
||||
if (Axis_map_to[z] < 0) {
|
||||
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
|
||||
gamesnd_play_iface(SND_GENERAL_FAIL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -781,7 +787,7 @@ int control_config_clear_other()
|
||||
}
|
||||
|
||||
if (!total) {
|
||||
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
|
||||
gamesnd_play_iface(SND_GENERAL_FAIL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -802,7 +808,7 @@ int control_config_clear_other()
|
||||
}
|
||||
control_config_conflict_check();
|
||||
control_config_list_prepare();
|
||||
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
|
||||
gamesnd_play_iface(SND_USER_SELECT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -814,12 +820,12 @@ int control_config_clear_other()
|
||||
}
|
||||
}
|
||||
if (!total) {
|
||||
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
|
||||
gamesnd_play_iface(SND_GENERAL_FAIL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((Control_config[z].joy_id < 0) && (Control_config[z].key_id < 0)) {
|
||||
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
|
||||
gamesnd_play_iface(SND_GENERAL_FAIL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -844,7 +850,7 @@ int control_config_clear_other()
|
||||
}
|
||||
control_config_conflict_check();
|
||||
control_config_list_prepare();
|
||||
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
|
||||
gamesnd_play_iface(SND_USER_SELECT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -861,7 +867,7 @@ int control_config_clear_all()
|
||||
}
|
||||
|
||||
if (!total) {
|
||||
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
|
||||
gamesnd_play_iface(SND_GENERAL_FAIL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -882,7 +888,7 @@ int control_config_clear_all()
|
||||
|
||||
control_config_conflict_check();
|
||||
control_config_list_prepare();
|
||||
gamesnd_play_iface(InterfaceSounds::RESET_PRESSED);
|
||||
gamesnd_play_iface(SND_RESET_PRESSED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -939,7 +945,7 @@ int control_config_do_reset()
|
||||
}
|
||||
|
||||
if (!total && !cycling_presets) {
|
||||
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
|
||||
gamesnd_play_iface(SND_GENERAL_FAIL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -975,7 +981,7 @@ int control_config_do_reset()
|
||||
|
||||
control_config_conflict_check();
|
||||
control_config_list_prepare();
|
||||
gamesnd_play_iface(InterfaceSounds::RESET_PRESSED);
|
||||
gamesnd_play_iface(SND_RESET_PRESSED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1020,10 +1026,10 @@ void control_config_scroll_screen_up()
|
||||
}
|
||||
|
||||
Selected_item = -1;
|
||||
gamesnd_play_iface(InterfaceSounds::SCROLL);
|
||||
gamesnd_play_iface(SND_SCROLL);
|
||||
|
||||
} else {
|
||||
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
|
||||
gamesnd_play_iface(SND_GENERAL_FAIL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1036,10 +1042,10 @@ void control_config_scroll_line_up()
|
||||
}
|
||||
|
||||
Selected_item = -1;
|
||||
gamesnd_play_iface(InterfaceSounds::SCROLL);
|
||||
gamesnd_play_iface(SND_SCROLL);
|
||||
|
||||
} else {
|
||||
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
|
||||
gamesnd_play_iface(SND_GENERAL_FAIL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1053,10 +1059,10 @@ void control_config_scroll_screen_down()
|
||||
}
|
||||
|
||||
Selected_item = -1;
|
||||
gamesnd_play_iface(InterfaceSounds::SCROLL);
|
||||
gamesnd_play_iface(SND_SCROLL);
|
||||
|
||||
} else {
|
||||
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
|
||||
gamesnd_play_iface(SND_GENERAL_FAIL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1070,10 +1076,10 @@ void control_config_scroll_line_down()
|
||||
}
|
||||
|
||||
Selected_item = -1;
|
||||
gamesnd_play_iface(InterfaceSounds::SCROLL);
|
||||
gamesnd_play_iface(SND_SCROLL);
|
||||
|
||||
} else {
|
||||
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
|
||||
gamesnd_play_iface(SND_GENERAL_FAIL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1085,13 +1091,13 @@ void control_config_toggle_modifier(int bit)
|
||||
Assert(!(z & JOY_AXIS));
|
||||
k = Control_config[z].key_id;
|
||||
if (k < 0) {
|
||||
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
|
||||
gamesnd_play_iface(SND_GENERAL_FAIL);
|
||||
return;
|
||||
}
|
||||
|
||||
control_config_bind_key(z, k ^ bit);
|
||||
control_config_conflict_check();
|
||||
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
|
||||
gamesnd_play_iface(SND_USER_SELECT);
|
||||
}
|
||||
|
||||
void control_config_toggle_invert()
|
||||
@@ -1112,7 +1118,7 @@ void control_config_do_bind()
|
||||
game_flush();
|
||||
// if ((Selected_line < 0) || (Cc_lines[Selected_line].cc_index & JOY_AXIS)) {
|
||||
if (Selected_line < 0) {
|
||||
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
|
||||
gamesnd_play_iface(SND_GENERAL_FAIL);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1136,7 +1142,7 @@ void control_config_do_bind()
|
||||
Search_mode = 0;
|
||||
Last_key = -1;
|
||||
Axis_override = -1;
|
||||
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
|
||||
gamesnd_play_iface(SND_USER_SELECT);
|
||||
}
|
||||
|
||||
void control_config_do_search()
|
||||
@@ -1160,7 +1166,7 @@ void control_config_do_search()
|
||||
Binding_mode = 0;
|
||||
Search_mode = 1;
|
||||
Last_key = -1;
|
||||
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
|
||||
gamesnd_play_iface(SND_USER_SELECT);
|
||||
}
|
||||
|
||||
void control_config_do_cancel(int fail = 0)
|
||||
@@ -1183,9 +1189,9 @@ void control_config_do_cancel(int fail = 0)
|
||||
|
||||
Binding_mode = Search_mode = 0;
|
||||
if (fail){
|
||||
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
|
||||
gamesnd_play_iface(SND_GENERAL_FAIL);
|
||||
} else {
|
||||
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
|
||||
gamesnd_play_iface(SND_USER_SELECT);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1200,13 +1206,13 @@ int control_config_accept()
|
||||
}
|
||||
|
||||
if (i < NUM_TABS) {
|
||||
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
|
||||
gamesnd_play_iface(SND_GENERAL_FAIL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
hud_squadmsg_save_keys(); // rebuild map for saving/restoring keys in squadmsg mode
|
||||
gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
|
||||
gamesnd_play_iface(InterfaceSounds::COMMIT_PRESSED);
|
||||
gamesnd_play_iface(SND_COMMIT_PRESSED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1231,7 +1237,7 @@ void control_config_button_pressed(int n)
|
||||
Tab = n;
|
||||
Scroll_offset = Selected_line = 0;
|
||||
control_config_list_prepare();
|
||||
gamesnd_play_iface(InterfaceSounds::SCREEN_MODE_PRESSED);
|
||||
gamesnd_play_iface(SND_SCREEN_MODE_PRESSED);
|
||||
break;
|
||||
|
||||
case BIND_BUTTON:
|
||||
@@ -1244,17 +1250,17 @@ void control_config_button_pressed(int n)
|
||||
|
||||
case SHIFT_TOGGLE:
|
||||
control_config_toggle_modifier(KEY_SHIFTED);
|
||||
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
|
||||
gamesnd_play_iface(SND_USER_SELECT);
|
||||
break;
|
||||
|
||||
case ALT_TOGGLE:
|
||||
control_config_toggle_modifier(KEY_ALTED);
|
||||
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
|
||||
gamesnd_play_iface(SND_USER_SELECT);
|
||||
break;
|
||||
|
||||
case INVERT_AXIS:
|
||||
control_config_toggle_invert();
|
||||
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
|
||||
gamesnd_play_iface(SND_USER_SELECT);
|
||||
break;
|
||||
|
||||
case SCROLL_UP_BUTTON:
|
||||
@@ -1275,7 +1281,7 @@ void control_config_button_pressed(int n)
|
||||
|
||||
case HELP_BUTTON:
|
||||
launch_context_help();
|
||||
gamesnd_play_iface(InterfaceSounds::HELP_PRESSED);
|
||||
gamesnd_play_iface(SND_HELP_PRESSED);
|
||||
break;
|
||||
|
||||
case RESET_BUTTON:
|
||||
@@ -1793,7 +1799,7 @@ void control_config_do_frame(float frametime)
|
||||
|
||||
Scroll_offset = Selected_line = 0;
|
||||
control_config_list_prepare();
|
||||
gamesnd_play_iface(InterfaceSounds::SCREEN_MODE_PRESSED);
|
||||
gamesnd_play_iface(SND_SCREEN_MODE_PRESSED);
|
||||
break;
|
||||
|
||||
case KEY_TAB: // activate next tab
|
||||
@@ -1804,7 +1810,7 @@ void control_config_do_frame(float frametime)
|
||||
|
||||
Scroll_offset = Selected_line = 0;
|
||||
control_config_list_prepare();
|
||||
gamesnd_play_iface(InterfaceSounds::SCREEN_MODE_PRESSED);
|
||||
gamesnd_play_iface(SND_SCREEN_MODE_PRESSED);
|
||||
break;
|
||||
|
||||
case KEY_LEFT:
|
||||
@@ -1819,7 +1825,7 @@ void control_config_do_frame(float frametime)
|
||||
}
|
||||
}
|
||||
|
||||
gamesnd_play_iface(InterfaceSounds::SCROLL);
|
||||
gamesnd_play_iface(SND_SCROLL);
|
||||
break;
|
||||
|
||||
case KEY_RIGHT:
|
||||
@@ -1831,7 +1837,7 @@ void control_config_do_frame(float frametime)
|
||||
} else if (Selected_item > 1) {
|
||||
Selected_item = -1;
|
||||
}
|
||||
gamesnd_play_iface(InterfaceSounds::SCROLL);
|
||||
gamesnd_play_iface(SND_SCROLL);
|
||||
break;
|
||||
|
||||
case KEY_BACKSP: // undo
|
||||
@@ -1867,7 +1873,7 @@ void control_config_do_frame(float frametime)
|
||||
Selected_item = 1;
|
||||
}
|
||||
|
||||
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
|
||||
gamesnd_play_iface(SND_USER_SELECT);
|
||||
}
|
||||
|
||||
if (List_buttons[i].double_clicked()) {
|
||||
@@ -2187,6 +2193,17 @@ void control_config_do_frame(float frametime)
|
||||
gr_flip();
|
||||
}
|
||||
|
||||
void clear_key_binding(short key)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i<CCFG_MAX; i++) {
|
||||
if (Control_config[i].key_id == key) {
|
||||
Control_config[i].key_id = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float check_control_timef(int id)
|
||||
{
|
||||
float t1, t2;
|
||||
@@ -2328,7 +2345,7 @@ int check_control(int id, int key)
|
||||
// which has just been released
|
||||
|
||||
Script_system.SetHookVar("Action", 's', Control_config[id].text);
|
||||
Script_system.RunCondition(CHA_ONACTIONSTOPPED, nullptr, id);
|
||||
Script_system.RunCondition(CHA_ONACTIONSTOPPED, '\0', NULL, NULL, id);
|
||||
Script_system.RemHookVar("Action");
|
||||
|
||||
Control_config[id].continuous_ongoing = false;
|
||||
@@ -2362,7 +2379,7 @@ void control_get_axes_readings(int *h, int *p, int *b, int *ta, int *tr)
|
||||
|
||||
*ta = 0;
|
||||
if (Axis_map_to[3] >= 0) {
|
||||
*ta = joy_get_unscaled_reading(axes_values[Axis_map_to[3]]);
|
||||
*ta = joy_get_unscaled_reading(axes_values[Axis_map_to[3]], Axis_map_to[3]);
|
||||
}
|
||||
|
||||
*tr = 0;
|
||||
@@ -2402,7 +2419,7 @@ void control_used(int id)
|
||||
if (Control_config[id].used < Last_frame_timestamp) {
|
||||
if (!Control_config[id].continuous_ongoing) {
|
||||
Script_system.SetHookVar("Action", 's', Control_config[id].text);
|
||||
Script_system.RunCondition(CHA_ONACTION, nullptr, id);
|
||||
Script_system.RunCondition(CHA_ONACTION, '\0', NULL, NULL, id);
|
||||
Script_system.RemHookVar("Action");
|
||||
|
||||
if (Control_config[id].type == CC_TYPE_CONTINUOUS)
|
||||
@@ -2430,4 +2447,9 @@ void control_config_clear()
|
||||
for (i=0; i<CCFG_MAX; i++) {
|
||||
Control_config[i].key_id = Control_config[i].joy_id = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int control_config_handle_conflict()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -277,6 +277,12 @@ enum IoActionId {
|
||||
};
|
||||
|
||||
extern int Failed_key_index;
|
||||
extern int Invert_heading;
|
||||
extern int Invert_pitch;
|
||||
extern int Invert_roll;
|
||||
extern int Invert_thrust;
|
||||
extern int Disable_axis2;
|
||||
extern int Disable_axis3;
|
||||
|
||||
extern int Axis_map_to[];
|
||||
extern int Invert_axis[];
|
||||
@@ -330,6 +336,7 @@ int check_control(int id, int key = -1);
|
||||
void control_get_axes_readings(int *h, int *p, int *b, int *ta, int *tr);
|
||||
void control_used(int id);
|
||||
void control_config_clear();
|
||||
void clear_key_binding(short key);
|
||||
void control_check_indicate();
|
||||
void control_config_clear_used_status();
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdarg>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "cfile/cfile.h"
|
||||
#include "controlconfig/controlsconfig.h"
|
||||
@@ -34,6 +34,13 @@ int Failed_key_index;
|
||||
int Joy_dead_zone_size = 10;
|
||||
int Joy_sensitivity = 9;
|
||||
|
||||
// assume control keys are used as modifiers until we find out
|
||||
int Shift_is_modifier;
|
||||
int Ctrl_is_modifier;
|
||||
int Alt_is_modifier;
|
||||
|
||||
int Axis_enabled[JOY_NUM_AXES] = { 1, 1, 1, 0, 0, 0 };
|
||||
int Axis_enabled_defaults[JOY_NUM_AXES] = { 1, 1, 1, 0, 0, 0 };
|
||||
int Invert_axis[JOY_NUM_AXES] = { 0, 0, 0, 0, 0, 0 };
|
||||
int Invert_axis_defaults[JOY_NUM_AXES] = { 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
@@ -194,7 +201,7 @@ config_item Control_config[CCFG_MAX + 1] = {
|
||||
|
||||
const char *Scan_code_text_german[] = {
|
||||
"", "Esc", "1", "2", "3", "4", "5", "6",
|
||||
"7", "8", "9", "0", "Akzent '", "Eszett", "R\x81""cktaste", "Tab", // NOLINT
|
||||
"7", "8", "9", "0", "Akzent '", "Eszett", "R\x81""cktaste", "Tab",
|
||||
"Q", "W", "E", "R", "T", "Z", "U", "I",
|
||||
"O", "P", "\x9A", "+", "Eingabe", "Strg Links", "A", "S",
|
||||
|
||||
@@ -244,8 +251,8 @@ const char *Joy_button_text_german[] = {
|
||||
};
|
||||
|
||||
const char *Scan_code_text_french[] = {
|
||||
"", "\x90""chap", "1", "2", "3", "4", "5", "6", // NOLINT
|
||||
"7", "8", "9", "0", "-", "=", "Fl\x82""che Ret.", "Tab", // NOLINT
|
||||
"", "\x90""chap", "1", "2", "3", "4", "5", "6",
|
||||
"7", "8", "9", "0", "-", "=", "Fl\x82""che Ret.", "Tab",
|
||||
"Q", "W", "E", "R", "T", "Y", "U", "I",
|
||||
"O", "P", "[", "]", "Entr\x82""e", "Ctrl Gauche", "A", "S",
|
||||
|
||||
@@ -403,6 +410,31 @@ const char **Joy_button_text = Joy_button_text_english;
|
||||
SCP_vector<config_item*> Control_config_presets;
|
||||
SCP_vector<SCP_string> Control_config_preset_names;
|
||||
|
||||
void set_modifier_status()
|
||||
{
|
||||
int i;
|
||||
|
||||
Alt_is_modifier = 0;
|
||||
Shift_is_modifier = 0;
|
||||
Ctrl_is_modifier = 0;
|
||||
|
||||
for (i=0; i<CCFG_MAX; i++) {
|
||||
if (Control_config[i].key_id < 0)
|
||||
continue;
|
||||
|
||||
if (Control_config[i].key_id & KEY_ALTED)
|
||||
Alt_is_modifier = 1;
|
||||
|
||||
if (Control_config[i].key_id & KEY_SHIFTED)
|
||||
Shift_is_modifier = 1;
|
||||
|
||||
if (Control_config[i].key_id & KEY_CTRLED) {
|
||||
Assert(0); // get Alan
|
||||
Ctrl_is_modifier = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If find_override is set to true, then this returns the index of the action
|
||||
// which has been bound to the given key. Otherwise, the index of the action
|
||||
// which has the given key as its default key will be returned.
|
||||
@@ -504,9 +536,7 @@ char *translate_key(char *key)
|
||||
// both key and joystick button are mapped to this control
|
||||
if ((key_code >= 0 ) && (joy_code >= 0) ) {
|
||||
strcpy_s(text, key_text);
|
||||
strcat_s(text, " ");
|
||||
strcat_s(text, XSTR("or", 1638));
|
||||
strcat_s(text, " ");
|
||||
strcat_s(text, " or ");
|
||||
strcat_s(text, joy_text);
|
||||
}
|
||||
// if we only have one
|
||||
|
||||
@@ -3,12 +3,6 @@
|
||||
#include <memory>
|
||||
|
||||
namespace cutscene {
|
||||
FrameSize::FrameSize(size_t in_width, size_t in_height, size_t in_stride)
|
||||
: width(in_width), height(in_height), stride(in_stride)
|
||||
{
|
||||
}
|
||||
FrameSize::FrameSize() = default;
|
||||
|
||||
Decoder::Decoder() : m_decoding(true) {
|
||||
}
|
||||
|
||||
@@ -46,6 +40,10 @@ void Decoder::stopDecoder() {
|
||||
m_subtitleQueue->close();
|
||||
}
|
||||
|
||||
bool Decoder::canPushAudioData() {
|
||||
return !isAudioQueueFull();
|
||||
}
|
||||
|
||||
void Decoder::pushAudioData(AudioFramePtr&& data) {
|
||||
Assertion(data, "Invalid audio data passed!");
|
||||
|
||||
@@ -57,6 +55,9 @@ void Decoder::pushAudioData(AudioFramePtr&& data) {
|
||||
}
|
||||
}
|
||||
|
||||
bool Decoder::canPushSubtitleData() {
|
||||
return !isSubtitleQueueFull();
|
||||
}
|
||||
void Decoder::pushSubtitleData(SubtitleFramePtr&& data) {
|
||||
Assertion(data, "Invalid audio data passed!");
|
||||
|
||||
@@ -68,6 +69,10 @@ void Decoder::pushSubtitleData(SubtitleFramePtr&& data) {
|
||||
}
|
||||
}
|
||||
|
||||
bool Decoder::canPushVideoData() {
|
||||
return !isVideoQueueFull();
|
||||
}
|
||||
|
||||
void Decoder::pushFrameData(VideoFramePtr&& frame) {
|
||||
Assertion(frame, "Invalid video data passed!");
|
||||
|
||||
|
||||
+25
-27
@@ -10,26 +10,28 @@ struct FrameSize {
|
||||
size_t width = 0;
|
||||
size_t height = 0;
|
||||
size_t stride = 0;
|
||||
|
||||
FrameSize();
|
||||
FrameSize(size_t width, size_t in_height, size_t in_stride);
|
||||
};
|
||||
|
||||
class VideoFrame {
|
||||
protected:
|
||||
VideoFrame() = default;
|
||||
VideoFrame() {}
|
||||
|
||||
public:
|
||||
virtual ~VideoFrame() = default;
|
||||
public:
|
||||
virtual ~VideoFrame() {}
|
||||
|
||||
double frameTime = -1.0;
|
||||
int id = -1;
|
||||
|
||||
virtual size_t getPlaneNumber() = 0;
|
||||
FrameSize ySize;
|
||||
FrameSize uvSize;
|
||||
|
||||
virtual FrameSize getPlaneSize(size_t plane) = 0;
|
||||
struct DataPointers {
|
||||
ubyte* y;
|
||||
ubyte* u;
|
||||
ubyte* v;
|
||||
};
|
||||
|
||||
virtual void* getPlaneData(size_t plane) = 0;
|
||||
virtual DataPointers getDataPointers() = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -41,19 +43,10 @@ using FramePtr = std::unique_ptr<T>;
|
||||
|
||||
typedef std::unique_ptr<VideoFrame> VideoFramePtr;
|
||||
|
||||
enum class FramePixelFormat {
|
||||
Invalid,
|
||||
YUV420,
|
||||
BGR,
|
||||
BGRA
|
||||
};
|
||||
|
||||
struct MovieProperties {
|
||||
FrameSize size;
|
||||
|
||||
float fps = -1.0f;
|
||||
|
||||
FramePixelFormat pixelFormat = FramePixelFormat::Invalid;
|
||||
};
|
||||
|
||||
struct AudioFrame {
|
||||
@@ -73,11 +66,6 @@ struct SubtitleFrame {
|
||||
};
|
||||
typedef std::unique_ptr<SubtitleFrame> SubtitleFramePtr;
|
||||
|
||||
struct PlaybackProperties {
|
||||
bool with_audio = true;
|
||||
bool looping = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Abstract class for decoding a video or audio stream
|
||||
*
|
||||
@@ -111,13 +99,13 @@ class Decoder {
|
||||
* @param fileName The name of the file that should be opened
|
||||
* @return @c true if the initialization was successfull, @c false otherwise
|
||||
*/
|
||||
virtual bool initialize(const SCP_string& fileName, const PlaybackProperties& properties) = 0;
|
||||
virtual bool initialize(const SCP_string& fileName) = 0;
|
||||
|
||||
/**
|
||||
* @brief Returns the properties of the video
|
||||
* @return The properties
|
||||
*/
|
||||
virtual MovieProperties getProperties() const = 0;
|
||||
virtual MovieProperties getProperties() = 0;
|
||||
|
||||
/**
|
||||
* @brief Starts decoding the video
|
||||
@@ -128,9 +116,9 @@ class Decoder {
|
||||
* @brief Determines if the video has audio
|
||||
* @return @c true if audio is included in the video
|
||||
*/
|
||||
virtual bool hasAudio() const = 0;
|
||||
virtual bool hasAudio() = 0;
|
||||
|
||||
virtual bool hasSubtitles() const = 0;
|
||||
virtual bool hasSubtitles() = 0;
|
||||
|
||||
/**
|
||||
* @brief Ends decoding of the video file
|
||||
@@ -147,6 +135,10 @@ class Decoder {
|
||||
|
||||
bool isSubtitleQueueFull() { return m_subtitleQueue->size() == m_queueSize; }
|
||||
|
||||
bool isSubtitleFrameAvailable() { return !m_subtitleQueue->empty(); }
|
||||
|
||||
size_t getSubtitleQueueSize() { return m_subtitleQueue->size(); }
|
||||
|
||||
bool tryPopSubtitleData(SubtitleFramePtr&);
|
||||
|
||||
bool isVideoQueueFull() { return m_videoQueue->size() == m_queueSize; }
|
||||
@@ -164,10 +156,16 @@ class Decoder {
|
||||
protected:
|
||||
void initializeQueues(size_t queueSize);
|
||||
|
||||
bool canPushAudioData();
|
||||
|
||||
void pushAudioData(AudioFramePtr&& data);
|
||||
|
||||
bool canPushSubtitleData();
|
||||
|
||||
void pushSubtitleData(SubtitleFramePtr&& data);
|
||||
|
||||
bool canPushVideoData();
|
||||
|
||||
void pushFrameData(VideoFramePtr&& frame);
|
||||
};
|
||||
}
|
||||
@@ -14,85 +14,46 @@ struct movie_vertex {
|
||||
|
||||
namespace cutscene {
|
||||
namespace player {
|
||||
VideoPresenter::VideoPresenter(const MovieProperties& props) : _properties(props)
|
||||
{
|
||||
VideoPresenter::VideoPresenter(const MovieProperties& props) {
|
||||
GR_DEBUG_SCOPE("Init video");
|
||||
|
||||
_planeTextureHandles.fill(-1);
|
||||
|
||||
auto w = static_cast<int>(props.size.width);
|
||||
auto h = static_cast<int>(props.size.height);
|
||||
|
||||
switch (props.pixelFormat) {
|
||||
case FramePixelFormat::YUV420:
|
||||
_planeTextureBuffers[0].reset(new uint8_t[w * h]);
|
||||
_planeTextureHandles[0] = bm_create(8, w, h, _planeTextureBuffers[0].get(), BMP_AABITMAP);
|
||||
// Create buffer textures
|
||||
_yTexBuffer.reset(new uint8_t[w * h]);
|
||||
_ytex = bm_create(8, w, h, _yTexBuffer.get(), BMP_AABITMAP);
|
||||
|
||||
_planeTextureBuffers[1].reset(new uint8_t[w / 2 * h / 2]);
|
||||
_planeTextureHandles[1] = bm_create(8, w / 2, h / 2, _planeTextureBuffers[1].get(), BMP_AABITMAP);
|
||||
_uTexBuffer.reset(new uint8_t[w / 2 * h / 2]);
|
||||
_utex = bm_create(8, w / 2, h / 2, _uTexBuffer.get(), BMP_AABITMAP);
|
||||
|
||||
_planeTextureBuffers[2].reset(new uint8_t[w / 2 * h / 2]);
|
||||
_planeTextureHandles[2] = bm_create(8, w / 2, h / 2, _planeTextureBuffers[2].get(), BMP_AABITMAP);
|
||||
_vTexBuffer.reset(new uint8_t[w / 2 * h / 2]);
|
||||
_vtex = bm_create(8, w / 2, h / 2, _vTexBuffer.get(), BMP_AABITMAP);
|
||||
|
||||
material_set_movie(&_movie_material, _planeTextureHandles[0], _planeTextureHandles[1], _planeTextureHandles[2]);
|
||||
break;
|
||||
case FramePixelFormat::BGR:
|
||||
_planeTextureBuffers[0].reset(new uint8_t[w * h * 3]);
|
||||
_planeTextureHandles[0] = bm_create(24, w, h, _planeTextureBuffers[0].get(), 0);
|
||||
|
||||
material_set_unlit(&_rgb_material, _planeTextureHandles[0], 1.0f, false, false);
|
||||
break;
|
||||
case FramePixelFormat::BGRA:
|
||||
_planeTextureBuffers[0].reset(new uint8_t[w * h * 4]);
|
||||
_planeTextureHandles[0] = bm_create(32, w, h, _planeTextureBuffers[0].get(), 0);
|
||||
|
||||
material_set_unlit(&_rgb_material, _planeTextureHandles[0], 1.0f, true, false);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE("Unhandled enum value!");
|
||||
break;
|
||||
}
|
||||
material_set_movie(&_render_material, _ytex, _utex, _vtex);
|
||||
}
|
||||
|
||||
VideoPresenter::~VideoPresenter() {
|
||||
GR_DEBUG_SCOPE("Deinit video");
|
||||
|
||||
for (auto& handle : _planeTextureHandles) {
|
||||
if (handle > 0) {
|
||||
bm_release(handle);
|
||||
handle = -1;
|
||||
}
|
||||
}
|
||||
bm_release(_ytex);
|
||||
bm_release(_utex);
|
||||
bm_release(_vtex);
|
||||
|
||||
_ytex = _utex = _vtex = -1;
|
||||
}
|
||||
|
||||
void VideoPresenter::uploadVideoFrame(const VideoFramePtr& frame) {
|
||||
GR_DEBUG_SCOPE("Update video frame");
|
||||
auto ptrs = frame->getDataPointers();
|
||||
|
||||
for (size_t i = 0; i < frame->getPlaneNumber(); ++i) {
|
||||
auto size = frame->getPlaneSize(i);
|
||||
auto data = frame->getPlaneData(i);
|
||||
memcpy(_yTexBuffer.get(), ptrs.y, frame->ySize.stride * frame->ySize.height);
|
||||
memcpy(_uTexBuffer.get(), ptrs.u, frame->uvSize.stride * frame->uvSize.height);
|
||||
memcpy(_vTexBuffer.get(), ptrs.v, frame->uvSize.stride * frame->uvSize.height);
|
||||
|
||||
memcpy(_planeTextureBuffers[i].get(), data, size.stride * size.height);
|
||||
|
||||
int bpp = 0;
|
||||
switch (_properties.pixelFormat) {
|
||||
case FramePixelFormat::YUV420:
|
||||
bpp = 8;
|
||||
break;
|
||||
case FramePixelFormat::BGR:
|
||||
bpp = 24;
|
||||
break;
|
||||
case FramePixelFormat::BGRA:
|
||||
bpp = 32;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE("Unhandled enum value!");
|
||||
break;
|
||||
}
|
||||
|
||||
gr_update_texture(_planeTextureHandles[i], bpp, _planeTextureBuffers[i].get(), static_cast<int>(size.width),
|
||||
static_cast<int>(size.height));
|
||||
}
|
||||
gr_update_texture(_ytex, 8, _yTexBuffer.get(), (int) frame->ySize.width, (int) frame->ySize.height);
|
||||
gr_update_texture(_utex, 8, _uTexBuffer.get(), (int) frame->uvSize.width, (int) frame->uvSize.height);
|
||||
gr_update_texture(_vtex, 8, _vTexBuffer.get(), (int) frame->uvSize.width, (int) frame->uvSize.height);
|
||||
}
|
||||
|
||||
void VideoPresenter::displayFrame(float x1, float y1, float x2, float y2) {
|
||||
@@ -124,14 +85,10 @@ void VideoPresenter::displayFrame(float x1, float y1, float x2, float y2) {
|
||||
auto offset = gr_add_to_immediate_buffer(sizeof(vertex_data), vertex_data);
|
||||
|
||||
vertex_layout layout;
|
||||
layout.add_vertex_component(vertex_format_data::POSITION2, sizeof(vertex_data[0]), offsetof(movie_vertex, pos));
|
||||
layout.add_vertex_component(vertex_format_data::TEX_COORD2, sizeof(vertex_data[0]), offsetof(movie_vertex, uv));
|
||||
layout.add_vertex_component(vertex_format_data::POSITION2, sizeof(vertex_data[0]), offset + offsetof(movie_vertex, pos));
|
||||
layout.add_vertex_component(vertex_format_data::TEX_COORD2, sizeof(vertex_data[0]), offset + offsetof(movie_vertex, uv));
|
||||
|
||||
if (_properties.pixelFormat == FramePixelFormat::YUV420) {
|
||||
gr_render_movie(&_movie_material, PRIM_TYPE_TRISTRIP, &layout, 4, gr_immediate_buffer_handle, offset);
|
||||
} else {
|
||||
gr_render_primitives(&_rgb_material, PRIM_TYPE_TRISTRIP, &layout, 0, 4, gr_immediate_buffer_handle, offset);
|
||||
}
|
||||
gr_render_movie(&_render_material, PRIM_TYPE_TRISTRIP, &layout, 4, gr_immediate_buffer_handle);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,13 +12,16 @@ namespace cutscene {
|
||||
namespace player {
|
||||
|
||||
class VideoPresenter {
|
||||
MovieProperties _properties;
|
||||
int _ytex = -1;
|
||||
std::unique_ptr<uint8_t[]> _yTexBuffer;
|
||||
|
||||
std::array<int, 3> _planeTextureHandles;
|
||||
std::array<std::unique_ptr<uint8_t[]>, 3> _planeTextureBuffers;
|
||||
int _utex = -1;
|
||||
std::unique_ptr<uint8_t[]> _uTexBuffer;
|
||||
|
||||
movie_material _movie_material;
|
||||
material _rgb_material; // Material used when a RGB/RGBA movie is played
|
||||
int _vtex = -1;
|
||||
std::unique_ptr<uint8_t[]> _vTexBuffer;
|
||||
|
||||
movie_material _render_material;
|
||||
public:
|
||||
explicit VideoPresenter(const MovieProperties& props);
|
||||
|
||||
|
||||
+12
-12
@@ -286,10 +286,10 @@ void cutscenes_screen_scroll_line_up()
|
||||
if (Selected_line)
|
||||
{
|
||||
Selected_line--;
|
||||
gamesnd_play_iface(InterfaceSounds::SCROLL);
|
||||
gamesnd_play_iface(SND_SCROLL);
|
||||
|
||||
} else
|
||||
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
|
||||
gamesnd_play_iface(SND_GENERAL_FAIL);
|
||||
|
||||
if (Selected_line < Scroll_offset)
|
||||
Scroll_offset = Selected_line;
|
||||
@@ -302,10 +302,10 @@ void cutscenes_screen_scroll_line_down()
|
||||
if (Selected_line < (int) Cutscene_list.size() - 1)
|
||||
{
|
||||
Selected_line++;
|
||||
gamesnd_play_iface(InterfaceSounds::SCROLL);
|
||||
gamesnd_play_iface(SND_SCROLL);
|
||||
|
||||
} else
|
||||
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
|
||||
gamesnd_play_iface(SND_GENERAL_FAIL);
|
||||
|
||||
h = Cutscene_list_coords[gr_screen.res][3] / gr_get_font_height();
|
||||
if (Selected_line >= Scroll_offset + h)
|
||||
@@ -328,11 +328,11 @@ void cutscenes_screen_scroll_screen_up()
|
||||
Selected_line--;
|
||||
}
|
||||
|
||||
gamesnd_play_iface(InterfaceSounds::SCROLL);
|
||||
gamesnd_play_iface(SND_SCROLL);
|
||||
|
||||
} else
|
||||
{
|
||||
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
|
||||
gamesnd_play_iface(SND_GENERAL_FAIL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -349,10 +349,10 @@ void cutscenes_screen_scroll_screen_down()
|
||||
Selected_line = Scroll_offset;
|
||||
}
|
||||
|
||||
gamesnd_play_iface(InterfaceSounds::SCROLL);
|
||||
gamesnd_play_iface(SND_SCROLL);
|
||||
} else
|
||||
{
|
||||
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
|
||||
gamesnd_play_iface(SND_GENERAL_FAIL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -361,17 +361,17 @@ int cutscenes_screen_button_pressed(int n)
|
||||
switch (n)
|
||||
{
|
||||
case TECH_DATABASE_BUTTON:
|
||||
gamesnd_play_iface(InterfaceSounds::SWITCH_SCREENS);
|
||||
gamesnd_play_iface(SND_SWITCH_SCREENS);
|
||||
gameseq_post_event(GS_EVENT_TECH_MENU);
|
||||
return 1;
|
||||
|
||||
case SIMULATOR_BUTTON:
|
||||
gamesnd_play_iface(InterfaceSounds::SWITCH_SCREENS);
|
||||
gamesnd_play_iface(SND_SWITCH_SCREENS);
|
||||
gameseq_post_event(GS_EVENT_SIMULATOR_ROOM);
|
||||
return 1;
|
||||
|
||||
case CREDITS_BUTTON:
|
||||
gamesnd_play_iface(InterfaceSounds::SWITCH_SCREENS);
|
||||
gamesnd_play_iface(SND_SWITCH_SCREENS);
|
||||
gameseq_post_event(GS_EVENT_CREDITS);
|
||||
return 1;
|
||||
|
||||
@@ -388,7 +388,7 @@ int cutscenes_screen_button_pressed(int n)
|
||||
break;
|
||||
|
||||
case EXIT_BUTTON:
|
||||
gamesnd_play_iface(InterfaceSounds::COMMIT_PRESSED);
|
||||
gamesnd_play_iface(SND_COMMIT_PRESSED);
|
||||
gameseq_post_event(GS_EVENT_MAIN_MENU);
|
||||
game_flush();
|
||||
break;
|
||||
|
||||
@@ -21,7 +21,15 @@ typedef struct cutscene_info
|
||||
bool viewable;
|
||||
} cutscene_info;
|
||||
|
||||
#if SCP_COMPILER_IS_GNU
|
||||
#pragma GCC diagnostic push
|
||||
// This suppresses a GCC bug where it thinks that the Cutscenes from the enum class below shadows a global variable
|
||||
#pragma GCC diagnostic ignored "-Wshadow"
|
||||
#endif
|
||||
extern SCP_vector<cutscene_info> Cutscenes;
|
||||
#if SCP_COMPILER_IS_GNU
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
// initializa table data
|
||||
void cutscene_init();
|
||||
|
||||
@@ -55,9 +55,6 @@ int resample_convert(SwrContext* ctx, uint8_t** output,
|
||||
#ifdef WITH_LIBAV
|
||||
return avresample_convert(ctx, output, out_plane_size, out_samples, input, in_plane_size, in_samples);
|
||||
#else
|
||||
(void)out_plane_size;
|
||||
(void)in_plane_size;
|
||||
|
||||
return swr_convert(ctx, output, out_samples, (const uint8_t**) input, in_samples);
|
||||
#endif
|
||||
}
|
||||
@@ -223,8 +220,5 @@ void AudioDecoder::finishDecoding() {
|
||||
// Push the last bits of audio data into the queue
|
||||
flushAudioBuffer();
|
||||
}
|
||||
void AudioDecoder::flushBuffers() {
|
||||
avcodec_flush_buffers(m_status->audioCodecCtx);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,13 +25,11 @@ class AudioDecoder: public FFMPEGStreamDecoder<AudioFrame> {
|
||||
public:
|
||||
explicit AudioDecoder(DecoderStatus* status);
|
||||
|
||||
~AudioDecoder() override;
|
||||
virtual ~AudioDecoder();
|
||||
|
||||
void decodePacket(AVPacket* packet) override;
|
||||
virtual void decodePacket(AVPacket* packet) SCP_OVERRIDE;
|
||||
|
||||
void finishDecoding() override;
|
||||
|
||||
void flushBuffers() override;
|
||||
virtual void finishDecoding() SCP_OVERRIDE;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,6 @@
|
||||
#include "cutscene/ffmpeg/VideoDecoder.h"
|
||||
#include "cutscene/ffmpeg/SubtitleDecoder.h"
|
||||
|
||||
#include "FFMPEGDecoder.h"
|
||||
#include "localization/localize.h"
|
||||
|
||||
using namespace libs::ffmpeg;
|
||||
@@ -28,26 +27,20 @@ class AVPacketScope
|
||||
: _packet(av_packet) {
|
||||
}
|
||||
|
||||
AVPacketScope(const AVPacketScope&) = delete;
|
||||
AVPacketScope& operator=(const AVPacketScope&) = delete;
|
||||
|
||||
~AVPacketScope() {
|
||||
av_packet_unref(_packet);
|
||||
}
|
||||
};
|
||||
|
||||
const char* CHECKED_EXTENSIONS[] = {"webm", "mp4", "ogg",
|
||||
"png", // This is designed to be used with APNG animations
|
||||
"mve"};
|
||||
|
||||
const char* CHECKED_SUBT_EXTENSIONS[] = {"srt"};
|
||||
const char* CHECKED_EXTENSIONS[] = {
|
||||
"webm",
|
||||
"mp4",
|
||||
"ogg",
|
||||
"mve"
|
||||
};
|
||||
|
||||
double getFrameRate(AVStream* stream, AVCodecContext* codecCtx) {
|
||||
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(58, 3, 102)
|
||||
auto fps = av_q2d(stream->r_frame_rate);
|
||||
#else
|
||||
auto fps = av_q2d(av_stream_get_r_frame_rate(stream));
|
||||
#endif
|
||||
|
||||
if (fps < 0.000001)
|
||||
{
|
||||
@@ -65,111 +58,45 @@ double getFrameRate(AVStream* stream, AVCodecContext* codecCtx) {
|
||||
CodecContextParameters getCodecParameters(AVStream* stream) {
|
||||
CodecContextParameters paras;
|
||||
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
|
||||
paras.width = stream->codecpar->width;
|
||||
paras.height = stream->codecpar->height;
|
||||
paras.width = stream->codecpar->width;
|
||||
paras.height = stream->codecpar->height;
|
||||
paras.pixel_format = (AVPixelFormat)stream->codecpar->format;
|
||||
|
||||
paras.channel_layout = stream->codecpar->channel_layout;
|
||||
paras.sample_rate = stream->codecpar->sample_rate;
|
||||
paras.audio_format = (AVSampleFormat)stream->codecpar->format;
|
||||
paras.sample_rate = stream->codecpar->sample_rate;
|
||||
paras.audio_format = (AVSampleFormat)stream->codecpar->format;
|
||||
|
||||
paras.codec_id = stream->codecpar->codec_id;
|
||||
paras.codec_id = stream->codecpar->codec_id;
|
||||
#else
|
||||
paras.width = stream->codec->width;
|
||||
paras.height = stream->codec->height;
|
||||
paras.width = stream->codec->width;
|
||||
paras.height = stream->codec->height;
|
||||
paras.pixel_format = stream->codec->pix_fmt;
|
||||
|
||||
paras.channel_layout = stream->codec->channel_layout;
|
||||
paras.sample_rate = stream->codec->sample_rate;
|
||||
paras.audio_format = stream->codec->sample_fmt;
|
||||
paras.sample_rate = stream->codec->sample_rate;
|
||||
paras.audio_format = stream->codec->sample_fmt;
|
||||
|
||||
paras.codec_id = stream->codec->codec_id;
|
||||
paras.codec_id = stream->codec->codec_id;
|
||||
#endif
|
||||
return paras;
|
||||
return paras;
|
||||
}
|
||||
|
||||
SCP_string normalizeLanguage(const char* langauge_name) {
|
||||
if (!stricmp(langauge_name, "eng")) {
|
||||
return "English";
|
||||
}
|
||||
if (!stricmp(langauge_name, "ger")) {
|
||||
return "German";
|
||||
}
|
||||
if (!stricmp(langauge_name, "spa")) {
|
||||
return "Spanish";
|
||||
}
|
||||
if (!stricmp(langauge_name, "eng")) {
|
||||
return "English";
|
||||
}
|
||||
if (!stricmp(langauge_name, "ger")) {
|
||||
return "German";
|
||||
}
|
||||
if (!stricmp(langauge_name, "spa")) {
|
||||
return "Spanish";
|
||||
}
|
||||
|
||||
// Print to log so that we can find the actual value more easily later
|
||||
mprintf(("FFmpeg log: Found unknown language value '%s'!\n", langauge_name));
|
||||
// Print to log so that we can find the actual value more easily later
|
||||
mprintf(("FFmpeg log: Found unknown language value '%s'!\n", langauge_name));
|
||||
|
||||
// Default to english for everything else
|
||||
return "English";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Given a FFmpeg pixel format returns the format it should be converted to
|
||||
* @param in_fmt The input format
|
||||
* @return The output format
|
||||
*/
|
||||
AVPixelFormat getConversionFormat(AVPixelFormat in_fmt)
|
||||
{
|
||||
switch (in_fmt) {
|
||||
case AV_PIX_FMT_RGB24:
|
||||
case AV_PIX_FMT_BGR24:
|
||||
case AV_PIX_FMT_BGR8:
|
||||
case AV_PIX_FMT_BGR4:
|
||||
case AV_PIX_FMT_BGR4_BYTE:
|
||||
case AV_PIX_FMT_RGB8:
|
||||
case AV_PIX_FMT_RGB4:
|
||||
case AV_PIX_FMT_RGB4_BYTE:
|
||||
case AV_PIX_FMT_RGB48BE:
|
||||
case AV_PIX_FMT_RGB48LE:
|
||||
case AV_PIX_FMT_RGB565BE:
|
||||
case AV_PIX_FMT_RGB565LE:
|
||||
case AV_PIX_FMT_RGB555BE:
|
||||
case AV_PIX_FMT_RGB555LE:
|
||||
case AV_PIX_FMT_BGR565BE:
|
||||
case AV_PIX_FMT_BGR565LE:
|
||||
case AV_PIX_FMT_BGR555BE:
|
||||
case AV_PIX_FMT_BGR555LE:
|
||||
case AV_PIX_FMT_RGB444LE:
|
||||
case AV_PIX_FMT_RGB444BE:
|
||||
case AV_PIX_FMT_BGR444LE:
|
||||
case AV_PIX_FMT_BGR444BE:
|
||||
case AV_PIX_FMT_BGR48BE:
|
||||
case AV_PIX_FMT_BGR48LE:
|
||||
case AV_PIX_FMT_0RGB:
|
||||
case AV_PIX_FMT_RGB0:
|
||||
case AV_PIX_FMT_0BGR:
|
||||
case AV_PIX_FMT_BGR0:
|
||||
return AV_PIX_FMT_BGR24;
|
||||
|
||||
case AV_PIX_FMT_RGBA64BE:
|
||||
case AV_PIX_FMT_RGBA64LE:
|
||||
case AV_PIX_FMT_BGRA64BE:
|
||||
case AV_PIX_FMT_BGRA64LE:
|
||||
case AV_PIX_FMT_ARGB:
|
||||
case AV_PIX_FMT_RGBA:
|
||||
case AV_PIX_FMT_ABGR:
|
||||
case AV_PIX_FMT_BGRA:
|
||||
return AV_PIX_FMT_BGRA;
|
||||
|
||||
default:
|
||||
// Assume that everything else is converted to YUV 420
|
||||
return AV_PIX_FMT_YUV420P;
|
||||
}
|
||||
}
|
||||
|
||||
FramePixelFormat getPixelFormat(AVPixelFormat fmt)
|
||||
{
|
||||
switch (fmt) {
|
||||
case AV_PIX_FMT_BGR24:
|
||||
return FramePixelFormat::BGR;
|
||||
case AV_PIX_FMT_BGRA:
|
||||
return FramePixelFormat::BGRA;
|
||||
default:
|
||||
return FramePixelFormat::YUV420;
|
||||
}
|
||||
// Default to english for everything else
|
||||
return "English";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,15 +143,7 @@ std::unique_ptr<InputStream> openStream(const SCP_string& name) {
|
||||
return input;
|
||||
}
|
||||
|
||||
std::unique_ptr<DecoderStatus> initializeStatus(std::unique_ptr<InputStream>& stream,
|
||||
std::unique_ptr<InputStream>& subt,
|
||||
const PlaybackProperties& properties)
|
||||
{
|
||||
if (subt && properties.looping) {
|
||||
mprintf(("FFmpeg: External subtitles and looping movies are not supported!\n"));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<DecoderStatus> initializeStatus(std::unique_ptr<InputStream>& stream) {
|
||||
std::unique_ptr<DecoderStatus> status(new DecoderStatus());
|
||||
|
||||
auto ctx = stream->m_ctx->ctx();
|
||||
@@ -242,18 +161,14 @@ std::unique_ptr<DecoderStatus> initializeStatus(std::unique_ptr<InputStream>& st
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int audioStream = -1;
|
||||
|
||||
if (properties.with_audio) {
|
||||
audioStream = av_find_best_stream(ctx, AVMEDIA_TYPE_AUDIO, -1, videoStream, &status->audioCodec, 0);
|
||||
if (audioStream < 0) {
|
||||
if (audioStream == AVERROR_STREAM_NOT_FOUND) {
|
||||
mprintf(("FFmpeg: No audio stream found in file!\n"));
|
||||
} else if (audioStream == AVERROR_DECODER_NOT_FOUND) {
|
||||
mprintf(("FFmpeg: Codec for audio stream could not be found!\n"));
|
||||
} else {
|
||||
mprintf(("FFmpeg: Unknown error while finding audio stream!\n"));
|
||||
}
|
||||
auto audioStream = av_find_best_stream(ctx, AVMEDIA_TYPE_AUDIO, -1, videoStream, &status->audioCodec, 0);
|
||||
if (audioStream < 0) {
|
||||
if (audioStream == AVERROR_STREAM_NOT_FOUND) {
|
||||
mprintf(("FFmpeg: No audio stream found in file!\n"));
|
||||
} else if (videoStream == AVERROR_DECODER_NOT_FOUND) {
|
||||
mprintf(("FFmpeg: Codec for audio stream could not be found!\n"));
|
||||
} else {
|
||||
mprintf(("FFmpeg: Unknown error while finding audio stream!\n"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,60 +180,31 @@ std::unique_ptr<DecoderStatus> initializeStatus(std::unique_ptr<InputStream>& st
|
||||
status->audioStream = ctx->streams[audioStream];
|
||||
}
|
||||
|
||||
if (subt) {
|
||||
auto subtCtx = subt->m_ctx->ctx();
|
||||
auto& current_language = Lcl_languages[Lcl_current_lang];
|
||||
for (uint32_t i = 0; i < ctx->nb_streams; ++i) {
|
||||
auto test_stream = ctx->streams[i];
|
||||
|
||||
auto subtStream = av_find_best_stream(subtCtx, AVMEDIA_TYPE_SUBTITLE, -1, -1, nullptr, 0);
|
||||
if (subtStream < 0) {
|
||||
if (subtStream == AVERROR_STREAM_NOT_FOUND) {
|
||||
mprintf(("FFmpeg: No subtitle stream found in subtitle file!\n"));
|
||||
} else if (subtStream == AVERROR_DECODER_NOT_FOUND) {
|
||||
mprintf(("FFmpeg: Codec for subtitle stream could not be found!\n"));
|
||||
} else {
|
||||
mprintf(("FFmpeg: Unknown error while finding subtitle stream!\n"));
|
||||
}
|
||||
} else {
|
||||
status->subtitleStream = subtCtx->streams[subtStream];
|
||||
status->externalSubtitles = true;
|
||||
status->subtitleStreamIndex = subtStream;
|
||||
auto& pars = test_stream->codecpar;
|
||||
|
||||
if (!(pars->codec_type == AVMEDIA_TYPE_SUBTITLE)) {
|
||||
continue;
|
||||
}
|
||||
AVDictionaryEntry* tag = nullptr;
|
||||
if ((tag = av_dict_get(test_stream->metadata, "language", nullptr, 0)) == nullptr) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (status->subtitleStream == nullptr) {
|
||||
// We don't have an external subtitle stream or loading from that file has failed
|
||||
auto& current_language = Lcl_languages[Lcl_current_lang];
|
||||
for (uint32_t i = 0; i < ctx->nb_streams; ++i) {
|
||||
auto test_stream = ctx->streams[i];
|
||||
auto normalized_language = normalizeLanguage(tag->value);
|
||||
|
||||
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
|
||||
auto& pars = test_stream->codecpar;
|
||||
|
||||
if (!(pars->codec_type == AVMEDIA_TYPE_SUBTITLE)) {
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
AVDictionaryEntry* tag = nullptr;
|
||||
if ((tag = av_dict_get(test_stream->metadata, "language", nullptr, 0)) == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto normalized_language = normalizeLanguage(tag->value);
|
||||
|
||||
if (!stricmp(normalized_language.c_str(), current_language.lang_name)) {
|
||||
status->subtitleStreamIndex = i;
|
||||
status->subtitleStream = test_stream;
|
||||
break;
|
||||
}
|
||||
if (!stricmp(normalized_language.c_str(), current_language.lang_name)) {
|
||||
status->subtitleStreamIndex = i;
|
||||
status->subtitleStream = test_stream;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
status->videoCodecPars = getCodecParameters(status->videoStream);
|
||||
|
||||
if (properties.looping && status->videoCodecPars.codec_id == AV_CODEC_ID_INTERPLAY_VIDEO) {
|
||||
mprintf(("FFmpeg: Looping is not supported for inteplay (MVE) movies!\n"));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int err;
|
||||
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
|
||||
status->videoCodecCtx = avcodec_alloc_context3(status->videoCodec);
|
||||
@@ -375,37 +261,36 @@ std::unique_ptr<DecoderStatus> initializeStatus(std::unique_ptr<InputStream>& st
|
||||
status->audioCodec->name ? status->audioCodec->name : "<Unknown>"));
|
||||
}
|
||||
|
||||
if (status->subtitleStream != nullptr) {
|
||||
// Not really sure if this makes sense for subtitles but it shouldn't break anything...
|
||||
status->subtitleCodecPars = getCodecParameters(status->subtitleStream);
|
||||
if (status->subtitleStreamIndex >= 0) {
|
||||
// Not really sure if this makes sense for subtitles but it shouldn't break anything...
|
||||
status->subtitleCodecPars = getCodecParameters(status->subtitleStream);
|
||||
|
||||
status->subtitleCodec = avcodec_find_decoder(status->subtitleCodecPars.codec_id);
|
||||
status->subtitleCodec = avcodec_find_decoder(status->subtitleCodecPars.codec_id);
|
||||
|
||||
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
|
||||
status->subtitleCodecCtx = avcodec_alloc_context3(status->subtitleCodec);
|
||||
status->subtitleCodecCtx = avcodec_alloc_context3(status->subtitleCodec);
|
||||
|
||||
err = avcodec_parameters_to_context(status->subtitleCodecCtx, status->subtitleStream->codecpar);
|
||||
if (err < 0) {
|
||||
char errorStr[512];
|
||||
av_strerror(err, errorStr, sizeof(errorStr));
|
||||
mprintf(("FFMPEG: Failed to copy context parameters! Error: %s\n", errorStr));
|
||||
return nullptr;
|
||||
}
|
||||
err = avcodec_parameters_to_context(status->subtitleCodecCtx, status->subtitleStream->codecpar);
|
||||
if (err < 0) {
|
||||
char errorStr[512];
|
||||
av_strerror(err, errorStr, sizeof(errorStr));
|
||||
mprintf(("FFMPEG: Failed to copy context parameters! Error: %s\n", errorStr));
|
||||
return nullptr;
|
||||
}
|
||||
#else
|
||||
status->subtitleCodecCtx = status->subtitleStream->codec;
|
||||
status->subtitleCodecCtx = status->subtitleStream->codec;
|
||||
#endif
|
||||
|
||||
err = avcodec_open2(status->subtitleCodecCtx, status->subtitleCodec, nullptr);
|
||||
if (err < 0) {
|
||||
char errorStr[512];
|
||||
av_strerror(err, errorStr, sizeof(errorStr));
|
||||
mprintf(("FFMPEG: Failed to open subtitle codec! Error: %s\n", errorStr));
|
||||
}
|
||||
err = avcodec_open2(status->subtitleCodecCtx, status->subtitleCodec, nullptr);
|
||||
if (err < 0) {
|
||||
char errorStr[512];
|
||||
av_strerror(err, errorStr, sizeof(errorStr));
|
||||
mprintf(("FFMPEG: Failed to open subtitle codec! Error: %s\n", errorStr));
|
||||
}
|
||||
|
||||
mprintf(("FFmpeg: Using subtitle codec %s (%s).\n",
|
||||
status->subtitleCodec->long_name ? status->subtitleCodec->long_name : "<Unknown>",
|
||||
status->subtitleCodec->name ? status->subtitleCodec->name : "<Unknown>"));
|
||||
}
|
||||
mprintf(("FFmpeg: Using subtitle codec %s (%s).\n", status->subtitleCodec->long_name ? status->subtitleCodec->long_name : "<Unknown>",
|
||||
status->subtitleCodec->name ? status->subtitleCodec->name : "<Unknown>"));
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
@@ -425,35 +310,12 @@ std::unique_ptr<InputStream> openInputStream(const SCP_string& name) {
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<InputStream> openSubtitleStream(const SCP_string& name)
|
||||
{
|
||||
auto& current_language = Lcl_languages[Lcl_current_lang];
|
||||
|
||||
for (auto ext : CHECKED_SUBT_EXTENSIONS) {
|
||||
SCP_string fileName;
|
||||
if (strlen(current_language.lang_ext) == 0) {
|
||||
fileName = name + "." + ext;
|
||||
} else {
|
||||
fileName = name + "-" + current_language.lang_ext + "." + ext;
|
||||
}
|
||||
|
||||
auto input = openStream(fileName);
|
||||
|
||||
if (input) {
|
||||
return input;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool FFMPEGDecoder::initialize(const SCP_string& fileName, const PlaybackProperties& properties)
|
||||
{
|
||||
bool FFMPEGDecoder::initialize(const SCP_string& fileName) {
|
||||
SCP_string movieName = fileName;
|
||||
// First make the file name lower case
|
||||
std::transform(movieName.begin(), movieName.end(), movieName.begin(), [](char c) { return (char)::tolower(c); });
|
||||
std::transform(movieName.begin(), movieName.end(), movieName.begin(), ::tolower);
|
||||
|
||||
// Then remove the extension
|
||||
size_t dotPos = movieName.find('.');
|
||||
@@ -467,10 +329,8 @@ bool FFMPEGDecoder::initialize(const SCP_string& fileName, const PlaybackPropert
|
||||
return false;
|
||||
}
|
||||
|
||||
auto subt = openSubtitleStream(movieName);
|
||||
|
||||
// We now have a valid input stream, try to find the correct streams
|
||||
auto status = initializeStatus(input, subt, properties);
|
||||
auto status = initializeStatus(input);
|
||||
if (!status) {
|
||||
return false;
|
||||
}
|
||||
@@ -480,178 +340,46 @@ bool FFMPEGDecoder::initialize(const SCP_string& fileName, const PlaybackPropert
|
||||
|
||||
// We're done, now just put the pointer into this
|
||||
std::swap(m_input, input);
|
||||
std::swap(m_subtitleInput, subt);
|
||||
std::swap(m_status, status);
|
||||
m_properties = properties;
|
||||
return true;
|
||||
}
|
||||
|
||||
MovieProperties FFMPEGDecoder::getProperties() const
|
||||
{
|
||||
MovieProperties FFMPEGDecoder::getProperties() {
|
||||
MovieProperties props;
|
||||
props.size.width = static_cast<size_t>(m_status->videoCodecPars.width);
|
||||
props.size.height = static_cast<size_t>(m_status->videoCodecPars.height);
|
||||
|
||||
props.fps = static_cast<float>(getFrameRate(m_status->videoStream, m_status->videoCodecCtx));
|
||||
|
||||
props.pixelFormat = getPixelFormat(getConversionFormat(m_status->videoCodecPars.pixel_format));
|
||||
|
||||
return props;
|
||||
}
|
||||
|
||||
void FFMPEGDecoder::startDecoding() {
|
||||
std::unique_ptr<VideoDecoder> videoDecoder(new VideoDecoder(m_status.get(), getConversionFormat(m_status->videoCodecPars.pixel_format)));
|
||||
std::unique_ptr<VideoDecoder> videoDecoder(new VideoDecoder(m_status.get()));
|
||||
|
||||
std::unique_ptr<AudioDecoder> audioDecoder;
|
||||
std::unique_ptr<SubtitleDecoder> subtitleDecoder;
|
||||
std::unique_ptr<SubtitleDecoder> subtitleDecoder;
|
||||
|
||||
if (hasAudio()) {
|
||||
audioDecoder.reset(new AudioDecoder(m_status.get()));
|
||||
}
|
||||
if (hasSubtitles()) {
|
||||
subtitleDecoder.reset(new SubtitleDecoder(m_status.get()));
|
||||
}
|
||||
|
||||
std::unique_ptr<std::thread> subtitle_thread;
|
||||
if (hasExternalSubtitle()) {
|
||||
// Start a new thread for the subtitles since otherwise we would need to make sure that neither of the input
|
||||
// streames starves while the other waits for more space in the queues
|
||||
subtitle_thread.reset(
|
||||
new std::thread([this, &subtitleDecoder]() { runSubtitleDecoder(subtitleDecoder.get()); }));
|
||||
}
|
||||
if (hasSubtitles()) {
|
||||
subtitleDecoder.reset(new SubtitleDecoder(m_status.get()));
|
||||
}
|
||||
|
||||
auto ctx = m_input->m_ctx->ctx();
|
||||
AVPacket packet;
|
||||
do {
|
||||
if (m_properties.looping) {
|
||||
// Only seek if we are looping the movie. The MVE code doesn't support seeking to this function may not be
|
||||
// called there
|
||||
auto seek_err = av_seek_frame(ctx, -1, 0, AVSEEK_FLAG_BACKWARD);
|
||||
if (seek_err < 0) {
|
||||
char errorStr[512];
|
||||
av_strerror(seek_err, errorStr, sizeof(errorStr));
|
||||
mprintf(("FFMPEG: Failed to seek to start of movie file! Error: %s\n", errorStr));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
videoDecoder->flushBuffers();
|
||||
if (audioDecoder) {
|
||||
audioDecoder->flushBuffers();
|
||||
}
|
||||
if (subtitleDecoder) {
|
||||
subtitleDecoder->flushBuffers();
|
||||
}
|
||||
|
||||
while (isDecoding()) {
|
||||
auto read_err = av_read_frame(ctx, &packet);
|
||||
AVPacketScope scope(&packet);
|
||||
|
||||
if (read_err < 0) {
|
||||
if (read_err == AVERROR_EOF) {
|
||||
// Finished reading -> break out of loop
|
||||
break;
|
||||
} else if (avio_feof(ctx->pb) != 0) {
|
||||
// Also EOF!
|
||||
break;
|
||||
} else {
|
||||
// Some kind of other error, try to continue reading
|
||||
char errorStr[512];
|
||||
av_strerror(read_err, errorStr, sizeof(errorStr));
|
||||
mprintf(("FFMPEG: Failed to read frame! Error: %s\n", errorStr));
|
||||
|
||||
// Skip packet
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (packet.stream_index == m_status->videoStreamIndex) {
|
||||
videoDecoder->decodePacket(&packet);
|
||||
|
||||
VideoFramePtr ptr;
|
||||
while ((ptr = videoDecoder->getFrame()) != nullptr) {
|
||||
pushFrameData(std::move(ptr));
|
||||
}
|
||||
} else if (audioDecoder && packet.stream_index == m_status->audioStreamIndex) {
|
||||
audioDecoder->decodePacket(&packet);
|
||||
|
||||
AudioFramePtr ptr;
|
||||
while ((ptr = audioDecoder->getFrame()) != nullptr) {
|
||||
pushAudioData(std::move(ptr));
|
||||
}
|
||||
} else if (subtitleDecoder && packet.stream_index == m_status->subtitleStreamIndex) {
|
||||
subtitleDecoder->decodePacket(&packet);
|
||||
|
||||
SubtitleFramePtr ptr;
|
||||
while ((ptr = subtitleDecoder->getFrame()) != nullptr) {
|
||||
pushSubtitleData(std::move(ptr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isDecoding()) {
|
||||
// If we are still alive then read the last frames from the decoders
|
||||
videoDecoder->finishDecoding();
|
||||
VideoFramePtr video_ptr;
|
||||
while ((video_ptr = videoDecoder->getFrame()) != nullptr) {
|
||||
pushFrameData(std::move(video_ptr));
|
||||
}
|
||||
|
||||
if (audioDecoder) {
|
||||
audioDecoder->finishDecoding();
|
||||
AudioFramePtr audio_frame;
|
||||
while ((audio_frame = audioDecoder->getFrame()) != nullptr) {
|
||||
pushAudioData(std::move(audio_frame));
|
||||
}
|
||||
}
|
||||
}
|
||||
// If the video is being looped then we start again from the beginning
|
||||
} while (m_properties.looping && isDecoding());
|
||||
|
||||
// Stop the decoder first to let the subtitle thread know that it shouldn't continue
|
||||
stopDecoder();
|
||||
|
||||
if (subtitle_thread) {
|
||||
subtitle_thread->join();
|
||||
}
|
||||
}
|
||||
|
||||
bool FFMPEGDecoder::hasAudio() const { return m_status->audioStreamIndex >= 0; }
|
||||
|
||||
bool FFMPEGDecoder::hasSubtitles() const { return m_status->subtitleStream != nullptr; }
|
||||
|
||||
bool FFMPEGDecoder::hasExternalSubtitle() const { return m_status->externalSubtitles; }
|
||||
|
||||
void FFMPEGDecoder::close() {
|
||||
if (m_status) {
|
||||
m_status = nullptr;
|
||||
}
|
||||
|
||||
if (m_input) {
|
||||
// This will delete the InputStream pointer and free all data
|
||||
m_input = nullptr;
|
||||
}
|
||||
|
||||
if (m_subtitleInput) {
|
||||
m_subtitleInput = nullptr;
|
||||
}
|
||||
}
|
||||
void FFMPEGDecoder::runSubtitleDecoder(SubtitleDecoder* decoder)
|
||||
{
|
||||
auto ctx = m_subtitleInput->m_ctx->ctx();
|
||||
AVPacket packet;
|
||||
|
||||
while (isDecoding()) {
|
||||
auto read_err = av_read_frame(ctx, &packet);
|
||||
AVPacketScope scope(&packet);
|
||||
|
||||
if (read_err < 0) {
|
||||
if (avio_feof(ctx->pb) != 0) {
|
||||
// EOF!!
|
||||
break;
|
||||
} else if (read_err < 0) {
|
||||
if (read_err == AVERROR_EOF) {
|
||||
// Finished reading -> break out of loop
|
||||
break;
|
||||
} else if (avio_feof(ctx->pb) != 0) {
|
||||
// Also EOF!
|
||||
break;
|
||||
} else {
|
||||
// Some kind of other error, try to continue reading
|
||||
char errorStr[512];
|
||||
@@ -663,23 +391,66 @@ void FFMPEGDecoder::runSubtitleDecoder(SubtitleDecoder* decoder)
|
||||
}
|
||||
}
|
||||
|
||||
if (packet.stream_index == m_status->subtitleStreamIndex) {
|
||||
decoder->decodePacket(&packet);
|
||||
if (packet.stream_index == m_status->videoStreamIndex) {
|
||||
videoDecoder->decodePacket(&packet);
|
||||
|
||||
SubtitleFramePtr ptr;
|
||||
while ((ptr = decoder->getFrame()) != nullptr) {
|
||||
pushSubtitleData(std::move(ptr));
|
||||
VideoFramePtr ptr;
|
||||
while((ptr = videoDecoder->getFrame()) != nullptr) {
|
||||
pushFrameData(std::move(ptr));
|
||||
}
|
||||
} else if (audioDecoder && packet.stream_index == m_status->audioStreamIndex) {
|
||||
audioDecoder->decodePacket(&packet);
|
||||
|
||||
AudioFramePtr ptr;
|
||||
while ((ptr = audioDecoder->getFrame()) != nullptr) {
|
||||
pushAudioData(std::move(ptr));
|
||||
}
|
||||
} else if (subtitleDecoder && packet.stream_index == m_status->subtitleStreamIndex) {
|
||||
subtitleDecoder->decodePacket(&packet);
|
||||
|
||||
SubtitleFramePtr ptr;
|
||||
while((ptr = subtitleDecoder->getFrame()) != nullptr) {
|
||||
pushSubtitleData(std::move(ptr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isDecoding()) {
|
||||
// If we are still alive then read the last frames from the decoders
|
||||
videoDecoder->finishDecoding();
|
||||
VideoFramePtr video_ptr;
|
||||
while ((video_ptr = videoDecoder->getFrame()) != nullptr) {
|
||||
pushFrameData(std::move(video_ptr));
|
||||
}
|
||||
|
||||
if (audioDecoder) {
|
||||
audioDecoder->finishDecoding();
|
||||
AudioFramePtr audio_frame;
|
||||
while ((audio_frame = audioDecoder->getFrame()) != nullptr) {
|
||||
pushAudioData(std::move(audio_frame));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isDecoding()) {
|
||||
// If we are still alive then read the last frames from the decoders
|
||||
decoder->finishDecoding();
|
||||
|
||||
SubtitleFramePtr ptr;
|
||||
while ((ptr = decoder->getFrame()) != nullptr) {
|
||||
pushSubtitleData(std::move(ptr));
|
||||
}
|
||||
stopDecoder();
|
||||
}
|
||||
|
||||
bool FFMPEGDecoder::hasAudio() {
|
||||
return m_status->audioStreamIndex >= 0;
|
||||
}
|
||||
|
||||
bool FFMPEGDecoder::hasSubtitles() {
|
||||
return m_status->subtitleStreamIndex >= 0;
|
||||
}
|
||||
|
||||
void FFMPEGDecoder::close() {
|
||||
if (m_status) {
|
||||
m_status = nullptr;
|
||||
}
|
||||
|
||||
if (m_input) {
|
||||
// This will delete the InputStream pointer and free all data
|
||||
m_input = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,38 +8,28 @@ struct InputStream;
|
||||
|
||||
struct DecoderStatus;
|
||||
|
||||
class SubtitleDecoder;
|
||||
|
||||
class FFMPEGDecoder: public Decoder {
|
||||
private:
|
||||
std::unique_ptr<InputStream> m_input;
|
||||
|
||||
std::unique_ptr<InputStream> m_subtitleInput;
|
||||
|
||||
std::unique_ptr<DecoderStatus> m_status;
|
||||
|
||||
PlaybackProperties m_properties;
|
||||
|
||||
bool hasExternalSubtitle() const;
|
||||
|
||||
void runSubtitleDecoder(SubtitleDecoder* decoder);
|
||||
|
||||
public:
|
||||
public:
|
||||
FFMPEGDecoder();
|
||||
|
||||
~FFMPEGDecoder() override;
|
||||
virtual ~FFMPEGDecoder();
|
||||
|
||||
bool initialize(const SCP_string& fileName, const PlaybackProperties& properties) override;
|
||||
bool initialize(const SCP_string& fileName) SCP_OVERRIDE;
|
||||
|
||||
MovieProperties getProperties() const override;
|
||||
MovieProperties getProperties() SCP_OVERRIDE;
|
||||
|
||||
void startDecoding() override;
|
||||
void startDecoding() SCP_OVERRIDE;
|
||||
|
||||
bool hasAudio() const override;
|
||||
bool hasAudio() SCP_OVERRIDE;
|
||||
|
||||
bool hasSubtitles() const override;
|
||||
bool hasSubtitles() SCP_OVERRIDE;
|
||||
|
||||
void close() override;
|
||||
void close() SCP_OVERRIDE;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -31,25 +31,7 @@ void SubtitleDecoder::decodePacket(AVPacket* packet) {
|
||||
}
|
||||
}
|
||||
void SubtitleDecoder::finishDecoding() {
|
||||
// Handle those decoders that have a delay
|
||||
AVPacket nullPacket;
|
||||
memset(&nullPacket, 0, sizeof(nullPacket));
|
||||
nullPacket.data = nullptr;
|
||||
nullPacket.size = 0;
|
||||
|
||||
AVSubtitle subtitle;
|
||||
while (true) {
|
||||
int finishedFrame = 1;
|
||||
auto err = avcodec_decode_subtitle2(m_status->subtitleCodecCtx, &subtitle, &finishedFrame, &nullPacket);
|
||||
|
||||
if (err < 0 || !finishedFrame) {
|
||||
break;
|
||||
}
|
||||
|
||||
pushSubtitleFrame(&nullPacket, &subtitle);
|
||||
|
||||
avsubtitle_free(&subtitle);
|
||||
}
|
||||
}
|
||||
void SubtitleDecoder::pushSubtitleFrame(AVPacket* packet, AVSubtitle* subtitle) {
|
||||
if (subtitle->format != 1) {
|
||||
@@ -129,9 +111,6 @@ void SubtitleDecoder::pushSubtitleFrame(AVPacket* packet, AVSubtitle* subtitle)
|
||||
|
||||
pushFrame(std::move(frame));
|
||||
}
|
||||
void SubtitleDecoder::flushBuffers() {
|
||||
avcodec_flush_buffers(m_status->subtitleCodecCtx);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,13 +10,12 @@ class SubtitleDecoder: public FFMPEGStreamDecoder<SubtitleFrame> {
|
||||
public:
|
||||
explicit SubtitleDecoder(DecoderStatus* status);
|
||||
|
||||
~SubtitleDecoder() override;
|
||||
virtual ~SubtitleDecoder();
|
||||
|
||||
void decodePacket(AVPacket* packet) override;
|
||||
virtual void decodePacket(AVPacket* packet) SCP_OVERRIDE;
|
||||
|
||||
void finishDecoding() override;
|
||||
virtual void finishDecoding() SCP_OVERRIDE;
|
||||
void pushSubtitleFrame(AVPacket* subtitle, AVSubtitle* pSubtitle);
|
||||
void flushBuffers() override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -3,9 +3,11 @@
|
||||
#include "tracing/tracing.h"
|
||||
|
||||
namespace {
|
||||
SwsContext* getSWSContext(int width, int height, AVPixelFormat fmt, AVPixelFormat destination_fmt)
|
||||
{
|
||||
return sws_getContext(width, height, fmt, width, height, destination_fmt, SWS_BILINEAR, nullptr, nullptr, nullptr);
|
||||
const AVPixelFormat DESTINATION_FORMAT = AV_PIX_FMT_YUV420P;
|
||||
|
||||
SwsContext* getSWSContext(int width, int height, AVPixelFormat fmt) {
|
||||
return sws_getContext(width, height, fmt, width, height, DESTINATION_FORMAT,
|
||||
SWS_BILINEAR, nullptr, nullptr, nullptr);
|
||||
}
|
||||
|
||||
double getFrameTime(int64_t pts, AVRational time_base) {
|
||||
@@ -16,53 +18,34 @@ double getFrameTime(int64_t pts, AVRational time_base) {
|
||||
namespace cutscene {
|
||||
namespace ffmpeg {
|
||||
class FFMPEGVideoFrame: public VideoFrame {
|
||||
size_t _width;
|
||||
size_t _height;
|
||||
AVFrame* _frame;
|
||||
public:
|
||||
FFMPEGVideoFrame() : frame(nullptr) {
|
||||
}
|
||||
|
||||
public:
|
||||
FFMPEGVideoFrame(size_t width, size_t height, AVFrame* frame) : _width(width), _height(height), _frame(frame) {}
|
||||
|
||||
~FFMPEGVideoFrame() override {
|
||||
if (_frame != nullptr) {
|
||||
av_freep(&_frame->data[0]);
|
||||
av_frame_free(&_frame);
|
||||
virtual ~FFMPEGVideoFrame() {
|
||||
if (frame != nullptr) {
|
||||
av_freep(&frame->data[0]);
|
||||
av_frame_free(&frame);
|
||||
}
|
||||
}
|
||||
size_t getPlaneNumber() override
|
||||
{
|
||||
switch (_frame->format) {
|
||||
case AV_PIX_FMT_YUV420P:
|
||||
// YUV data is planar
|
||||
return 3;
|
||||
default:
|
||||
// Everything else is packed
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
FrameSize getPlaneSize(size_t plane) override
|
||||
{
|
||||
switch (_frame->format) {
|
||||
case AV_PIX_FMT_YUV420P: {
|
||||
// YUV data is planar
|
||||
auto width = plane > 0 ? _width / 2 : _width;
|
||||
auto height = plane > 0 ? _height / 2 : _height;
|
||||
|
||||
return {width, height, (size_t)_frame->linesize[plane]};
|
||||
}
|
||||
default:
|
||||
// Everything else is packed
|
||||
return {_width, _height, (size_t)_frame->linesize[plane]};
|
||||
}
|
||||
virtual DataPointers getDataPointers() {
|
||||
DataPointers ptrs;
|
||||
ptrs.y = frame->data[0];
|
||||
ptrs.u = frame->data[1];
|
||||
ptrs.v = frame->data[2];
|
||||
|
||||
return ptrs;
|
||||
}
|
||||
void* getPlaneData(size_t plane) override { return _frame->data[plane]; }
|
||||
|
||||
AVFrame* frame;
|
||||
};
|
||||
|
||||
VideoDecoder::VideoDecoder(DecoderStatus* status, AVPixelFormat destination_fmt)
|
||||
: FFMPEGStreamDecoder(status), m_frameId(0), m_destinationFormat(destination_fmt)
|
||||
{
|
||||
VideoDecoder::VideoDecoder(DecoderStatus* status)
|
||||
: FFMPEGStreamDecoder(status),
|
||||
m_frameId(0) {
|
||||
m_swsCtx = getSWSContext(m_status->videoCodecPars.width, m_status->videoCodecPars.height,
|
||||
m_status->videoCodecPars.pixel_format, destination_fmt);
|
||||
m_status->videoCodecPars.pixel_format);
|
||||
}
|
||||
|
||||
VideoDecoder::~VideoDecoder() {
|
||||
@@ -70,32 +53,53 @@ VideoDecoder::~VideoDecoder() {
|
||||
}
|
||||
|
||||
void VideoDecoder::convertAndPushPicture(const AVFrame* frame) {
|
||||
// Allocate a picture to hold the destination data
|
||||
// Allocate a picture to hold the YUV data
|
||||
AVFrame* yuvFrame = av_frame_alloc();
|
||||
av_frame_copy(yuvFrame, frame);
|
||||
yuvFrame->format = m_destinationFormat;
|
||||
yuvFrame->format = DESTINATION_FORMAT;
|
||||
|
||||
av_image_alloc(yuvFrame->data, yuvFrame->linesize, m_status->videoCodecPars.width, m_status->videoCodecPars.height,
|
||||
m_destinationFormat, 1);
|
||||
av_image_alloc(yuvFrame->data,
|
||||
yuvFrame->linesize,
|
||||
m_status->videoCodecPars.width,
|
||||
m_status->videoCodecPars.height,
|
||||
DESTINATION_FORMAT,
|
||||
1);
|
||||
|
||||
if (m_status->videoCodecPars.pixel_format == m_destinationFormat) {
|
||||
av_image_copy(yuvFrame->data, yuvFrame->linesize, (const uint8_t**)(frame->data), frame->linesize,
|
||||
m_destinationFormat, m_status->videoCodecPars.width, m_status->videoCodecPars.height);
|
||||
std::unique_ptr<FFMPEGVideoFrame> videoFramePtr(new FFMPEGVideoFrame());
|
||||
|
||||
if (m_status->videoCodecPars.pixel_format == DESTINATION_FORMAT) {
|
||||
av_image_copy(yuvFrame->data,
|
||||
yuvFrame->linesize,
|
||||
(const uint8_t**) (frame->data),
|
||||
frame->linesize,
|
||||
DESTINATION_FORMAT,
|
||||
m_status->videoCodecPars.width,
|
||||
m_status->videoCodecPars.height);
|
||||
} else {
|
||||
// Convert frame to destination format
|
||||
sws_scale(m_swsCtx, (uint8_t const* const*)frame->data, frame->linesize, 0, m_status->videoCodecPars.height,
|
||||
yuvFrame->data, yuvFrame->linesize);
|
||||
// Convert frame to YUV
|
||||
sws_scale(
|
||||
m_swsCtx,
|
||||
(uint8_t const* const*) frame->data,
|
||||
frame->linesize,
|
||||
0,
|
||||
m_status->videoCodecPars.height,
|
||||
yuvFrame->data,
|
||||
yuvFrame->linesize
|
||||
);
|
||||
}
|
||||
|
||||
std::unique_ptr<FFMPEGVideoFrame> videoFramePtr(
|
||||
new FFMPEGVideoFrame(static_cast<size_t>(m_status->videoCodecPars.width),
|
||||
static_cast<size_t>(m_status->videoCodecPars.height), yuvFrame));
|
||||
videoFramePtr->id = ++m_frameId;
|
||||
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(58, 3, 102)
|
||||
videoFramePtr->frameTime = getFrameTime(frame->best_effort_timestamp, m_status->videoStream->time_base);
|
||||
#else
|
||||
videoFramePtr->frameTime = getFrameTime(av_frame_get_best_effort_timestamp(frame), m_status->videoStream->time_base);
|
||||
#endif
|
||||
videoFramePtr->frame = yuvFrame;
|
||||
|
||||
videoFramePtr->ySize.height = static_cast<size_t>(m_status->videoCodecPars.height);
|
||||
videoFramePtr->ySize.width = static_cast<size_t>(m_status->videoCodecPars.width);
|
||||
videoFramePtr->ySize.stride = static_cast<size_t>(yuvFrame->linesize[0]);
|
||||
|
||||
// 420P means that the UV channels have half the width and height
|
||||
videoFramePtr->uvSize.height = static_cast<size_t>(m_status->videoCodecPars.height / 2);
|
||||
videoFramePtr->uvSize.width = static_cast<size_t>(m_status->videoCodecPars.width / 2);
|
||||
videoFramePtr->uvSize.stride = static_cast<size_t>(yuvFrame->linesize[1]);
|
||||
|
||||
pushFrame(VideoFramePtr(videoFramePtr.release()));
|
||||
}
|
||||
@@ -158,8 +162,5 @@ void VideoDecoder::finishDecoding() {
|
||||
}
|
||||
#endif
|
||||
}
|
||||
void VideoDecoder::flushBuffers() {
|
||||
avcodec_flush_buffers(m_status->videoCodecCtx);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,20 +9,17 @@ class VideoDecoder: public FFMPEGStreamDecoder<VideoFrame> {
|
||||
private:
|
||||
int m_frameId;
|
||||
SwsContext* m_swsCtx;
|
||||
AVPixelFormat m_destinationFormat;
|
||||
|
||||
void convertAndPushPicture(const AVFrame* frame);
|
||||
|
||||
public:
|
||||
explicit VideoDecoder(DecoderStatus* status, AVPixelFormat destination_fmt);
|
||||
explicit VideoDecoder(DecoderStatus* status);
|
||||
|
||||
~VideoDecoder() override;
|
||||
virtual ~VideoDecoder();
|
||||
|
||||
void decodePacket(AVPacket* packet) override;
|
||||
virtual void decodePacket(AVPacket* packet) SCP_OVERRIDE;
|
||||
|
||||
void finishDecoding() override;
|
||||
|
||||
void flushBuffers() override;
|
||||
virtual void finishDecoding() SCP_OVERRIDE;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -33,8 +33,6 @@ struct DecoderStatus {
|
||||
AVCodec* audioCodec = nullptr;
|
||||
AVCodecContext* audioCodecCtx = nullptr;
|
||||
|
||||
// Subtitles are a bit different since they max come from a different file
|
||||
bool externalSubtitles = false;
|
||||
int subtitleStreamIndex = -1;
|
||||
AVStream* subtitleStream = nullptr;
|
||||
CodecContextParameters subtitleCodecPars;
|
||||
@@ -74,8 +72,6 @@ class FFMPEGStreamDecoder {
|
||||
|
||||
virtual void finishDecoding() = 0;
|
||||
|
||||
virtual void flushBuffers() = 0;
|
||||
|
||||
virtual FramePtr<frame_type> getFrame();
|
||||
};
|
||||
|
||||
|
||||
+16
-25
@@ -44,11 +44,21 @@ struct PlaybackState {
|
||||
int subtitle_font = -1;
|
||||
};
|
||||
|
||||
void processEvents()
|
||||
{
|
||||
void processEvents(PlaybackState* state) {
|
||||
io::mouse::CursorManager::get()->showCursor(false);
|
||||
|
||||
os_poll();
|
||||
|
||||
int k = key_inkey();
|
||||
switch (k) {
|
||||
case KEY_ESC:
|
||||
case KEY_ENTER:
|
||||
case KEY_SPACEBAR:
|
||||
state->playing = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
@@ -183,21 +193,6 @@ void movie_display_loop(Player* player, PlaybackState* state) {
|
||||
// We will sleep at most half the time a frame would be displayed
|
||||
auto sleepTime = static_cast<std::uint64_t>((1. / (4. * player->getMovieProperties().fps)) * 1000.);
|
||||
|
||||
auto listener = [state](const SDL_Event& event) {
|
||||
switch (event.key.keysym.sym) {
|
||||
case SDLK_ESCAPE:
|
||||
case SDLK_KP_ENTER:
|
||||
case SDLK_RETURN:
|
||||
case SDLK_SPACE:
|
||||
state->playing = false;
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
};
|
||||
// Use a dedicated listener here since we want to listen for the KEYUP event
|
||||
auto key_handle = os::events::addEventListener(SDL_KEYUP, os::events::DEFAULT_LISTENER_WEIGHT - 10, listener);
|
||||
|
||||
auto lastDisplayTimestamp = timer_get_microseconds();
|
||||
while (state->playing) {
|
||||
TRACE_SCOPE(tracing::CutsceneStep);
|
||||
@@ -207,14 +202,12 @@ void movie_display_loop(Player* player, PlaybackState* state) {
|
||||
auto passed = timestamp - lastDisplayTimestamp;
|
||||
lastDisplayTimestamp = timestamp;
|
||||
|
||||
if (player->isPlaybackReady()) {
|
||||
// Play as long as the player reports that there is more to display
|
||||
state->playing = player->update(passed);
|
||||
// Play as long as the player reports that there is more to display
|
||||
state->playing = player->update(passed);
|
||||
|
||||
displayVideo(player, state);
|
||||
}
|
||||
displayVideo(player, state);
|
||||
|
||||
processEvents();
|
||||
processEvents(state);
|
||||
|
||||
if (passed < sleepTime) {
|
||||
auto sleep = sleepTime - passed;
|
||||
@@ -222,8 +215,6 @@ void movie_display_loop(Player* player, PlaybackState* state) {
|
||||
os_sleep(static_cast<uint>(sleep));
|
||||
}
|
||||
}
|
||||
|
||||
os::events::removeEventListener(key_handle);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+22
-36
@@ -17,7 +17,6 @@
|
||||
#include "io/key.h"
|
||||
#include "io/timer.h"
|
||||
|
||||
#include "player.h"
|
||||
#include "parse/parselo.h"
|
||||
|
||||
using namespace cutscene::player;
|
||||
@@ -27,10 +26,10 @@ using namespace cutscene;
|
||||
|
||||
const int MAX_AUDIO_BUFFERS = 15;
|
||||
|
||||
std::unique_ptr<Decoder> findDecoder(const SCP_string& name, const PlaybackProperties& properties) {
|
||||
std::unique_ptr<Decoder> findDecoder(const SCP_string& name) {
|
||||
{
|
||||
std::unique_ptr<Decoder> ffmpeg(new ::cutscene::ffmpeg::FFMPEGDecoder());
|
||||
if (ffmpeg->initialize(name, properties)) {
|
||||
std::unique_ptr<Decoder> ffmpeg(new ffmpeg::FFMPEGDecoder());
|
||||
if (ffmpeg->initialize(name)) {
|
||||
return ffmpeg;
|
||||
}
|
||||
}
|
||||
@@ -50,8 +49,7 @@ void videoPlaybackInit(PlayerState* state) {
|
||||
|
||||
Assert(state != NULL);
|
||||
|
||||
if (gr_screen.mode != GR_STUB) {
|
||||
// The video presenter is independent of the underlying graphics API
|
||||
if (gr_screen.mode == GR_OPENGL) {
|
||||
state->videoPresenter.reset(new VideoPresenter(state->props));
|
||||
}
|
||||
|
||||
@@ -123,15 +121,6 @@ void processVideoData(PlayerState* state) {
|
||||
}
|
||||
|
||||
while (currentTime >= state->nextFrame->frameTime) {
|
||||
if (state->currentFrame) {
|
||||
if (state->nextFrame->frameTime < state->currentFrame->frameTime) {
|
||||
// We reached the end of the movie and just looped to the beginning. Now we need to reset the playback
|
||||
// time
|
||||
state->playback_time = 0;
|
||||
currentTime = playbackGetTime(state);
|
||||
}
|
||||
}
|
||||
|
||||
// Move the next frame to the current frame slot
|
||||
state->currentFrame = std::move(state->nextFrame);
|
||||
|
||||
@@ -283,22 +272,8 @@ bool shouldBeginPlayback(Decoder* decoder) {
|
||||
}
|
||||
|
||||
namespace cutscene {
|
||||
Player::Player(std::unique_ptr<Decoder>&& decoder, const PlaybackProperties& properties)
|
||||
: m_decoder(std::move(decoder))
|
||||
{
|
||||
Assertion(!m_state.videoInited,
|
||||
"Internal State has been initialized before! Create a new player for replaying a movie.");
|
||||
|
||||
m_decoderThread.reset(new std::thread(std::bind(&Player::decoderThread, this)));
|
||||
|
||||
m_state.props = m_decoder->getProperties();
|
||||
m_state.decoder = m_decoder.get();
|
||||
|
||||
videoPlaybackInit(&m_state);
|
||||
|
||||
if (properties.with_audio) {
|
||||
audioPlaybackInit(&m_state);
|
||||
}
|
||||
Player::Player(std::unique_ptr<Decoder>&& decoder) : m_decoder(std::move(decoder)) {
|
||||
initPlayback();
|
||||
}
|
||||
|
||||
Player::~Player() {
|
||||
@@ -340,6 +315,19 @@ bool Player::processDecoderData() {
|
||||
|
||||
return decoding || pendingAudio || pendingVideo;
|
||||
}
|
||||
|
||||
void Player::initPlayback() {
|
||||
Assertion(!m_state.videoInited, "Internal State has been initialized before! Create a new player for replaying a movie.");
|
||||
|
||||
m_decoderThread.reset(new std::thread(std::bind(&Player::decoderThread, this)));
|
||||
|
||||
m_state.props = m_decoder->getProperties();
|
||||
m_state.decoder = m_decoder.get();
|
||||
|
||||
videoPlaybackInit(&m_state);
|
||||
|
||||
audioPlaybackInit(&m_state);
|
||||
}
|
||||
bool Player::update(uint64_t diff_time_micro) {
|
||||
if (m_state.playbackHasBegun) {
|
||||
m_state.playback_time += diff_time_micro;
|
||||
@@ -366,16 +354,15 @@ void Player::decoderThread() {
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<Player> Player::newPlayer(const SCP_string& name, const PlaybackProperties& properties)
|
||||
{
|
||||
std::unique_ptr<Player> Player::newPlayer(const SCP_string& name) {
|
||||
mprintf(("Creating player for movie '%s'.\n", name.c_str()));
|
||||
|
||||
auto decoder = findDecoder(name, properties);
|
||||
auto decoder = findDecoder(name);
|
||||
|
||||
if (decoder == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
return std::unique_ptr<Player>(new Player(std::move(decoder), properties));
|
||||
return std::unique_ptr<Player>(new Player(std::move(decoder)));
|
||||
}
|
||||
const PlayerState& Player::getInternalState() const {
|
||||
return m_state;
|
||||
@@ -399,5 +386,4 @@ SCP_string Player::getCurrentSubtitle() {
|
||||
return m_state.currentSubtitle->text;
|
||||
}
|
||||
}
|
||||
bool Player::isPlaybackReady() const { return m_state.playbackHasBegun || shouldBeginPlayback(m_decoder.get()); }
|
||||
}
|
||||
+13
-21
@@ -52,7 +52,7 @@ struct PlayerState {
|
||||
* @brief A movie player
|
||||
*/
|
||||
class Player {
|
||||
private:
|
||||
private:
|
||||
std::unique_ptr<Decoder> m_decoder;
|
||||
|
||||
std::unique_ptr<std::thread> m_decoderThread;
|
||||
@@ -61,11 +61,14 @@ class Player {
|
||||
|
||||
bool processDecoderData();
|
||||
|
||||
private:
|
||||
private:
|
||||
void decoderThread();
|
||||
|
||||
Player(std::unique_ptr<Decoder>&& decoder, const PlaybackProperties& properties);
|
||||
public:
|
||||
void initPlayback();
|
||||
|
||||
public:
|
||||
explicit Player(std::unique_ptr<Decoder>&& decoder);
|
||||
|
||||
~Player();
|
||||
|
||||
Player(const Player&) = delete;
|
||||
@@ -94,12 +97,6 @@ class Player {
|
||||
*/
|
||||
const MovieProperties& getMovieProperties() const;
|
||||
|
||||
/**
|
||||
* @brief Determines if this player can start displaying video.
|
||||
* @return true if the cutscene is ready, false otherwise
|
||||
*/
|
||||
bool isPlaybackReady() const;
|
||||
|
||||
/**
|
||||
* @brief Draws the current movie frame at the specified coordinates.
|
||||
*
|
||||
@@ -112,10 +109,6 @@ class Player {
|
||||
*/
|
||||
void draw(float x1, float y1, float x2, float y2);
|
||||
|
||||
/**
|
||||
* @brief Gets the subtitle text that should be displayed now
|
||||
* @return The text, encoded in UTF-8
|
||||
*/
|
||||
SCP_string getCurrentSubtitle();
|
||||
|
||||
/**
|
||||
@@ -126,12 +119,11 @@ class Player {
|
||||
void stopPlayback();
|
||||
|
||||
/**
|
||||
* @brief Creates a player
|
||||
* The player is configured to play the movie with the specified name
|
||||
* @param name The movie to play
|
||||
* @param properties A structure describing how the movie will be used
|
||||
* @return @c nullptr if the specified movie could not be opened, a valid Player pointer otherwise
|
||||
*/
|
||||
static std::unique_ptr<Player> newPlayer(const SCP_string& name, const PlaybackProperties& properties = PlaybackProperties());
|
||||
* @brief Creates a player
|
||||
* The player is configured to play the movie with the specified name
|
||||
* @param name The movie to play
|
||||
* @return @c nullptr if the specified movie could not be opened, a valid Player pointer otherwise
|
||||
*/
|
||||
static std::unique_ptr<Player> newPlayer(const SCP_string& name);
|
||||
};
|
||||
}
|
||||
+29
-12
@@ -31,6 +31,7 @@
|
||||
#include "weapon/weapon.h"
|
||||
#include "tracing/Monitor.h"
|
||||
|
||||
#define MAX_LIFE 10.0f
|
||||
#define MIN_RADIUS_FOR_PERSISTANT_DEBRIS 50 // ship radius at which debris from it becomes persistant
|
||||
#define DEBRIS_SOUND_DELAY 2000 // time to start debris sound after created
|
||||
#define MAX_HULL_PIECES MAX_DEBRIS_PIECES // limit the number of hull debris chunks that can exist.
|
||||
@@ -51,6 +52,10 @@ int Debris_num_submodels = 0;
|
||||
#define DEBRIS_DISTANCE_CHECK_TIME (10*1000) // Check every 10 seconds.
|
||||
#define DEBRIS_INDEX(dp) (int)(dp-Debris)
|
||||
|
||||
#define MAX_SPEED_SMALL_DEBRIS 200 // maximum velocity of small debris piece
|
||||
#define MAX_SPEED_BIG_DEBRIS 150 // maximum velocity of big debris piece
|
||||
#define MAX_SPEED_CAPITAL_DEBRIS 100 // maximum velocity of capital debris piece
|
||||
|
||||
/**
|
||||
* Start the sequence of a piece of debris writhing in unholy agony!!!
|
||||
*/
|
||||
@@ -69,7 +74,7 @@ static void debris_start_death_roll(object *debris_obj, debris *debris_p)
|
||||
|
||||
// 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 ) {
|
||||
snd_play_3d( gamesnd_get_game_sound(gamesnd_id(GameSounds::MISSILE_IMPACT1)), &debris_obj->pos, &View_position, debris_obj->radius );
|
||||
snd_play_3d( gamesnd_get_game_sound(SND_MISSILE_IMPACT1), &debris_obj->pos, &View_position, debris_obj->radius );
|
||||
|
||||
}
|
||||
}
|
||||
@@ -233,7 +238,7 @@ void debris_process_post(object * obj, float frame_time)
|
||||
radar_plot_object( obj );
|
||||
|
||||
if ( timestamp_elapsed(db->sound_delay) ) {
|
||||
obj_snd_assign(objnum, GameSounds::DEBRIS, &vmd_zero_vector, 0);
|
||||
obj_snd_assign(objnum, SND_DEBRIS, &vmd_zero_vector, 0);
|
||||
db->sound_delay = 0;
|
||||
}
|
||||
} else {
|
||||
@@ -265,8 +270,13 @@ void debris_process_post(object * obj, float frame_time)
|
||||
|
||||
vec3d v1, v2, v3, v4;
|
||||
|
||||
submodel_get_two_random_points_better(db->model_num, db->submodel_num, &v1, &v2);
|
||||
submodel_get_two_random_points_better(db->model_num, db->submodel_num, &v3, &v4);
|
||||
if ( Cmdline_old_collision_sys ) {
|
||||
submodel_get_two_random_points( db->model_num, db->submodel_num, &v1, &v2 );
|
||||
submodel_get_two_random_points( db->model_num, db->submodel_num, &v3, &v4 );
|
||||
} else {
|
||||
submodel_get_two_random_points_better( db->model_num, db->submodel_num, &v1, &v2 );
|
||||
submodel_get_two_random_points_better( db->model_num, db->submodel_num, &v3, &v4 );
|
||||
}
|
||||
|
||||
n = 0;
|
||||
|
||||
@@ -314,19 +324,19 @@ void debris_process_post(object * obj, float frame_time)
|
||||
//Play a sound effect
|
||||
if ( lifetime > 750 ) {
|
||||
// 1.00 second effect
|
||||
snd_play_3d( gamesnd_get_game_sound(GameSounds::DEBRIS_ARC_05), &snd_pos, &View_position, obj->radius );
|
||||
snd_play_3d( gamesnd_get_game_sound(SND_DEBRIS_ARC_05), &snd_pos, &View_position, obj->radius );
|
||||
} else if ( lifetime > 500 ) {
|
||||
// 0.75 second effect
|
||||
snd_play_3d( gamesnd_get_game_sound(GameSounds::DEBRIS_ARC_04), &snd_pos, &View_position, obj->radius );
|
||||
snd_play_3d( gamesnd_get_game_sound(SND_DEBRIS_ARC_04), &snd_pos, &View_position, obj->radius );
|
||||
} else if ( lifetime > 250 ) {
|
||||
// 0.50 second effect
|
||||
snd_play_3d( gamesnd_get_game_sound(GameSounds::DEBRIS_ARC_03), &snd_pos, &View_position, obj->radius );
|
||||
snd_play_3d( gamesnd_get_game_sound(SND_DEBRIS_ARC_03), &snd_pos, &View_position, obj->radius );
|
||||
} else if ( lifetime > 100 ) {
|
||||
// 0.25 second effect
|
||||
snd_play_3d( gamesnd_get_game_sound(GameSounds::DEBRIS_ARC_02), &snd_pos, &View_position, obj->radius );
|
||||
snd_play_3d( gamesnd_get_game_sound(SND_DEBRIS_ARC_02), &snd_pos, &View_position, obj->radius );
|
||||
} else {
|
||||
// 0.10 second effect
|
||||
snd_play_3d( gamesnd_get_game_sound(GameSounds::DEBRIS_ARC_01), &snd_pos, &View_position, obj->radius );
|
||||
snd_play_3d( gamesnd_get_game_sound(SND_DEBRIS_ARC_01), &snd_pos, &View_position, obj->radius );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -342,8 +352,12 @@ void debris_process_post(object * obj, float frame_time)
|
||||
if ( mr < RAND_MAX/5 ) {
|
||||
vec3d v1, v2;
|
||||
|
||||
submodel_get_two_random_points_better(db->model_num, db->submodel_num, &v1, &v2);
|
||||
|
||||
if ( Cmdline_old_collision_sys ) {
|
||||
submodel_get_two_random_points( db->model_num, db->submodel_num, &v1, &v2 );
|
||||
} else {
|
||||
submodel_get_two_random_points_better( db->model_num, db->submodel_num, &v1, &v2 );
|
||||
}
|
||||
|
||||
db->arc_pts[i][mr % 2] = v1;
|
||||
}
|
||||
}
|
||||
@@ -491,6 +505,7 @@ object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d
|
||||
db->flags |= DEBRIS_USED;
|
||||
db->is_hull = hull_flag;
|
||||
db->source_objnum = parent_objnum;
|
||||
db->source_sig = source_obj->signature;
|
||||
db->damage_type_idx = shipp->debris_damage_type_idx;
|
||||
db->ship_info_index = shipp->ship_info_index;
|
||||
db->team = shipp->team;
|
||||
@@ -678,7 +693,7 @@ object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d
|
||||
* Alas, poor debris_obj got whacked. Fortunately, we know who did it, where and how hard, so we
|
||||
* can do something about it.
|
||||
*/
|
||||
void debris_hit(object *debris_obj, object * /*other_obj*/, vec3d *hitpos, float damage)
|
||||
void debris_hit(object *debris_obj, object *other_obj, vec3d *hitpos, float damage)
|
||||
{
|
||||
debris *debris_p = &Debris[debris_obj->instance];
|
||||
|
||||
@@ -974,6 +989,8 @@ int debris_check_collision(object *pdebris, object *other_obj, vec3d *hitpos, co
|
||||
|
||||
// SET PHYSICS PARAMETERS
|
||||
// already have (hitpos - heavy) and light_cm_pos
|
||||
// get heavy cm pos - already have light_cm_pos
|
||||
debris_hit_info->heavy_collision_cm_pos = zero;
|
||||
|
||||
// get r_heavy and r_light
|
||||
debris_hit_info->r_heavy = debris_hit_info->hit_pos;
|
||||
|
||||
@@ -24,6 +24,7 @@ typedef struct debris {
|
||||
debris *next, *prev; // used for a linked list of the hull debris chunks
|
||||
int flags; // See DEBRIS_??? defines
|
||||
int source_objnum; // What object this came from
|
||||
int source_sig; // Signature of the source object
|
||||
int damage_type_idx; // Damage type of this debris
|
||||
int ship_info_index; // Ship info index of the ship type debris came from
|
||||
int team; // Team of the ship where the debris came from
|
||||
|
||||
@@ -70,6 +70,7 @@ int dc_font = font::FONT1;
|
||||
|
||||
SCP_string dc_title;
|
||||
|
||||
#define SCROLL_X_MAX (DBCOLS - DCOLS)
|
||||
#define SCROLL_Y_MAX (DBROWS - DROWS)
|
||||
|
||||
// Commands and History
|
||||
@@ -116,6 +117,11 @@ void dc_draw_window(bool show_prompt);
|
||||
*/
|
||||
void dc_putc(char c);
|
||||
|
||||
/**
|
||||
* @brief Predicate function used to sort debug_commands
|
||||
*/
|
||||
bool dcmd_less(debug_command *first, debug_command *second);
|
||||
|
||||
// ============================== IMPLEMENTATIONS =============================
|
||||
void dc_do_command(SCP_string *cmd_str)
|
||||
{
|
||||
@@ -156,7 +162,7 @@ void dc_do_command(SCP_string *cmd_str)
|
||||
try {
|
||||
dc_commands[i]->func(); // Run the command!
|
||||
|
||||
} catch (const errParseString& err) {
|
||||
} catch (errParseString err) {
|
||||
dc_printf("Require string(s) not found: \n");
|
||||
for (uint j = 0; j < err.expected_tokens.size(); ++j) {
|
||||
dc_printf("%i: %s\n", j, err.expected_tokens[j].c_str());
|
||||
@@ -164,7 +170,7 @@ void dc_do_command(SCP_string *cmd_str)
|
||||
|
||||
dc_printf("Found '%s' instead\n", err.found_token.c_str());
|
||||
|
||||
} catch (const errParse& err) {
|
||||
} catch (errParse err) {
|
||||
dc_printf("Invalid argument. Expected %s, found '%s'\n", token_str[err.expected_type], err.found_token.c_str());
|
||||
|
||||
}
|
||||
@@ -488,6 +494,11 @@ void dc_putc(char c)
|
||||
line_str->push_back(c);
|
||||
}
|
||||
|
||||
bool dcmd_less(debug_command *first, debug_command *second)
|
||||
{
|
||||
return (strcmp(first->name, second->name) < 0);
|
||||
}
|
||||
|
||||
void debug_console(void (*_func)(void))
|
||||
{
|
||||
int done = 0;
|
||||
|
||||
@@ -28,6 +28,10 @@ debug_command *dc_commands[DC_MAX_COMMANDS];
|
||||
int dc_commands_size = 0;
|
||||
|
||||
// ========================= LOCALS ==========================
|
||||
// dcf_shell commands
|
||||
void dc_shell_font( void );
|
||||
void dc_shell_resize( void );
|
||||
void dc_shell_resize_buf( void );
|
||||
|
||||
// =================== class debug_command ===================
|
||||
debug_command::debug_command()
|
||||
@@ -151,4 +155,6 @@ DCF(help, "Displays the help list." )
|
||||
|
||||
dc_printf(" %s - %s\n", dc_commands[i]->name, dc_commands[i]->help);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
debug_command dc_man("man", "Also displays the help list", dcf_help);
|
||||
@@ -20,7 +20,7 @@
|
||||
#include <cmath>
|
||||
#include <cstdarg>
|
||||
#include <cstring>
|
||||
#include <climits>
|
||||
#include <limits.h>
|
||||
|
||||
|
||||
// ========================= LOCALS =========================
|
||||
|
||||
@@ -1,549 +0,0 @@
|
||||
#include <nebula/neb.h>
|
||||
#include <utility>
|
||||
#include "decals/decals.h"
|
||||
|
||||
#include "graphics/2d.h"
|
||||
#include "graphics/decal_draw_list.h"
|
||||
#include "graphics/util/uniform_structs.h"
|
||||
#include "parse/parselo.h"
|
||||
#include "tracing/tracing.h"
|
||||
#include "ship/ship.h"
|
||||
|
||||
namespace {
|
||||
|
||||
class DecalDefinition {
|
||||
SCP_string _name;
|
||||
|
||||
SCP_string _diffuseFilename;
|
||||
bool _loopDiffuse = true;
|
||||
|
||||
SCP_string _glowFilename;
|
||||
bool _loopGlow = true;
|
||||
|
||||
SCP_string _normalMapFilename;
|
||||
bool _loopNormal = true;
|
||||
|
||||
int _diffuseBitmap = -1;
|
||||
int _glowBitmap = -1;
|
||||
int _normalBitmap = -1;
|
||||
|
||||
public:
|
||||
explicit DecalDefinition(SCP_string name) : _name(std::move(name)) {
|
||||
}
|
||||
|
||||
~DecalDefinition() {
|
||||
if (_diffuseBitmap >= 0) {
|
||||
bm_release(_diffuseBitmap);
|
||||
}
|
||||
if (_glowBitmap >= 0) {
|
||||
bm_release(_glowBitmap);
|
||||
}
|
||||
if (_normalBitmap >= 0) {
|
||||
bm_release(_normalBitmap);
|
||||
}
|
||||
}
|
||||
|
||||
// Disallow copying
|
||||
DecalDefinition(const DecalDefinition&) = delete;
|
||||
DecalDefinition& operator=(const DecalDefinition&) = delete;
|
||||
|
||||
// Move constructor and operator
|
||||
DecalDefinition(DecalDefinition&& other) SCP_NOEXCEPT {
|
||||
*this = std::move(other); // Use operator implementation
|
||||
}
|
||||
DecalDefinition& operator=(DecalDefinition&& other) SCP_NOEXCEPT {
|
||||
std::swap(_name, other._name);
|
||||
|
||||
std::swap(_diffuseFilename, other._diffuseFilename);
|
||||
std::swap(_glowFilename, other._glowFilename);
|
||||
std::swap(_normalMapFilename, other._normalMapFilename);
|
||||
|
||||
std::swap(_diffuseBitmap, other._diffuseBitmap);
|
||||
std::swap(_glowBitmap, other._glowBitmap);
|
||||
std::swap(_normalBitmap, other._normalBitmap);
|
||||
|
||||
std::swap(_loopDiffuse, other._loopDiffuse);
|
||||
std::swap(_loopGlow, other._loopGlow);
|
||||
std::swap(_loopNormal, other._loopNormal);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void parse() {
|
||||
if (optional_string("+Diffuse:")) {
|
||||
stuff_string(_diffuseFilename, F_FILESPEC);
|
||||
|
||||
if (!bm_validate_filename(_diffuseFilename, true, true)) {
|
||||
error_display(0, "Animation '%s' is not valid!", _diffuseFilename.c_str());
|
||||
_diffuseFilename = "";
|
||||
}
|
||||
|
||||
if (optional_string("+Loop:")) {
|
||||
stuff_boolean(&_loopDiffuse);
|
||||
}
|
||||
}
|
||||
if (optional_string("+Glow:")) {
|
||||
stuff_string(_glowFilename, F_FILESPEC);
|
||||
|
||||
if (!bm_validate_filename(_glowFilename, true, true)) {
|
||||
error_display(0, "Animation '%s' is not valid!", _glowFilename.c_str());
|
||||
_glowFilename = "";
|
||||
}
|
||||
|
||||
if (optional_string("+Loop:")) {
|
||||
stuff_boolean(&_loopGlow);
|
||||
}
|
||||
}
|
||||
if (optional_string("+Normal:")) {
|
||||
stuff_string(_normalMapFilename, F_FILESPEC);
|
||||
|
||||
if (!bm_validate_filename(_normalMapFilename, true, true)) {
|
||||
error_display(0, "Animation '%s' is not valid!", _normalMapFilename.c_str());
|
||||
_normalMapFilename = "";
|
||||
}
|
||||
|
||||
if (optional_string("+Loop:")) {
|
||||
stuff_boolean(&_loopNormal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void loadBitmaps() {
|
||||
if (_diffuseBitmap == -1 && VALID_FNAME(_diffuseFilename)) {
|
||||
_diffuseBitmap = bm_load_either(_diffuseFilename.c_str());
|
||||
if (_diffuseBitmap == -1) {
|
||||
Warning(LOCATION,
|
||||
"Bitmap '%s' failed to load for decal definition %s!",
|
||||
_diffuseFilename.c_str(),
|
||||
_name.c_str());
|
||||
}
|
||||
}
|
||||
if (_glowBitmap == -1 && VALID_FNAME(_glowFilename)) {
|
||||
_glowBitmap = bm_load_either(_glowFilename.c_str());
|
||||
if (_glowBitmap == -1) {
|
||||
Warning(LOCATION,
|
||||
"Bitmap '%s' failed to load for decal definition %s!",
|
||||
_glowFilename.c_str(),
|
||||
_name.c_str());
|
||||
}
|
||||
}
|
||||
if (_normalBitmap == -1 && VALID_FNAME(_normalMapFilename)) {
|
||||
_normalBitmap = bm_load_either(_normalMapFilename.c_str());
|
||||
if (_normalBitmap == -1) {
|
||||
Warning(LOCATION,
|
||||
"Bitmap '%s' failed to load for decal definition %s!",
|
||||
_normalMapFilename.c_str(),
|
||||
_name.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pageIn() {
|
||||
if (_diffuseBitmap >= 0) {
|
||||
bm_page_in_texture(_diffuseBitmap);
|
||||
}
|
||||
if (_glowBitmap >= 0) {
|
||||
bm_page_in_texture(_glowBitmap);
|
||||
}
|
||||
if (_normalBitmap >= 0) {
|
||||
bm_page_in_texture(_normalBitmap);
|
||||
}
|
||||
}
|
||||
|
||||
bool bitmapsLoaded() {
|
||||
// Since both bitmap types are optional we need to check if either is loaded to determine if any bitmap is loaded
|
||||
return _diffuseBitmap >= 0 || _glowBitmap >= 0 || _normalBitmap >= 0;
|
||||
}
|
||||
|
||||
const SCP_string& getName() const {
|
||||
return _name;
|
||||
}
|
||||
int getDiffuseBitmap() const {
|
||||
return _diffuseBitmap;
|
||||
}
|
||||
int getGlowBitmap() const {
|
||||
return _glowBitmap;
|
||||
}
|
||||
int getNormalBitmap() const {
|
||||
return _normalBitmap;
|
||||
}
|
||||
bool isDiffuseLooping() const {
|
||||
return _loopDiffuse;
|
||||
}
|
||||
bool isGlowLooping() const {
|
||||
return _loopGlow;
|
||||
}
|
||||
bool isNormalLooping() const {
|
||||
return _loopNormal;
|
||||
}
|
||||
};
|
||||
|
||||
SCP_vector<DecalDefinition> decalDefinitions;
|
||||
|
||||
// Variable to indicate if the system is able to work correctly on the current system
|
||||
bool decal_system_active = true;
|
||||
|
||||
void parse_decals_table(const char* filename) {
|
||||
try {
|
||||
read_file_text(filename, CF_TYPE_TABLES);
|
||||
reset_parse();
|
||||
|
||||
required_string("#Decals");
|
||||
|
||||
while (optional_string("$Decal:")) {
|
||||
SCP_string name;
|
||||
stuff_string(name, F_NAME);
|
||||
|
||||
DecalDefinition def(name);
|
||||
def.parse();
|
||||
|
||||
decalDefinitions.push_back(std::move(def));
|
||||
}
|
||||
|
||||
required_string("#End");
|
||||
} catch (const parse::ParseException& e) {
|
||||
mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", filename, e.what()));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!gr_is_capable(CAPABILITY_DEFERRED_LIGHTING)) {
|
||||
// we need deferred lighting
|
||||
decal_system_active = false;
|
||||
mprintf(("Note: Decal system has been disabled due to lack of deferred lighting.\n"));
|
||||
}
|
||||
if (!gr_is_capable(CAPABILITY_NORMAL_MAP)) {
|
||||
// We need normal mapping for the full feature range
|
||||
decal_system_active = false;
|
||||
mprintf(("Note: Decal system has been disabled due to lack of normal mapping.\n"));
|
||||
}
|
||||
if (!gr_is_capable(CAPABILITY_SEPARATE_BLEND_FUNCTIONS)) {
|
||||
// WWe need separate blending functions for different color buffers
|
||||
decal_system_active = false;
|
||||
mprintf(("Note: Decal system has been disabled due to lack of separate color buffer blend functions.\n"));
|
||||
}
|
||||
}
|
||||
|
||||
struct Decal {
|
||||
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() {
|
||||
vm_vec_make(&scale, 1.f, 1.f, 1.f);
|
||||
}
|
||||
|
||||
bool isValid() {
|
||||
if (!object.IsValid()) {
|
||||
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",
|
||||
OBJ_INDEX(object.objp), 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 < model_get(object_get_model(objp))->n_models,
|
||||
"Invalid submodel number detected!");
|
||||
auto smi = &model_instance->submodel[submodel];
|
||||
|
||||
if (smi->blown_off) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
SCP_vector<Decal> active_decals;
|
||||
|
||||
bool required_string_if_new(const char* token, bool new_entry) {
|
||||
if (!new_entry) {
|
||||
return optional_string(token) == 1;
|
||||
}
|
||||
|
||||
required_string(token);
|
||||
return true;
|
||||
}
|
||||
|
||||
float clamp(float x, float min, float max) {
|
||||
return std::min(std::max(x, min), max);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Produces a smoothstep value as specified by the GLSL specification
|
||||
* @param edge0
|
||||
* @param edge1
|
||||
* @param x
|
||||
* @return
|
||||
*/
|
||||
float smoothstep(float edge0, float edge1, float x) {
|
||||
auto t = clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
|
||||
return t * t * (3.0f - 2.0f * t);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace decals {
|
||||
|
||||
void initialize() {
|
||||
decalDefinitions.clear();
|
||||
graphics::decal_draw_list::globalInit();
|
||||
|
||||
parse_modular_table(NOX("*-dcl.tbm"), parse_decals_table);
|
||||
}
|
||||
void shutdown() {
|
||||
graphics::decal_draw_list::globalShutdown();
|
||||
|
||||
// Free allocated resources
|
||||
decalDefinitions.clear();
|
||||
}
|
||||
|
||||
int getDecalConfig(const SCP_string& name) {
|
||||
int index = 0;
|
||||
for (auto& def : decalDefinitions) {
|
||||
if (!stricmp(def.getName().c_str(), name.c_str())) {
|
||||
return index;
|
||||
}
|
||||
++index;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void parseDecalReference(creation_info& dest_info, bool is_new_entry) {
|
||||
SCP_string name;
|
||||
stuff_string(name, F_NAME);
|
||||
|
||||
auto decalRef = getDecalConfig(name);
|
||||
|
||||
if (decalRef < 0) {
|
||||
error_display(0, "Decal definition '%s' is unknown!", name.c_str());
|
||||
}
|
||||
dest_info.definition_handle = decalRef;
|
||||
|
||||
if (required_string_if_new("+Radius:", is_new_entry)) {
|
||||
stuff_float(&dest_info.radius);
|
||||
|
||||
if (dest_info.radius <= 0.0f) {
|
||||
error_display(0, "Invalid radius of %f! Must be a positive number.", dest_info.radius);
|
||||
dest_info.radius = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
if (required_string_if_new("+Lifetime:", is_new_entry)) {
|
||||
if (optional_string("Eternal")) {
|
||||
dest_info.lifetime = util::UniformFloatRange(-1.0f);
|
||||
} else {
|
||||
// Require at least a small lifetime so that the calculations don't have to deal with div-by-zero
|
||||
dest_info.lifetime = util::parseUniformRange(0.0001f);
|
||||
}
|
||||
}
|
||||
}
|
||||
void loadBitmaps(const creation_info& info) {
|
||||
if (!decal_system_active) {
|
||||
return;
|
||||
}
|
||||
// Silently ignore invalid definition handle since weapons use the default values if the decal option is not present
|
||||
if (info.definition_handle < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
Assertion(info.definition_handle >= 0 && info.definition_handle < (int) decalDefinitions.size(),
|
||||
"Invalid decal handle detected!");
|
||||
|
||||
auto& def = decalDefinitions[info.definition_handle];
|
||||
|
||||
def.loadBitmaps();
|
||||
}
|
||||
void pageInDecal(const creation_info& info) {
|
||||
if (!decal_system_active) {
|
||||
return;
|
||||
}
|
||||
// Silently ignore invalid definition handle since weapons use the default values if the decal option is not present
|
||||
if (info.definition_handle < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
Assertion(info.definition_handle >= 0 && info.definition_handle < (int) decalDefinitions.size(),
|
||||
"Invalid decal handle detected!");
|
||||
|
||||
decalDefinitions[info.definition_handle].pageIn();
|
||||
}
|
||||
|
||||
void initializeMission() {
|
||||
active_decals.clear();
|
||||
}
|
||||
|
||||
matrix4 getDecalTransform(Decal& decal) {
|
||||
Assertion(decal.object.objp->type == OBJ_SHIP, "Only ships are currently supported for decals!");
|
||||
|
||||
auto objp = decal.object.objp;
|
||||
auto ship = &Ships[objp->instance];
|
||||
|
||||
vec3d worldPos;
|
||||
model_instance_find_world_point(&worldPos,
|
||||
&decal.position,
|
||||
ship->model_instance_num,
|
||||
decal.submodel,
|
||||
&objp->orient,
|
||||
&objp->pos);
|
||||
|
||||
vec3d worldDir;
|
||||
model_instance_find_world_dir(&worldDir,
|
||||
&decal.orientation.vec.fvec,
|
||||
ship->model_instance_num,
|
||||
decal.submodel,
|
||||
&objp->orient);
|
||||
|
||||
vec3d worldUp;
|
||||
model_instance_find_world_dir(&worldUp,
|
||||
&decal.orientation.vec.fvec,
|
||||
ship->model_instance_num,
|
||||
decal.submodel,
|
||||
&objp->orient);
|
||||
|
||||
matrix worldOrient;
|
||||
vm_vector_2_matrix(&worldOrient, &worldDir, &worldUp);
|
||||
|
||||
// Apply scaling
|
||||
worldOrient.a2d[0][0] *= decal.scale.xyz.x;
|
||||
worldOrient.a2d[0][1] *= decal.scale.xyz.x;
|
||||
worldOrient.a2d[0][2] *= decal.scale.xyz.x;
|
||||
worldOrient.a2d[1][0] *= decal.scale.xyz.y;
|
||||
worldOrient.a2d[1][1] *= decal.scale.xyz.y;
|
||||
worldOrient.a2d[1][2] *= decal.scale.xyz.y;
|
||||
worldOrient.a2d[2][0] *= decal.scale.xyz.z;
|
||||
worldOrient.a2d[2][1] *= decal.scale.xyz.z;
|
||||
worldOrient.a2d[2][2] *= decal.scale.xyz.z;
|
||||
|
||||
matrix4 mat4;
|
||||
vm_matrix4_set_transform(&mat4, &worldOrient, &worldPos);
|
||||
|
||||
return mat4;
|
||||
}
|
||||
|
||||
void renderAll() {
|
||||
if (!decal_system_active) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear out any invalid decals
|
||||
for (auto iter = active_decals.begin(); iter != active_decals.end(); ++iter) {
|
||||
if (!iter->isValid()) {
|
||||
// if we're sitting on the very last element, popping-back will invalidate the iterator!
|
||||
if (iter + 1 == active_decals.end()) {
|
||||
active_decals.pop_back();
|
||||
break;
|
||||
}
|
||||
|
||||
*iter = active_decals.back();
|
||||
active_decals.pop_back();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (active_decals.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
graphics::decal_draw_list draw_list;
|
||||
auto mission_time = f2fl(Missiontime);
|
||||
|
||||
for (auto& decal : active_decals) {
|
||||
int diffuse_bm = -1;
|
||||
int glow_bm = -1;
|
||||
int normal_bm = -1;
|
||||
|
||||
Assertion(decal.definition_handle >= 0 && decal.definition_handle < (int) decalDefinitions.size(),
|
||||
"Invalid decal handle detected!");
|
||||
auto& decalDef = decalDefinitions[decal.definition_handle];
|
||||
|
||||
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();
|
||||
}
|
||||
void
|
||||
addDecal(creation_info& info, object* host, int submodel, const vec3d& local_pos, const matrix& local_orient) {
|
||||
if (!decal_system_active) {
|
||||
return;
|
||||
}
|
||||
// Silently ignore invalid definition handle since weapons use the default values if the decal option is not present
|
||||
if (info.definition_handle < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
Assertion(info.definition_handle >= 0 && info.definition_handle < (int) decalDefinitions.size(),
|
||||
"Invalid decal handle detected!");
|
||||
auto& def = decalDefinitions[info.definition_handle];
|
||||
|
||||
if (!def.bitmapsLoaded()) {
|
||||
// If this decal was never used before then the bitmaps are not loaded so we need to do that here.
|
||||
def.loadBitmaps();
|
||||
}
|
||||
|
||||
Decal newDecal;
|
||||
newDecal.definition_handle = info.definition_handle;
|
||||
newDecal.object = object_h(host);
|
||||
newDecal.orig_obj_type = host->type;
|
||||
newDecal.submodel = submodel;
|
||||
newDecal.creation_time = f2fl(Missiontime);
|
||||
newDecal.lifetime = info.lifetime.next();
|
||||
|
||||
newDecal.position = local_pos;
|
||||
newDecal.orientation = local_orient;
|
||||
newDecal.scale.xyz.x = info.radius;
|
||||
newDecal.scale.xyz.y = info.radius;
|
||||
newDecal.scale.xyz.z = info.radius;
|
||||
|
||||
active_decals.push_back(newDecal);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "globalincs/pstypes.h"
|
||||
|
||||
#include "object/object.h"
|
||||
|
||||
#include "utils/RandomRange.h"
|
||||
|
||||
namespace decals {
|
||||
|
||||
/**
|
||||
* @brief A reference to a decal definition
|
||||
*/
|
||||
typedef int DecalReference;
|
||||
|
||||
/**
|
||||
* @brief A structure containing all information for creating a decal
|
||||
*/
|
||||
struct creation_info {
|
||||
DecalReference definition_handle = -1;
|
||||
float radius = -1.0f;
|
||||
util::UniformFloatRange lifetime = ::util::UniformFloatRange(-1.0f);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Initializes the global state of the decal system. Call once at game init.
|
||||
*/
|
||||
void initialize();
|
||||
|
||||
|
||||
/**
|
||||
* @brief Parses the information for a decal reference
|
||||
*
|
||||
* @details This function expects that the initial token has already been consumed by the parse system.
|
||||
*
|
||||
* @param dest_info The creation information struct to parse the information into
|
||||
* @param is_new_entry Set to @c false if the currently parsed object used +nocreate
|
||||
*/
|
||||
void parseDecalReference(creation_info& dest_info, bool is_new_entry = true);
|
||||
|
||||
/**
|
||||
* @brief Loads the bitmaps specified by the creation info into texture memory
|
||||
*
|
||||
* This should be called when the bitmaps of the object using this decal are loaded.
|
||||
*
|
||||
* @param info The creation information containing the decal definition handle
|
||||
*/
|
||||
void loadBitmaps(const creation_info& info);
|
||||
|
||||
/**
|
||||
* @brief Page in the bitmap data of the specified creation information. Needs to be called after loadBitmaps
|
||||
* @param info The information to page in
|
||||
*/
|
||||
void pageInDecal(const creation_info& info);
|
||||
|
||||
/**
|
||||
* @brief Shut down the decal system. Must be called from game_shutdown
|
||||
*/
|
||||
void shutdown();
|
||||
|
||||
/**
|
||||
* @brief Initialize the decal system for the mission. Must be called before every mission is started
|
||||
*/
|
||||
void initializeMission();
|
||||
|
||||
/**
|
||||
* @brief Renders all currently active decals and removes invalid decals from the active list.
|
||||
*/
|
||||
void renderAll();
|
||||
|
||||
/**
|
||||
* @brief Creates a new decal on the specified object at the specified location
|
||||
*
|
||||
* @param info The decal to create
|
||||
* @param host The object host on which to create this decal. Must be a ship.
|
||||
* @param submodel The submodel of the object model on which to create the decal.
|
||||
* @param local_pos The position in the frame of reference of the submodel at which the decal should be created.
|
||||
* @param local_orient The orientation of the decal in the frame of reference of the submodel. The forward vector of the
|
||||
* orientation should look along the direction
|
||||
*/
|
||||
void addDecal(creation_info& info,
|
||||
object* host,
|
||||
int submodel,
|
||||
const vec3d& local_pos,
|
||||
const matrix& local_orient);
|
||||
|
||||
}
|
||||
File renamed without changes.
@@ -1,18 +1,15 @@
|
||||
|
||||
#include "gamma.sdr"
|
||||
|
||||
in vec4 fragTexCoord;
|
||||
in vec4 fragColor;
|
||||
out vec4 fragOut0;
|
||||
uniform sampler2DArray baseMap;
|
||||
uniform float intensity;
|
||||
|
||||
#define SRGB_GAMMA 2.2
|
||||
void main()
|
||||
{
|
||||
vec4 baseColor = texture(baseMap, fragTexCoord.xyz);
|
||||
|
||||
baseColor.rgb = srgb_to_linear(baseColor.rgb);
|
||||
vec4 blendColor = vec4(srgb_to_linear(fragColor.rgb), fragColor.a);
|
||||
baseColor.rgb = pow(baseColor.rgb, vec3(SRGB_GAMMA));
|
||||
vec4 blendColor = vec4(pow(fragColor.rgb, vec3(SRGB_GAMMA)), fragColor.a);
|
||||
|
||||
fragOut0 = baseColor * blendColor * intensity;
|
||||
}
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loaded 100 of 1164 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user