Compare commits

..
Author SHA1 Message Date
asarium e1cee23b82 Add bindless texturing 2018-04-03 10:18:10 +02:00
971 changed files with 33277 additions and 66107 deletions

No files matched your search

-182
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -26,6 +26,9 @@
*.unsuccessfulbuild
ipch/
[Oo]bj/
[Bb]in
[Dd]ebug*/
[Rr]elease*/
Ankh.NoLoad
*.VC.db
*.VC.VC.opendb
-3
View File
@@ -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
+135 -166
View File
@@ -1,182 +1,151 @@
language: bash
language: generic
sudo: required
dist: trusty
cache:
directories:
- $HOME/cmake-3.8
directories:
- $HOME/cmake
- $HOME/.ccache
- $HOME/curl_cache
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
- qt57base
coverity_scan:
project:
name: "scp-fs2open/fs2open.github.com"
notification_email: niffiwan.scp@gmail.com
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
- sourceline: 'ppa:beineri/opt-qt571-trusty'
packages:
- *global_deps
- g++-5
- os: linux
env: CONFIGURATION="Debug" CC=gcc-7 CXX=g++-7
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- sourceline: 'ppa:beineri/opt-qt571-trusty'
packages:
- g++-7
- *global_deps
- os: linux
env: CONFIGURATION="Debug" CC=clang-3.6 CXX=clang++-3.6
addons:
apt:
sources:
- llvm-toolchain-precise
- sourceline: 'ppa:beineri/opt-qt571-trusty'
packages:
- *global_deps
- clang-3.6
- libc++-dev
- os: osx
env: CONFIGURATION="Debug"
- 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-7 CXX=g++-7
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- sourceline: 'ppa:beineri/opt-qt571-trusty'
packages:
- g++-7
- *global_deps
- os: linux
env: CONFIGURATION="Release" CC=clang-3.6 CXX=clang++-3.6
addons:
apt:
sources:
- llvm-toolchain-precise
- sourceline: 'ppa:beineri/opt-qt571-trusty'
packages:
- *global_deps
- clang-3.6
- libc++-dev
- 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"
- 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"
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
+1 -6
View File
@@ -84,6 +84,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)
@@ -115,8 +116,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 +123,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 +142,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)
@@ -190,7 +186,6 @@ include(doxygen)
IF (WIN32)
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()
+4 -5
View File
@@ -1,5 +1,4 @@
version: 1.0.0.{build}
image: Visual Studio 2015
configuration:
- Debug
- Release
@@ -7,13 +6,13 @@ 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
QT_DIR: C:\Qt\5.7\msvc2013
- BuildID: 1
CMAKE_GENERATOR: Visual Studio 14 2015 Win64
PlatformToolset: v140_xp
QT_DIR: C:\Qt\5.9\msvc2015_64
QT_DIR: C:\Qt\5.7\msvc2015_64
before_build:
- git submodule update --init --recursive
build_script:
+7 -8
View File
@@ -14,7 +14,7 @@ $NightlyConfigurations = @(
PackageType="Win64";
Toolset="v140_xp";
SimdType="SSE2";
QtDir="C:\Qt\5.9\msvc2015_64";
QtDir="C:\Qt\5.7\msvc2015_64";
SourcePackage=$false;
},
[BuildConfig]@{
@@ -22,7 +22,7 @@ $NightlyConfigurations = @(
PackageType="Win32";
Toolset="v140_xp";
SimdType="SSE2";
QtDir="C:\Qt\5.9\msvc2015";
QtDir="C:\Qt\5.7\msvc2015";
SourcePackage=$false;
}
)
@@ -32,7 +32,7 @@ $ReleaseConfigurations = @(
PackageType="Win32";
Toolset="v140_xp";
SimdType="SSE2";
QtDir="C:\Qt\5.9\msvc2015";
QtDir="C:\Qt\5.7\msvc2015";
SourcePackage=$true;
}
[BuildConfig]@{
@@ -40,7 +40,7 @@ $ReleaseConfigurations = @(
PackageType="Win32-AVX";
Toolset="v140_xp";
SimdType="AVX";
QtDir="C:\Qt\5.9\msvc2015";
QtDir="C:\Qt\5.7\msvc2015";
SourcePackage=$false;
}
[BuildConfig]@{
@@ -48,7 +48,7 @@ $ReleaseConfigurations = @(
PackageType="Win64";
Toolset="v140_xp";
SimdType="SSE2";
QtDir="C:\Qt\5.9\msvc2015_64";
QtDir="C:\Qt\5.7\msvc2015_64";
SourcePackage=$false;
}
[BuildConfig]@{
@@ -56,7 +56,7 @@ $ReleaseConfigurations = @(
PackageType="Win64-AVX";
Toolset="v140_xp";
SimdType="AVX";
QtDir="C:\Qt\5.9\msvc2015_64";
QtDir="C:\Qt\5.7\msvc2015_64";
SourcePackage=$false;
}
)
@@ -133,7 +133,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 +148,7 @@ 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" `
-DFSO_BUILD_QTFRED=ON -DQT5_INSTALL_ROOT="$env:QT_DIR" -DFSO_BUILD_FRED2="OFF" `
-G "$Env:CMAKE_GENERATOR" -T "$Env:PlatformToolset" ..
cmake --build . --config "$Env:CONFIGURATION" -- /verbosity:minimal
-3
View File
@@ -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
+9 -20
View File
@@ -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,14 +20,15 @@ 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
@@ -41,14 +38,6 @@ 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
-5
View File
@@ -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
-141
View File
@@ -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()
-24
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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 -3
View File
@@ -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
+8 -6
View File
@@ -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)
-37
View File
@@ -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()
-3
View File
@@ -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}")
-3
View File
@@ -25,7 +25,4 @@
#cmakedefine01 HAVE_CHAR32_T
#cmakedefine01 HAVE_UNICODE_CHAR_LITERAL
#cmakedefine01 HAVE_SNPRINTF
#cmakedefine01 HAVE__SNPRINTF
#endif // __PLATFORM_CHECKS_H__
+2
View File
@@ -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")
+5 -1
View File
@@ -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")
+5 -13
View File
@@ -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)
+3 -4
View File
@@ -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 -16
View File
@@ -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)
@@ -225,13 +223,3 @@ function(list_target_dependencies _target _out_var)
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
View File
@@ -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
View File
@@ -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
-3
View File
@@ -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,
-6
View File
@@ -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:")) {
+26 -20
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+6
View File
@@ -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);
+361
View File
@@ -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
+4
View File
@@ -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
View File
@@ -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;
+1
View File
@@ -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);
+49 -3
View File
@@ -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)
{
+7
View File
@@ -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
View File
@@ -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__
+835 -711
View File
File diff suppressed because it is too large. Load diff
+102 -16
View File
@@ -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,18 +741,6 @@ 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
*
+18 -24
View File
@@ -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++)
+6 -3
View File
@@ -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();
+373 -203
View File
File diff suppressed because it is too large. Load diff
+61 -150
View File
@@ -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,34 +109,32 @@ 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)
@@ -204,13 +146,17 @@ CFILE *_cfopen_special(const char* source_file, int line, const char *file_path,
// 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,13 +190,17 @@ 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);
// Returns current position of file.
int cftell(CFILE *fp);
// cfputc() writes a character to a file
int cftell(CFILE *fp);
// cfputc() writes a character to a file
int cfputc(int c, CFILE *cfile);
// cfputs() writes a string to a file
@@ -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, const void** data_out = nullptr);
// 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, const void** data_out = nullptr);
// 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__ */
+77 -58
View File
@@ -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,20 @@ int cfeof(CFILE *cfile)
{
Assert(cfile != NULL);
Cfile_block *cb;
Assert(cfile->id >= 0 && cfile->id < MAX_CFILE_BLOCKS);
cb = &Cfile_block_list[cfile->id];
int result = 0;
#if defined(CHECK_POSITION) && !defined(NDEBUG)
if (cfile->fp) {
auto raw_position = ftell(cfile->fp) - cfile->lib_offset;
Assert(raw_position == cfile->raw_position);
if (cb->fp) {
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 +100,21 @@ 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];
#if defined(CHECK_POSITION) && !defined(NDEBUG)
if (cfile->fp) {
auto raw_position = ftell(cfile->fp) - cfile->lib_offset;
Assert(raw_position == cfile->raw_position);
if (cb->fp) {
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 +127,27 @@ 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->mem_mapped );
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,23 +155,23 @@ 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 (cb->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);
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);
}
// 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!");
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);
if (cb->fp) {
auto tmp_offset = ftell(cb->fp) - cb->lib_offset;
Assert(tmp_offset == cb->raw_position);
}
#endif
@@ -179,17 +194,19 @@ 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];
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";
@@ -198,22 +215,22 @@ int cfread(void *buf, int elsize, int nelem, CFILE *cfile)
}
size_t bytes_read;
if (cfile->data != nullptr) {
if (cb->data != nullptr) {
// This is a file from memory
bytes_read = size;
memcpy(buf, reinterpret_cast<const char*>(cfile->data) + cfile->raw_position, size);
memcpy(buf, reinterpret_cast<const char*>(cb->data) + cb->raw_position, size);
} else {
bytes_read = fread( buf, 1, size, cfile->fp );
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);
if (cb->fp) {
auto tmp_offset = ftell(cb->fp) - cb->lib_offset;
Assert(tmp_offset==cb->raw_position);
}
#endif
@@ -229,8 +246,10 @@ 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;
@@ -238,28 +257,28 @@ int cfread_lua_number(double *buf, CFILE *cfile)
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);
if (cb->fp) {
long orig_pos = ftell(cb->fp);
items_read = fscanf(cb->fp, LUA_NUMBER_SCAN, buf);
advance = (size_t) (ftell(cb->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);
items_read = sscanf(reinterpret_cast<const char*>(cb->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!");
cb->raw_position += advance;
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);
if (cb->fp) {
auto tmp_offset = ftell(cb->fp) - cb->lib_offset;
Assert(tmp_offset==cb->raw_position);
}
#endif
+15 -14
View File
@@ -22,30 +22,31 @@
#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
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)
#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
View File
@@ -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;
}
-266
View File
@@ -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;
}
}
-10
View File
@@ -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);
}
+539 -327
View File
File diff suppressed because it is too large. Load diff
+3 -7
View File
@@ -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
+251 -418
View File
File diff suppressed because it is too large. Load diff
+26 -18
View File
@@ -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,6 +55,7 @@ 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;
@@ -63,18 +63,26 @@ extern float static_tube_factor;
extern int Cmdline_ambient_factor;
extern int Cmdline_env;
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 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 +102,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,18 +129,20 @@ 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;
extern bool Cmdline_nograb;
extern bool Cmdline_noshadercache;
extern bool Cmdline_no_bindless_textures;
#ifdef WIN32
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;
@@ -151,6 +158,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;
-48
View File
@@ -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"
}
]
}
}
+21 -1
View File
@@ -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 );
}
+1
View File
@@ -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
+72 -50
View File
@@ -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;
}
+7
View File
@@ -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();
+38 -8
View File
@@ -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
+11 -6
View File
@@ -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
View File
@@ -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);
};
}
+24 -67
View File
@@ -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);
}
}
+8 -5
View File
@@ -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
View File
@@ -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;
+8
View File
@@ -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();
-6
View File
@@ -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);
}
}
}
+3 -5
View File
@@ -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;
};
}
}
+145 -372
View File
@@ -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,33 @@ std::unique_ptr<DecoderStatus> initializeStatus(std::unique_ptr<InputStream>& st
status->audioStream = ctx->streams[audioStream];
}
if (subt) {
auto subtCtx = subt->m_ctx->ctx();
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;
}
}
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& current_language = Lcl_languages[Lcl_current_lang];
for (uint32_t i = 0; i < ctx->nb_streams; ++i) {
auto test_stream = ctx->streams[i];
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
auto& pars = test_stream->codecpar;
auto& pars = test_stream->codecpar;
if (!(pars->codec_type == AVMEDIA_TYPE_SUBTITLE)) {
continue;
}
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;
}
AVDictionaryEntry* tag = nullptr;
if ((tag = av_dict_get(test_stream->metadata, "language", nullptr, 0)) == nullptr) {
continue;
}
auto normalized_language = normalizeLanguage(tag->value);
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 +263,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 +312,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 +331,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 +342,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 +393,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 -18
View File
@@ -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;
};
}
}
-21
View File
@@ -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);
}
}
}
+3 -4
View File
@@ -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;
};
}
+63 -62
View File
@@ -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);
}
}
}
+4 -7
View File
@@ -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;
};
}
}
-4
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+1
View File
@@ -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
+13 -2
View File
@@ -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;
+7 -1
View File
@@ -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);
+1 -1
View File
@@ -20,7 +20,7 @@
#include <cmath>
#include <cstdarg>
#include <cstring>
#include <climits>
#include <limits.h>
// ========================= LOCALS =========================
+2 -10
View File
@@ -48,10 +48,10 @@ class DecalDefinition {
DecalDefinition& operator=(const DecalDefinition&) = delete;
// Move constructor and operator
DecalDefinition(DecalDefinition&& other) SCP_NOEXCEPT {
DecalDefinition(DecalDefinition&& other) {
*this = std::move(other); // Use operator implementation
}
DecalDefinition& operator=(DecalDefinition&& other) SCP_NOEXCEPT {
DecalDefinition& operator=(DecalDefinition&& other) {
std::swap(_name, other._name);
std::swap(_diffuseFilename, other._diffuseFilename);
@@ -226,7 +226,6 @@ void parse_decals_table(const char* filename) {
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
@@ -245,12 +244,6 @@ struct Decal {
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
@@ -532,7 +525,6 @@ addDecal(creation_info& info, object* host, int submodel, const vec3d& local_pos
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();
+4 -8
View File
@@ -24,15 +24,11 @@ void main()
// Now we compute the depth value in projection space using the clipping plane information
float view_depth = 2.0 * zNear * zFar / (zFar + zNear - depth_normalized * (zFar - zNear));
if (isinf(view_depth)) {
fragOut0.rgb = color_in.rgb;
} else {
// This is the same formula that is also used by the main shader
float fog_dist = clamp((view_depth - fog_start) * 0.75 * fog_scale, 0.0, 1.0);
// This is the same formula that is also used by the main shader
float fog_dist = isinf(view_depth) ? 1.0 : clamp((view_depth - fog_start) * 0.75 * fog_scale, 0.0, 1.0);
vec3 finalFogColor = srgb_to_linear(fog_color);
vec3 finalFogColor = srgb_to_linear(fog_color);
fragOut0.rgb = mix(color_in.rgb, finalFogColor, fog_dist);
}
fragOut0.rgb = mix(color_in.rgb, finalFogColor, fog_dist);
fragOut0.a = 1.0;
}
+124 -48
View File
@@ -1,4 +1,8 @@
#ifdef FEATURE_BINDLESS_TEXTURES
#extension GL_ARB_bindless_texture : require
#endif
#include "shadows.sdr"
#include "lighting.sdr"
#include "gamma.sdr"
@@ -19,6 +23,7 @@ struct model_light {
vec3 direction;
};
#ifdef FEATURE_BINDLESS_TEXTURES
layout (std140) uniform modelData {
mat4 modelViewMatrix;
mat4 modelMatrix;
@@ -33,7 +38,96 @@ layout (std140) uniform modelData {
model_light lights[MAX_LIGHTS];
float outlineWidth;
float extrudeWidth;
float fogStart;
float fogScale;
int buffer_matrix_offset;
vec4 clip_equation;
float thruster_scale;
bool use_clip_plane;
int n_lights;
float defaultGloss;
vec3 ambientFactor;
int desaturate;
vec3 diffuseFactor;
int blend_alpha;
vec3 emissionFactor;
bool overrideDiffuse;
vec3 diffuseClr;
bool overrideGlow;
vec3 glowClr;
bool overrideSpec;
vec3 specClr;
bool alphaGloss;
bool gammaSpec;
bool envGloss;
bool alpha_spec;
int effect_num;
vec4 fogColor;
vec3 base_color;
float anim_timer;
vec3 stripe_color;
float vpwidth;
float vpheight;
bool team_glow_enabled;
float znear;
float zfar;
float veryneardist;
float neardist;
float middist;
float fardist;
vec2 normalAlphaMinMax;
int sBasemapIndex;
int sGlowmapIndex;
int sSpecmapIndex;
int sNormalmapIndex;
int sAmbientmapIndex;
int sMiscmapIndex;
sampler2DArray sBasemap;
sampler2DArray sGlowmap;
sampler2DArray sSpecmap;
samplerCube sEnvmap;
sampler2DArray sNormalmap;
sampler2DArray sAmbientmap;
sampler2DArray sMiscmap;
sampler2DArray sHeightmap;
};
#else
layout (std140) uniform modelData {
mat4 modelViewMatrix;
mat4 modelMatrix;
mat4 viewMatrix;
mat4 projMatrix;
mat4 textureMatrix;
mat4 shadow_mv_matrix;
mat4 shadow_proj_matrix[4];
mat4 envMatrix;
vec4 color;
model_light lights[MAX_LIGHTS];
float extrudeWidth;
float fogStart;
float fogScale;
int buffer_matrix_offset;
@@ -95,6 +189,17 @@ layout (std140) uniform modelData {
int sAmbientmapIndex;
int sMiscmapIndex;
};
uniform sampler2DArray sBasemap;
uniform sampler2DArray sGlowmap;
uniform sampler2DArray sSpecmap;
uniform samplerCube sEnvmap;
uniform sampler2DArray sNormalmap;
uniform sampler2DArray sAmbientmap;
uniform sampler2DArray sMiscmap;
#endif
uniform sampler2D sFramebuffer;
uniform sampler2DArray shadow_map;
in VertexOutput {
#ifdef FLAG_ENV_MAP
@@ -105,6 +210,11 @@ in VertexOutput {
#endif
#ifdef FLAG_FOG
float fogDist;
#endif
#ifdef WORKAROUND_CLIPPING_PLANES
#ifdef FLAG_TRANSFORM
float notVisible;
#endif
#endif
vec4 position;
vec3 normal;
@@ -115,36 +225,9 @@ in VertexOutput {
#endif
} vertIn;
#ifdef FLAG_DIFFUSE_MAP
uniform sampler2DArray sBasemap;
#endif
#ifdef FLAG_GLOW_MAP
uniform sampler2DArray sGlowmap;
#endif
#ifdef FLAG_SPEC_MAP
uniform sampler2DArray sSpecmap;
#endif
#ifdef FLAG_ENV_MAP
uniform samplerCube sEnvmap;
#endif
#ifdef FLAG_NORMAL_MAP
uniform sampler2DArray sNormalmap;
#endif
#ifdef FLAG_AMBIENT_MAP
uniform sampler2DArray sAmbientmap;
#endif
#ifdef FLAG_ANIMATED
uniform sampler2D sFramebuffer;
#endif
#ifdef FLAG_TEAMCOLOR
vec2 teamMask = vec2(0.0, 0.0);
#endif
#ifdef FLAG_MISC_MAP
uniform sampler2DArray sMiscmap;
#endif
#ifdef FLAG_SHADOWS
uniform sampler2DArray shadow_map;
#endif
out vec4 fragOut0;
out vec4 fragOut1;
@@ -210,6 +293,11 @@ vec3 CalculateLighting(vec3 normal, vec3 diffuseMaterial, vec3 specularMaterial,
void main()
{
#ifdef WORKAROUND_CLIPPING_PLANES
#ifdef FLAG_TRANSFORM
if(vertIn.notVisible >= 0.9) { discard; }
#endif
#endif
#ifdef FLAG_SHADOW_MAP
// need depth and depth squared for variance shadow maps
fragOut0 = vec4(vertIn.position.z, vertIn.position.z * vertIn.position.z * VARIANCE_SHADOW_SCALE_INV, 0.0, 1.0);
@@ -280,11 +368,11 @@ void main()
}
if(gammaSpec) {
specColor.rgb = max(specColor.rgb, vec3(0.03f)); // hardcoded minimum specular value. read John Hable's blog post titled 'Everything Is Shiny'.
#ifdef FLAG_HDR
specColor.rgb = srgb_to_linear(specColor.rgb);
#endif
fresnelFactor = 1.0;
}
#ifdef FLAG_HDR
specColor.rgb = srgb_to_linear(specColor.rgb);
#endif
#endif
baseColor.rgb *= aoFactors.y;
specColor.rgb *= aoFactors.y;
@@ -292,29 +380,20 @@ void main()
#ifdef FLAG_TEAMCOLOR
vec4 teamMask = vec4(0.0, 0.0, 0.0, 0.0);
teamMask = texture(sMiscmap, vec3(texCoord, float(sMiscmapIndex)));
//For team colors applied to a diffuse or spec map, we assume that the base color of the diffuse
//at this point is vec3(0.5). To get accurate results, we subtract 0.5 from the team colors
vec3 color_offset = vec3(-0.5) * (teamMask.x + teamMask.y);
vec3 team_color = base_color * teamMask.x + stripe_color * teamMask.y + color_offset;
vec3 team_color = ((base_color - vec3(0.5)) * teamMask.x) + ((stripe_color - vec3(0.5)) * teamMask.y);
vec3 team_color_glow = (base_color * teamMask.b) + (stripe_color * teamMask.a);
#ifdef FLAG_HDR
baseColor.rgb = linear_to_srgb(baseColor.rgb);
specColor.rgb = linear_to_srgb(specColor.rgb);
team_color = srgb_to_linear(team_color);
team_color_glow = srgb_to_linear(team_color_glow) * GLOW_MAP_SRGB_MULTIPLIER;
#endif
baseColor.rgb += team_color;
baseColor.rgb = max(baseColor.rgb, vec3(0.0)); // We need to make sure that nothing here ever goes negative
specColor.rgb += team_color;
specColor.rgb = max(specColor.rgb, vec3(0.03));
#ifdef FLAG_HDR
baseColor.rgb = srgb_to_linear(baseColor.rgb);
specColor.rgb = srgb_to_linear(specColor.rgb);
#endif
#endif
#endif
// Lights aren't applied when we are rendering to the G-buffers since that gets handled later
@@ -380,10 +459,8 @@ void main()
#ifdef FLAG_DIFFUSE_MAP
if(blend_alpha == 1) finalFogColor *= baseColor.a;
#endif
// This code will only be used by the forward renderer so we apply the fog effect to both the emissive and the base
// color.
baseColor.rgb = mix(emissiveColor.rgb + baseColor.rgb, finalFogColor, vertIn.fogDist);
emissiveColor.rgb = vec3(0.0); // Zero the emissive color since it has already been added by the previous line
baseColor.rgb = mix(baseColor.rgb, finalFogColor, vertIn.fogDist);
emissiveColor.rgb = mix(emissiveColor.rgb, finalFogColor, vertIn.fogDist);
specColor.rgb *= vertIn.fogDist;
#endif
@@ -425,7 +502,6 @@ void main()
// emissive colors won't be added later when we are using forward rendering so we need to do that here
baseColor.rgb += emissiveColor.rgb;
#endif
fragOut0 = baseColor;
#ifdef FLAG_DEFERRED
fragOut1 = vec4(vertIn.position.xyz, 1.0);
+117 -83
View File
@@ -1,18 +1,13 @@
#extension GL_ARB_gpu_shader5: enable
#ifdef FLAG_THICK_OUTLINE
layout (triangles) in;
// For every triangle line we generate 2 triangles which can be done with 4 vertices so in total we will need 12 vertices
layout (triangle_strip, max_vertices = 12) out;
#else
layout (triangles) in;
layout (triangle_strip, max_vertices = 3) out;
#ifdef FEATURE_BINDLESS_TEXTURES
#extension GL_ARB_bindless_texture : require
#endif
#ifdef FLAG_SHADOW_MAP
#ifdef GL_ARB_gpu_shader5
layout (triangles) in;
layout (triangle_strip, max_vertices = 3) out;
#ifdef GL_ARB_gpu_shader5
layout(invocations = 4) in;
#endif
#endif
#define MAX_LIGHTS 8
@@ -28,6 +23,7 @@ struct model_light {
vec3 direction;
};
#ifdef FEATURE_BINDLESS_TEXTURES
layout (std140) uniform modelData {
mat4 modelViewMatrix;
mat4 modelMatrix;
@@ -42,7 +38,96 @@ layout (std140) uniform modelData {
model_light lights[MAX_LIGHTS];
float outlineWidth;
float extrudeWidth;
float fogStart;
float fogScale;
int buffer_matrix_offset;
vec4 clip_equation;
float thruster_scale;
bool use_clip_plane;
int n_lights;
float defaultGloss;
vec3 ambientFactor;
int desaturate;
vec3 diffuseFactor;
int blend_alpha;
vec3 emissionFactor;
bool overrideDiffuse;
vec3 diffuseClr;
bool overrideGlow;
vec3 glowClr;
bool overrideSpec;
vec3 specClr;
bool alphaGloss;
bool gammaSpec;
bool envGloss;
bool alpha_spec;
int effect_num;
vec4 fogColor;
vec3 base_color;
float anim_timer;
vec3 stripe_color;
float vpwidth;
float vpheight;
bool team_glow_enabled;
float znear;
float zfar;
float veryneardist;
float neardist;
float middist;
float fardist;
vec2 normalAlphaMinMax;
int sBasemapIndex;
int sGlowmapIndex;
int sSpecmapIndex;
int sNormalmapIndex;
int sAmbientmapIndex;
int sMiscmapIndex;
sampler2DArray sBasemap;
sampler2DArray sGlowmap;
sampler2DArray sSpecmap;
samplerCube sEnvmap;
sampler2DArray sNormalmap;
sampler2DArray sAmbientmap;
sampler2DArray sMiscmap;
sampler2DArray sHeightmap;
};
#else
layout (std140) uniform modelData {
mat4 modelViewMatrix;
mat4 modelMatrix;
mat4 viewMatrix;
mat4 projMatrix;
mat4 textureMatrix;
mat4 shadow_mv_matrix;
mat4 shadow_proj_matrix[4];
mat4 envMatrix;
vec4 color;
model_light lights[MAX_LIGHTS];
float extrudeWidth;
float fogStart;
float fogScale;
int buffer_matrix_offset;
@@ -104,6 +189,7 @@ layout (std140) uniform modelData {
int sAmbientmapIndex;
int sMiscmapIndex;
};
#endif
in VertexOutput {
#ifdef FLAG_ENV_MAP
@@ -115,13 +201,15 @@ in VertexOutput {
#ifdef FLAG_FOG
float fogDist;
#endif
#ifdef WORKAROUND_CLIPPING_PLANES
#ifdef FLAG_TRANSFORM
float notVisible;
#endif
#endif
#ifdef FLAG_SHADOW_MAP
#if !defined(GL_ARB_gpu_shader5)
float instance;
#endif
#ifdef FLAG_TRANSFORM
float clipModel;
#endif
#else
vec4 position;
#endif
@@ -142,6 +230,11 @@ out VertexOutput {
#endif
#ifdef FLAG_FOG
float fogDist;
#endif
#ifdef WORKAROUND_CLIPPING_PLANES
#ifdef FLAG_TRANSFORM
float notVisible;
#endif
#endif
vec4 position;
vec3 normal;
@@ -152,7 +245,6 @@ out VertexOutput {
#endif
} vertOut;
#ifdef FLAG_SHADOW_MAP
void main(void)
{
#ifdef GL_ARB_gpu_shader5
@@ -162,25 +254,14 @@ void main(void)
#endif
for(int vert = 0; vert < gl_in.length(); vert++)
{
#ifdef FLAG_TRANSFORM
if (vertIn[vert].clipModel > 0.9) {
// If the model was clipped in the vertex shader then we do not apply the shadow projection matrix here
gl_Position = gl_in[vert].gl_Position;
} else {
gl_Position = shadow_proj_matrix[instanceID] * gl_in[vert].gl_Position;
}
#else
gl_Position = shadow_proj_matrix[instanceID] * gl_in[vert].gl_Position;
#endif
if(gl_Position.z < -1.0)
gl_Position.z = -1.0;
vertOut.position = gl_in[vert].gl_Position;
vertOut.normal = vertIn[vert].normal;
vertOut.texCoord = vertIn[vert].texCoord;
gl_Layer = instanceID;
#ifdef FLAG_ENV_MAP
vertOut.envReflect = vertIn[vert].envReflect;
#endif
@@ -197,66 +278,19 @@ void main(void)
vertOut.shadowUV[3] = vertIn[vert].shadowUV[3];
vertOut.shadowPos = vertIn[vert].shadowPos;
#endif
#if defined(FLAG_CLIP)
#ifdef WORKAROUND_CLIPPING_PLANES
#ifdef FLAG_TRANSFORM
vertOut.notVisible = vertIn[vert].notVisible;
#endif
#ifdef FLAG_CLIP
gl_ClipDistance[0] = gl_in[vert].gl_ClipDistance[0];
#endif
#else
#if defined(FLAG_CLIP) || defined(FLAG_TRANSFORM)
gl_ClipDistance[0] = gl_in[vert].gl_ClipDistance[0];
#endif
#endif
EmitVertex();
}
EndPrimitive();
}
#elif defined(FLAG_THICK_OUTLINE)
const vec2 pixelOffsetDir[4] = vec2[](
vec2(0.0, 1.0),
vec2(1.0, 1.0),
vec2(1.0, -1.0),
vec2(0.0, -1.0)
);
void main(void)
{
for(int vert = 0; vert < gl_in.length(); vert++)
{
int nextVert = (vert + 1) % gl_in.length();
vec4 clip = gl_in[vert].gl_Position;
vec4 diff = gl_in[nextVert].gl_Position - clip; // vector from vert to the next vertex in the list
vec2 normal = normalize(vec2(diff.y, -diff.x)); // Computing the normal of a 2D vector is actually rather simple...
for (int lineVert = 0; lineVert < 4; ++lineVert)
{
// This is the pixel offset along the normal axis
vec2 yOffPixel = pixelOffsetDir[lineVert].y * normal * (outlineWidth / 2.0);
// This is the offset of the vertex along the vector between this vertex and the next one in the triangle
vec2 xOff = pixelOffsetDir[lineVert].x * diff.xy;
// This is the final offset in clip space
vec2 finalOffset = xOff + yOffPixel * vec2(vpwidth, vpheight) * clip.w;
gl_Position = vec4(clip.xyz + vec3(finalOffset, 0.0), clip.w);
vertOut.position = vertIn[vert].position;
vertOut.normal = vertIn[vert].normal;
vertOut.texCoord = vertIn[vert].texCoord;
#ifdef FLAG_ENV_MAP
vertOut.envReflect = vertIn[vert].envReflect;
#endif
#ifdef FLAG_NORMAL_MAP
vertOut.tangentMatrix = vertIn[vert].tangentMatrix;
#endif
#ifdef FLAG_FOG
vertOut.fogDist = vertIn[vert].fogDist;
#endif
#ifdef FLAG_SHADOWS
vertOut.shadowUV[0] = vertIn[vert].shadowUV[0];
vertOut.shadowUV[1] = vertIn[vert].shadowUV[1];
vertOut.shadowUV[2] = vertIn[vert].shadowUV[2];
vertOut.shadowUV[3] = vertIn[vert].shadowUV[3];
vertOut.shadowPos = vertIn[vert].shadowPos;
#endif
#if defined(FLAG_CLIP)
gl_ClipDistance[0] = gl_in[vert].gl_ClipDistance[0];
#endif
EmitVertex();
}
EndPrimitive();
}
}
#endif
+131 -23
View File
@@ -1,4 +1,7 @@
#extension GL_ARB_gpu_shader5: enable
#ifdef FEATURE_BINDLESS_TEXTURES
#extension GL_ARB_bindless_texture : require
#endif
#include "shadows.sdr"
@@ -22,6 +25,7 @@ struct model_light {
vec3 direction;
};
#ifdef FEATURE_BINDLESS_TEXTURES
layout (std140) uniform modelData {
mat4 modelViewMatrix;
mat4 modelMatrix;
@@ -36,7 +40,96 @@ layout (std140) uniform modelData {
model_light lights[MAX_LIGHTS];
float outlineWidth;
float extrudeWidth;
float fogStart;
float fogScale;
int buffer_matrix_offset;
vec4 clip_equation;
float thruster_scale;
bool use_clip_plane;
int n_lights;
float defaultGloss;
vec3 ambientFactor;
int desaturate;
vec3 diffuseFactor;
int blend_alpha;
vec3 emissionFactor;
bool overrideDiffuse;
vec3 diffuseClr;
bool overrideGlow;
vec3 glowClr;
bool overrideSpec;
vec3 specClr;
bool alphaGloss;
bool gammaSpec;
bool envGloss;
bool alpha_spec;
int effect_num;
vec4 fogColor;
vec3 base_color;
float anim_timer;
vec3 stripe_color;
float vpwidth;
float vpheight;
bool team_glow_enabled;
float znear;
float zfar;
float veryneardist;
float neardist;
float middist;
float fardist;
vec2 normalAlphaMinMax;
int sBasemapIndex;
int sGlowmapIndex;
int sSpecmapIndex;
int sNormalmapIndex;
int sAmbientmapIndex;
int sMiscmapIndex;
sampler2DArray sBasemap;
sampler2DArray sGlowmap;
sampler2DArray sSpecmap;
samplerCube sEnvmap;
sampler2DArray sNormalmap;
sampler2DArray sAmbientmap;
sampler2DArray sMiscmap;
sampler2DArray sHeightmap;
};
#else
layout (std140) uniform modelData {
mat4 modelViewMatrix;
mat4 modelMatrix;
mat4 viewMatrix;
mat4 projMatrix;
mat4 textureMatrix;
mat4 shadow_mv_matrix;
mat4 shadow_proj_matrix[4];
mat4 envMatrix;
vec4 color;
model_light lights[MAX_LIGHTS];
float extrudeWidth;
float fogStart;
float fogScale;
int buffer_matrix_offset;
@@ -98,11 +191,10 @@ layout (std140) uniform modelData {
int sAmbientmapIndex;
int sMiscmapIndex;
};
#ifdef FLAG_TRANSFORM
uniform samplerBuffer transform_tex;
#endif
uniform samplerBuffer transform_tex;
out VertexOutput {
#ifdef FLAG_ENV_MAP
vec3 envReflect;
@@ -113,15 +205,15 @@ out VertexOutput {
#ifdef FLAG_FOG
float fogDist;
#endif
#ifdef WORKAROUND_CLIPPING_PLANES
#ifdef FLAG_TRANSFORM
float notVisible;
#endif
#endif
#ifdef FLAG_SHADOW_MAP
#if !defined(GL_ARB_gpu_shader5)
float instance;
#endif
#ifdef FLAG_TRANSFORM
// This flag is needed to let the geometry shader know that it doesn't need to apply the
// shadow projection to gl_Position
float clipModel;
#endif
#else
vec4 position;
#endif
@@ -152,9 +244,19 @@ void main()
vec4 texCoord;
mat4 orient = mat4(1.0);
mat4 scale = mat4(1.0);
#ifdef FLAG_TRANSFORM
#ifdef WORKAROUND_CLIPPING_PLANES
#ifdef FLAG_TRANSFORM
bool clipModel;
getModelTransform(orient, clipModel, int(vertModelID), buffer_matrix_offset);
vertOut.notVisible = clipModel ? 1.0 : 0.0;
#endif
#else
#ifdef FLAG_TRANSFORM
bool clipModel;
getModelTransform(orient, clipModel, int(vertModelID), buffer_matrix_offset);
#else
bool clipModel = false;
#endif
#endif
texCoord = textureMatrix * vertTexCoord;
vec4 vertex = vertPosition;
@@ -178,6 +280,9 @@ void main()
#else
gl_Position = projMatrix * position;
#endif
#ifdef FLAG_NORMAL_EXTRUDE
gl_Position.xy += (mat3(projMatrix) * normal.xyz).xy * gl_Position.z * extrudeWidth;
#endif
#ifdef FLAG_SHADOWS
vec4 shadowPos = shadow_mv_matrix * modelMatrix * orient * vertPosition;
vertOut.shadowPos = shadow_mv_matrix * modelMatrix * orient * vertPosition;
@@ -200,28 +305,31 @@ void main()
#ifdef FLAG_FOG
vertOut.fogDist = clamp((gl_Position.z - fogStart) * 0.75 * fogScale, 0.0, 1.0);
#endif
#ifdef FLAG_TRANSFORM
if (clipModel) {
// Clip this model by moving all vertices outside the clip volume
gl_Position = vec4(vec3(-2.0), 1.0);
}
#ifdef FLAG_SHADOW_MAP
vertOut.clipModel = clipModel ? 1.0 : 0.0;
#endif
#endif
#ifdef FLAG_CLIP
#ifdef WORKAROUND_CLIPPING_PLANES
if(use_clip_plane) {
gl_ClipDistance[0] = dot(clip_equation, modelMatrix * orient * vertex);
} else {
gl_ClipDistance[0] = 1.0;
}
#else
#ifdef FLAG_CLIP
if (clipModel) {
gl_ClipDistance[0] = -1.0;
} else if(use_clip_plane) {
gl_ClipDistance[0] = dot(clip_equation, modelMatrix * orient * vertex);
} else {
gl_ClipDistance[0] = 1.0;
}
#elif defined(FLAG_TRANSFORM)
gl_ClipDistance[0] = clipModel ? -1.0 : 1.0;
#endif
#endif
#ifndef FLAG_SHADOW_MAP
#ifndef FLAG_SHADOW_MAP
vertOut.position = position;
vertOut.normal = normal;
vertOut.texCoord = texCoord;
#else
#else
vertOut.normal = normal;
vertOut.texCoord = texCoord;
#endif
#endif
}
@@ -1,17 +0,0 @@
in vec2 fragTexCoord;
in vec4 fragColor;
out vec4 fragOut0;
uniform bool textured;
uniform sampler2DArray baseMap;
uniform int baseMapIndex;
void main() {
if (textured) {
fragOut0 = texture(baseMap, vec3(fragTexCoord, float(baseMapIndex))) * fragColor;
} else {
fragOut0 = fragColor;
}
}
@@ -1,18 +0,0 @@
in vec2 vertPosition;
in vec4 vertColor;
in vec2 vertTexCoord;
out vec2 fragTexCoord;
out vec4 fragColor;
uniform mat4 modelViewMatrix;
uniform mat4 projMatrix;
void main()
{
fragTexCoord = vertTexCoord;
fragColor = vertColor;
gl_Position = projMatrix * modelViewMatrix * vec4(vertPosition, 0.0, 1.0);
}
Loaded 100 of 971 files, more files were not shown because too many files have changed in this diff. Show more