Compare commits

..
Author SHA1 Message Date
z64555 8b517ddda9 Adds outwindow init and the SCP_mspdbcs init and cleanup. 2016-08-15 17:45:22 -05:00
z64555 6bc5a395e0 Pointless style flag is pointless 2016-08-15 17:28:52 -05:00
z64555 318496992e Fix bug where scene would not repaint when window was resized to something smaller. 2016-08-15 17:24:55 -05:00
z64555 1e28d526ae Prevent excessive calls to wxfred::render_resize if the viewport size didn't change. 2016-08-15 16:10:48 -05:00
z64555 26a746d612 Some work on the viewport:
* Viewport now resizes. There's some kinks with re-draw to work out, though
* Viewport now displays starfield
* Viewport now displays mission grid
2016-08-15 07:24:39 -05:00
z64555 5b41dce69c Update wxfred2.cpp to use flagsets. Also a bit of whitespace maintenance (yawn). 2016-08-15 05:38:04 -05:00
z64555 ea9b611782 Merge branch 'master' of https://github.com/scp-fs2open/fs2open.github.com into wxfred2 2016-08-15 04:37:40 -05:00
z64555 9474f58820 Setup OS and FSO backend initialization.
* Currently only works on Windows due to the OpenGL loader (wxFredRender) being rather basic.
2016-08-14 19:36:16 -05:00
z64555 006853ae44 Forgot to set canvas target in context creation. 2016-08-13 20:33:50 -05:00
z64555 22f56a12d9 * Implements wxFredRender's render_init() and render_frame() functions.
* Implements glcViewport's construction
2016-08-13 20:09:52 -05:00
z64555 20990416a9 Implement wxFredRender components. 2016-08-10 17:56:51 -05:00
z64555 92fc16372f Create wxFredRender files, this'll be for the graphics of wxFred and used by the glcViewport class(es). 2016-08-08 05:50:41 -05:00
z64555 cd25f907ac Merge pull request #2 from asarium/wxfred2_dev
Fix MSVC compilation issues
2016-08-08 04:33:11 -05:00
asarium c2363989e4 Fix MSVC compilation issues 2016-08-08 11:27:45 +02:00
z64555 7b13d5c1f2 Merge pull request #1 from asarium/wxfred2_dev
Fix wxFRED CMake and compliation errors
2016-08-08 04:18:56 -05:00
asarium 25f6be7867 Use the version string in the project headers 2016-08-08 11:17:05 +02:00
asarium 9756b52845 Fix wxFRED CMake and compliation errors 2016-08-08 11:17:05 +02:00
z64555 93101aa8ce Remove glrcMissionFrame. 2016-08-08 04:07:48 -05:00
z64555 10a37e6ddb Add link targets to core codebase. 2016-08-08 02:46:08 -05:00
z64555 469a31602e Fix access violation. Can't append items to wxChoice elements for the moment. 2016-08-07 23:15:43 -05:00
z64555 3521740a60 Update XRC and generated files to use wxWidgets 3.0.2 (or later. wxFormBuilder doesn't say which version it uses) 2016-08-07 23:15:42 -05:00
z64555 beaee70a82 Fix building after rebase with master. 2016-08-07 23:15:42 -05:00
z64555 eb3b65e051 Implement Copy functions, settle on using OIN_t's for object selection queues. 2016-08-07 23:15:41 -05:00
z64555 4bb547ce09 (FRED) Fix bug where AIF_NO_DYNAMIC flags weren't set with copied objects 2016-08-07 23:15:40 -05:00
z64555 5294db25b3 Implement port of core mission management functions 2016-08-07 23:15:40 -05:00
z64555 5983ddeea4 Some FRED cleanup and debugging 2016-08-07 23:15:39 -05:00
z64555 37d16a65c4 Updating README with info on wxWidget's Release packages. 2016-08-07 23:15:39 -05:00
z64555 8c54c63908 Update the README a bit. 2016-08-07 23:15:38 -05:00
z64555 ae7bf0667e Fix linking due to an unknown, removed, or renamed ailocal.h 2016-08-07 23:15:38 -05:00
z64555 c018329a4c Adds new define to disable FSO's mem* function overrides 2016-08-07 23:15:38 -05:00
z64555 f188960f91 Fixes compiling by de-tangling a #include chain that was exposed by commit 798a8922879f7af8ebd2bb07a6cdaa655a2e038b 2016-08-07 23:15:37 -05:00
niffiwan 7255d5e8e4 Update Linux to link successfully with libcode.a 2016-08-07 23:15:36 -05:00
z64555 198c6cace9 End of linkage work. (This commit is probably temporary)
* Includes wxfredstubs.cpp to prevent linkage to certain data members and functions defined in freespace.cpp.
 * "_SECURE_SCL" and "_HAS_ITERATOR_DEBUGGING" defines removed from the project files
 * C runtime library (CRT) switched to use DLL so as to integrate with wxWidgets default settings.
2016-08-07 23:15:34 -05:00
z64555 5efe85b4db Beginning setup to link into code.lib, defined some variables needed for linkage and link tests. 2016-08-07 23:15:01 -05:00
z64555 fb8fe9bb75 Started work on docFRED2, and mission load/save methods. More work done on glcViewport. 2016-08-07 23:14:59 -05:00
z64555 790f8b9d8c Some header name wrangling, a Big O snuck in somehow. 2016-08-07 23:14:03 -05:00
z64555 0bcc9f27d4 glcViewport and glrcMissionFrame classes added. README updated. 2016-08-07 23:13:59 -05:00
1073 changed files with 78964 additions and 139397 deletions

No files matched your search

-3
View File
@@ -2,6 +2,3 @@ root = true
[*.{h,cpp}]
indent_style = tab
[*.sdr]
indent_style = tab
+30 -5
View File
@@ -1,3 +1,33 @@
*.o
*.a
.dirstamp
libtool
ltmain.sh
m4/libtool.m4
m4/ltoptions.m4
m4/ltsugar.m4
m4/ltversion.m4
m4/lt~obsolete.m4
compile
.deps/
code/.deps/
Makefile
Makefile.in
aclocal.m4
autom4te.cache/
config.*
code/fs2_open_*
code/wxFRED2_*
configure
depcomp
install-sh
missing
.svn
*.layout
projects/Xcode/Frameworks/
#========
#OS junk files
[Tt]humbs.db
*.DS_Store
@@ -251,8 +281,3 @@ documentation/doxygen/*
.idea/*
projects/*
/.vs
CMakeSettings.json
# Weird files created by Linux
.fuse_hidden*
+3
View File
@@ -1,3 +1,6 @@
[submodule "cmake/external/cotire"]
path = cmake/external/cotire
url = https://github.com/sakra/cotire.git
[submodule "cmake/external/rpavlik-cmake-modules"]
path = cmake/external/rpavlik-cmake-modules
url = https://github.com/asarium/cmake-modules.git
+35 -66
View File
@@ -6,16 +6,18 @@ cache:
- $HOME/cmake
addons:
apt:
packages: &global_deps
packages:
- ninja-build
- libopenal-dev
- libogg-dev
- libvorbis-dev
- libtheora-dev
- libreadline6-dev
- libpng12-dev
- libjpeg62-dev
- liblua5.1-0-dev
- libjansson-dev
- libsdl2-dev
- valgrind
coverity_scan:
project:
name: "scp-fs2open/fs2open.github.com"
@@ -23,6 +25,25 @@ addons:
build_command: "ci/travis/script.sh"
# must match TRAVIS_BRANCH check below
branch_pattern: coverity_scan
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: bintray
user: sirknightly
key:
secure: "CZtvDW/zPf1Nxru21i8Wd+9hgiBRA8VowWBX0gmCOGgRq9WHISttKQQmBWGHuyVZ3rYvtE4Va2bR+2qRN+TFNkUUuOCOQkdBJTCal9nS3G/LprEmsOashG0Q5PTfMMBnlKzKxaxGJW6UhFj2GySmHEAjsFLVpuNWGJeeZgZQ3UE="
file: ci/bintray.json
on:
condition: '"$NIGHTLY_BUILD" == true'
tags: true
env:
global:
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
@@ -30,81 +51,27 @@ env:
# 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: 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
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
packages:
- g++-5
- *global_deps
compiler: gcc
env: CONFIGURATION="Debug"
- os: linux
env: CONFIGURATION="Debug" CC=clang-3.6 CXX=clang++-3.6
addons:
apt:
sources:
- llvm-toolchain-precise
packages:
- clang-3.6
- libc++-dev
- *global_deps
compiler: clang
env: CONFIGURATION="Debug" CC=clang CXX=clang++
- os: osx
compiler: clang
env: CONFIGURATION="Debug"
- os: linux
env: CONFIGURATION="Release" CC=gcc-5 CXX=g++-5
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-5
- *global_deps
compiler: gcc
env: CONFIGURATION="Release"
- os: linux
env: CONFIGURATION="Release" CC=clang-3.6 CXX=clang++-3.6
addons:
apt:
sources:
- llvm-toolchain-precise
packages:
- clang-3.6
- libc++-dev
- *global_deps
compiler: clang
env: CONFIGURATION="Release" CC=clang CXX=clang++
- os: osx
compiler: clang
env: CONFIGURATION="Release"
before_install:
# ugly hack; if running a coverity scan abort all except the 1st build
@@ -122,3 +89,5 @@ before_script:
- "./ci/travis/before_script.sh"
script:
- if [ "$BUILD_DEPLOYMENT" = true ] ; then ./ci/travis/release.sh ; else ./ci/travis/script.sh ; fi
before_deploy:
- "./ci/travis/before_deploy.sh"
+9 -10
View File
@@ -53,7 +53,7 @@ endif()
LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/finder")
LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/external/rpavlik-cmake-modules")
LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/external/cotire")
LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/external/cotire/CMake")
IF(RESET_INSTALL_PREFIX)
IF(NOT $ENV{FS2PATH} STREQUAL "")
@@ -81,8 +81,6 @@ ENDIF(WIN32)
OPTION(FSO_BUILD_TOOLS "Build tools related to FSO" OFF)
OPTION(FSO_BUILD_TESTS "Build unit tests" OFF)
OPTION(FSO_DEVELOPMENT_MODE "Generate binaries in development mode, only use if you know what you're doing!" OFF)
OPTION(FSO_BUILD_WXFRED2 "Build wxFRED2 binary" OFF)
@@ -108,16 +106,21 @@ 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(COTIRE_ENABLE "Enable cotire, this speeds up builds but may cause issues while developing (default = OFF)" OFF)
MARK_AS_ADVANCED(FORCE FSO_CMAKE_DEBUG)
MARK_AS_ADVANCED(FORCE FSO_BUILD_INCLUDED_LIBS)
MARK_AS_ADVANCED(FORCE FSO_USE_OPENALSOFT)
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 COTIRE_ENABLE)
mark_as_advanced(FORCE FSO_INSTALL_DEBUG_FILES)
# Include cotire file from https://github.com/sakra/cotire/
include(cotire)
IF(COTIRE_ENABLE)
# Include cotire file from https://github.com/sakra/cotire/
include(cotire)
ENDIF(COTIRE_ENABLE)
INCLUDE(globals)
INCLUDE(toolchain)
@@ -151,10 +154,6 @@ IF(FSO_BUILD_WXFRED2)
ADD_SUBDIRECTORY(wxfred2)
ENDIF(FSO_BUILD_WXFRED2)
if(FSO_BUILD_TESTS)
add_subdirectory(test)
endif()
if ("${CMAKE_VERSION}" VERSION_GREATER "3.5")
# Default to using Freespace2 as startup project if CMake supports it.
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT Freespace2)
@@ -184,4 +183,4 @@ elseif(UNIX)
ENDIF()
message(STATUS "Building FSO tools: ${FSO_BUILD_TOOLS}")
message(STATUS "Building wxFRED: ${FSO_BUILD_WXFRED2}")
message(STATUS "Fatal warnings: ${FSO_FATAL_WARNINGS}")
message(STATUS "Fatal warnings: ${FSO_FATAL_WARNINGS}")
+2 -6
View File
@@ -1,13 +1,10 @@
FreeSpace2 *S*ource *C*ode *P*roject
==
[![Travis-CI Build Status](https://travis-ci.org/scp-fs2open/fs2open.github.com.svg?branch=master)](https://travis-ci.org/scp-fs2open/fs2open.github.com)
[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/scp-fs2open/fs2open.github.com?branch=master&svg=true)](https://ci.appveyor.com/project/SirKnightly/fs2open-github-com/branch/master)
[![Build Status](https://travis-ci.org/scp-fs2open/fs2open.github.com.svg?branch=master)](https://travis-ci.org/scp-fs2open/fs2open.github.com)
[![Coverity](https://img.shields.io/coverity/scan/870.svg)](https://scan.coverity.com/projects/870)
Building
--
Before you do anything, make sure you have updated your git submodules, either by running `git submodule update --init --recursive` or by cloning the repository with the `--recursive` flag.<br/>
<br/>
For building you will need [CMake](http://www.cmake.org/cmake/resources/software.html). Version 3.4 is required. Once you have installed CMake you should create a build directory where the project/make files should be created, **do not create them inside the source tree!**<br>
<br>
On Windows you can use the `cmake-gui` executable to get a nice GUI, on Unix just use `cmake`. Use the newly created directory as build directory (change to this directory on Unix) and run cmake. On Windows this can be done by clicking the `Configure` button. Choose your compiler version and hit `Generate` when configuring is done. <br>
@@ -17,7 +14,6 @@ Depending on the makefile generator used build the `all` or `ALL_BUILD` target t
* `FSO_BUILD_WXFRED2`: Build the wxfred2 project, requires wxWidgets
* `FSO_FREESPACE_PATH`: Sets the path of your FreeSpace install, can be used to automatically run the generated executables with the correct working directory, this is an optional variable. By default this will use the value of the `FS2PATH` environment variable.
* `FSO_BUILD_TOOLS`: Build some tools related to FSO
* `CMAKE_BUILD_TYPE`: Sets the binary build type between `Debug` and `Release` (default)
#### Windows only variables
* `FSO_BUILD_FRED2`: Build FRED2, requires a Visual Studio version that ships with MFC
@@ -39,4 +35,4 @@ You should only use these variables if you know what you're doing
* `MSVC_SIMD_INSTRUCTIONS`: The instruction set the executables will be optimized for.
### Generating an installation package
CMake can automatically generate installation packages of the project. To do this you will just need to run the `package` target of the build system and the package will be placed inside your build directory. On Windows you will have to install [NSIS](http://nsis.sourceforge.net/Main_Page) to use this.
CMake can automaticall generate installation packages of the project. To do this you will just need to run the `package` target of the build system and the package will be placed inside your build directory. On Windows you will have to install [NSIS](http://nsis.sourceforge.net/Main_Page) to use this.
+17 -38
View File
@@ -5,18 +5,19 @@ configuration:
clone_depth: 10
environment:
matrix:
- BuildID: 0
- VS_VERSION: 12
CMAKE_GENERATOR: Visual Studio 12 2013
PlatformToolset: v120_xp
- BuildID: 1
CMAKE_GENERATOR: Visual Studio 14 2015 Win64
- VS_VERSION: 14
CMAKE_GENERATOR: Visual Studio 14 2015
PlatformToolset: v140_xp
before_build:
- git submodule update --init --recursive
- ps: . $Env:APPVEYOR_BUILD_FOLDER/ci/appveyor/check_release.ps1
- ps: . $Env:APPVEYOR_BUILD_FOLDER/ci/appveyor/before_build.ps1
build_script:
- ps: . $Env:APPVEYOR_BUILD_FOLDER/ci/appveyor/build.ps1
test_script:
- ps: . $Env:APPVEYOR_BUILD_FOLDER/ci/appveyor/test.ps1
deploy:
- provider: GitHub
@@ -25,37 +26,15 @@ deploy:
on:
ReleaseBuild: true # deploy on release push only
- provider: FTP
protocol: sftp
host: scp.indiegames.us
username:
secure: SFivQZfatqWHXK1ijYK3GQ==
password:
secure: q6Zk/412o1ri+NEya1dl1Q==
folder: public_html/builds/nightly/$(VersionName)
- provider: BinTray
username: sirknightly
api_key:
secure: pYWqfiZhIWvFYdjVWPXNaHobmnkXIWa4+LwoiyMTEiu4Z0CiCAW0ZrMfTKVkORKz
subject: scp-fs2open
repo: FSO
package: nightly
version: $(VersionName)
publish: true
override: true
on:
NightlyBuild: true # deploy on nightly push only
- provider: FTP
protocol: ftp
host: swc.fs2downloads.com
username:
secure: EXg2ADoKzMduZF90ip2Q0g==
password:
secure: x0LL0uY9yBAQ7JTARhQ6AA==
folder: swc.fs2downloads.com/builds/nightly/$(VersionName)
beta: true
on:
NightlyBuild: true # deploy on nightly push only
- provider: FTP
protocol: ftp
host: swc.fs2downloads.com
username:
secure: EXg2ADoKzMduZF90ip2Q0g==
password:
secure: x0LL0uY9yBAQ7JTARhQ6AA==
folder: swc.fs2downloads.com/builds/test/$(VersionName)
beta: true
on:
TestBuild: true # deploy on test build push only
NightlyBuild: true # deploy on nightly push only
+5
View File
@@ -0,0 +1,5 @@
New-Item build -type directory
Set-Location -Path build
cmake -DCMAKE_INSTALL_PREFIX="$env:APPVEYOR_BUILD_FOLDER/../install" -DFSO_USE_SPEECH="ON" `
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS=SSE2 -G "$Env:CMAKE_GENERATOR" -T "$Env:PlatformToolset" ..
+7 -130
View File
@@ -1,133 +1,13 @@
class BuildConfig {
[string]$Generator
[string]$PackageType
[string]$Toolset
[string]$SimdType
[Bool]$SourcePackage
}
write "$env:DeployBuild"
write "$env:DeployConfig"
$NightlyConfigurations = @(
[BuildConfig]@{
Generator="Visual Studio 14 2015 Win64";
PackageType="Win64";
Toolset="v140_xp";
SimdType="SSE2";
SourcePackage=$false;
},
[BuildConfig]@{
Generator="Visual Studio 14 2015";
PackageType="Win32";
Toolset="v140_xp";
SimdType="SSE2";
SourcePackage=$false;
}
)
$ReleaseConfigurations = @(
[BuildConfig]@{
Generator="Visual Studio 14 2015";
PackageType="Win32";
Toolset="v140_xp";
SimdType="SSE2";
SourcePackage=$true;
}
[BuildConfig]@{
Generator="Visual Studio 14 2015";
PackageType="Win32-AVX";
Toolset="v140_xp";
SimdType="AVX";
SourcePackage=$false;
}
[BuildConfig]@{
Generator="Visual Studio 14 2015 Win64";
PackageType="Win64";
Toolset="v140_xp";
SimdType="SSE2";
SourcePackage=$false;
}
[BuildConfig]@{
Generator="Visual Studio 14 2015 Win64";
PackageType="Win64-AVX";
Toolset="v140_xp";
SimdType="AVX";
SourcePackage=$false;
}
)
$BuildConfigurations = $null
# Default values
$ReleaseBuild = $false
$NightlyBuild = $false
$TestBuild = $false
# Set to true to test either the release or the nightly part of this script
$ReleaseTest = $false
$NightlyTest = $false
$TestBuildTest = $false
if ($ReleaseTest -Or ([System.Convert]::ToBoolean($env:APPVEYOR_REPO_TAG) -And ("$env:APPVEYOR_REPO_TAG_NAME" -match "^release_(.*)"))) {
# Tag matches
$ReleaseBuild = $true
$PackageName = "fs2_open_$($matches[1])"
$BuildConfigurations = $ReleaseConfigurations
}
if ($NightlyTest -Or ([System.Convert]::ToBoolean($env:APPVEYOR_REPO_TAG) -And ("$env:APPVEYOR_REPO_TAG_NAME" -match "^nightly_(.*)"))) {
# Tag matches
$NightlyBuild = $true
$PackageName = "nightly_$($matches[1])"
Set-AppveyorBuildVariable 'VersionName' "$($matches[1])"
$BuildConfigurations = $NightlyConfigurations
}
if ($TestBuildTest -Or ([System.Convert]::ToInt32($env:APPVEYOR_PULL_REQUEST_NUMBER) -le 0 -And ("$env:APPVEYOR_REPO_BRANCH" -match "^test\/(.*)"))) {
# Tag matches
$TestBuild = $true
$PackageName = "test_$($matches[1])"
Set-AppveyorBuildVariable 'VersionName' "$($matches[1])"
$BuildConfigurations = $NightlyConfigurations
# Override the revision string so that the builds are named correctly
[System.IO.File]::WriteAllLines("$env:APPVEYOR_BUILD_FOLDER/version_override.cmake", "set(FSO_VERSION_REVISION_STR $env:VersionName)")
}
# Multiply by 2 so that we can add 0 or 1 for debug or release Configs
$buildID = [convert]::ToInt32($env:BuildID) * 2
if ($Env:Configuration -eq "Release") {
$buildID = $buildID + 1
}
$DeployBuild = $false
if ($ReleaseBuild -Or $NightlyBuild -Or $TestBuild) {
$DeployBuild = $true
}
Set-AppveyorBuildVariable 'ReleaseBuild' "$ReleaseBuild"
Set-AppveyorBuildVariable 'NightlyBuild' "$NightlyBuild"
Set-AppveyorBuildVariable 'TestBuild' "$TestBuild"
New-Item build -type directory
Set-Location -Path build
if ($DeployBuild) {
if ([System.Convert]::ToBoolean($env:DeployBuild)) {
# Release build
if ($buildID -ge $BuildConfigurations.Length) {
# Not needed
exit 0
if (![System.Convert]::ToBoolean($env:DeployConfig)) {
exit 0 # End the build
}
$buildConfig = $BuildConfigurations[$buildID]
if ($buildConfig.SourcePackage -eq $True) {
7z a -xr'!.git' "$($PackageName)-source-Win.zip" "$env:APPVEYOR_BUILD_FOLDER"
Push-AppveyorArtifact "$($PackageName)-source-Win.zip"
}
cmake -DCMAKE_INSTALL_PREFIX="$env:APPVEYOR_BUILD_FOLDER/../install" -DFSO_USE_SPEECH="ON" `
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS="$($buildConfig.SimdType)" `
-G "$($buildConfig.Generator)" -T "$($buildConfig.Toolset)" ..
$Configs = @("Release", "FastDebug")
foreach ($config in $Configs) {
cmake --build . --config "$config" --target INSTALL -- /verbosity:minimal
@@ -137,12 +17,9 @@ if ($DeployBuild) {
}
}
7z a "$($PackageName)-builds-$($buildConfig.PackageType).zip" "$env:APPVEYOR_BUILD_FOLDER/../install/*"
Push-AppveyorArtifact "$($PackageName)-builds-$($buildConfig.PackageType).zip"
7z a "$($env:PackageName)-builds-Win32.zip" "$env:APPVEYOR_BUILD_FOLDER/../install/*"
Push-AppveyorArtifact "$($env:PackageName)-builds-Win32.zip"
} else {
cmake -DFSO_USE_SPEECH="ON" -DFSO_FATAL_WARNINGS="ON" -DFSO_USE_VOICEREC="ON" -DFSO_BUILD_TESTS="ON" -DMSVC_SIMD_INSTRUCTIONS=SSE2 `
-G "$Env:CMAKE_GENERATOR" -T "$Env:PlatformToolset" ..
cmake --build . --config "$Env:CONFIGURATION" -- /verbosity:minimal
if (! ($?)) {
+30
View File
@@ -0,0 +1,30 @@
# Default values
Set-AppveyorBuildVariable 'ReleaseBuild' 'false'
Set-AppveyorBuildVariable 'NightlyBuild' 'false'
Set-AppveyorBuildVariable 'DeployBuild' 'false'
Set-AppveyorBuildVariable 'PackagePrefix' ''
Set-AppveyorBuildVariable 'VersionName' ''
if ([System.Convert]::ToBoolean($env:APPVEYOR_REPO_TAG) -And ("$env:APPVEYOR_REPO_TAG_NAME" -match "^release_(.*)")) {
# Tag matches
Set-AppveyorBuildVariable 'ReleaseBuild' 'true'
Set-AppveyorBuildVariable 'PackageName' "fs2_open_$($matches[1])"
}
if ([System.Convert]::ToBoolean($env:APPVEYOR_REPO_TAG) -And ("$env:APPVEYOR_REPO_TAG_NAME" -match "^nightly_(.*)")) {
# Tag matches
Set-AppveyorBuildVariable 'NightlyBuild' 'true'
Set-AppveyorBuildVariable 'PackageName' "nightly_$($matches[1])"
Set-AppveyorBuildVariable 'VersionName' "$($matches[1])"
}
if (($Env:Configuration -eq "Release") -And ($Env:VS_VERSION -eq "14")) {
Set-AppveyorBuildVariable 'DeployConfig' 'true'
} else {
Set-AppveyorBuildVariable 'DeployConfig' 'false'
}
if ([System.Convert]::ToBoolean($env:ReleaseBuild) -Or [System.Convert]::ToBoolean($env:NightlyBuild)) {
Set-AppveyorBuildVariable 'DeployBuild' 'true'
}
-13
View File
@@ -1,13 +0,0 @@
if ([System.Convert]::ToBoolean($env:ReleaseBuild) -Or [System.Convert]::ToBoolean($env:NightlyBuild) -Or [System.Convert]::ToBoolean($env:TestBuild)) {
# Skip tests for deployment
exit 0
} else {
write "Running unit tests..."
# Run unit tests
&"$pwd\bin\$Env:CONFIGURATION\unittests.exe" --gtest_shuffle 2>&1
if (! ($?)) {
exit 1
}
}
+6 -23
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env bash
#!/usr/bin/env sh
set -ex
@@ -6,38 +6,21 @@ 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"
if [[ "$CC" =~ ^clang.*$ ]]; then
CXXFLAGS="$CXXFLAGS -stdlib=libc++"
fi
export CXXFLAGS
export CFLAGS
export CXXFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas"
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" \
eval $CMAKE -DFSO_INSTALL_DEBUG_FILES=ON -DCMAKE_BUILD_TYPE=$config -DCMAKE_INSTALL_PREFIX="/tmp/release" \
-DFSO_BUILD_APPIMAGE=ON -DAPPIMAGE_ASSISTANT="$HOME/AppImageAssistant" \
-DFSO_BUILD_INCLUDED_LIBS=ON -DFFMPEG_USE_PRECOMPILED=ON ../..
-DFSO_BUILD_INCLUDED_LIBS=ON ../..
cd ..
done
else
eval $CMAKE -DCMAKE_BUILD_TYPE=$CONFIGURATION -DFSO_BUILD_TESTS=ON -DFSO_BUILD_INCLUDED_LIBS=ON ..
eval $CMAKE -DCMAKE_BUILD_TYPE=$CONFIGURATION ..
fi
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
if [ "$BUILD_DEPLOYMENT" = true ]; then
cmake -G "Xcode" -DFSO_FATAL_WARNINGS=ON -DFSO_INSTALL_DEBUG_FILES=ON -DCMAKE_INSTALL_PREFIX="/tmp/release" ..
else
cmake -G "Xcode" ..
fi
cmake -G "Xcode" -DFSO_FATAL_WARNINGS=ON -DFSO_INSTALL_DEBUG_FILES=ON -DCMAKE_INSTALL_PREFIX="/tmp/release" ..
fi
+6 -29
View File
@@ -2,8 +2,6 @@
RELEASE_BUILD=false
NIGHTLY_BUILD=false
TEST_BUILD=false
BUILD_DEPLOYMENT=false
BUILD_CONFIGS="Release FastDebug"
VERSION_NAME=""
@@ -11,45 +9,25 @@ PACKAGE_NAME=""
RELEASE_PATTERN="^release_(.*)$"
NIGHTLY_PATTERN="^nightly_(.*)$"
TEST_BUILD_PATTERN="^test\/(.*)$"
# These are for testing
NIGHTLY_TEST=false
RELEASE_TEST=false
TEST_BUILD_TEST=false
if [ "$RELEASE_TEST" = true ] || [[ "$TRAVIS_TAG" =~ $RELEASE_PATTERN ]]; then
if [[ "$TRAVIS_TAG" =~ $RELEASE_PATTERN ]]; then
echo "This is a release tag!";
RELEASE_BUILD=true;
PACKAGE_NAME="fs2_open_${BASH_REMATCH[1]}";
fi
if [ "$NIGHTLY_TEST" = true ] || [[ "$TRAVIS_TAG" =~ $NIGHTLY_PATTERN ]]; then
if [[ "$TRAVIS_TAG" =~ $NIGHTLY_PATTERN ]]; then
echo "This is a nightly tag!";
NIGHTLY_BUILD=true;
VERSION_NAME="${BASH_REMATCH[1]}";
VERSION_NAME="${BASH_REMATCH[1]}"
PACKAGE_NAME="nightly_${BASH_REMATCH[1]}";
fi
if [ "$TEST_BUILD_TEST" = true ] || [[ "$TRAVIS_PULL_REQUEST" == "false" && "$TRAVIS_BRANCH" =~ $TEST_BUILD_PATTERN ]]; then
echo "This is a test build branch!";
TEST_BUILD=true;
if [ "$TEST_BUILD_TEST" = true ]; then
VERSION_NAME="test";
PACKAGE_NAME="test_test";
else
VERSION_NAME="${BASH_REMATCH[1]}";
PACKAGE_NAME="test_${BASH_REMATCH[1]}";
fi
# Override the revision string so that the builds are named correctly
echo "set(FSO_VERSION_REVISION_STR $VERSION_NAME)" > "$TRAVIS_BUILD_DIR/version_override.cmake"
fi
if ([ "$RELEASE_BUILD" = true ] || [ "$NIGHTLY_BUILD" = true ] || [ "$TEST_BUILD" = true ]); then
if ([ "$RELEASE_BUILD" = true ] || [ "$NIGHTLY_BUILD" = true ]); then
BUILD_DEPLOYMENT=true;
fi
if [ "$BUILD_DEPLOYMENT" = true ]; then
if ([ "$TRAVIS_OS_NAME" = "linux" ] && (! [[ "$CC" =~ ^gcc.*$ ]])); then
if ([ "$TRAVIS_OS_NAME" = "linux" ] && [ "$CC" = "clang" ]); then
echo "Skipping non-release compiler";
exit 0;
fi
@@ -62,8 +40,7 @@ fi
export RELEASE_BUILD
export NIGHTLY_BUILD
export TEST_BUILD
export BUILD_DEPLOYMENT
export BUILD_CONFIGS
export VERSION_NAME
export PACKAGE_NAME
export PACKAGE_NAME
-54
View File
@@ -1,54 +0,0 @@
#!/usr/bin/env bash
set -e
set -u
if [[ ! "$(curl -V)" == *"sftp"* ]]; then
# Before
echo "Before:"
curl -V
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
# 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 ..
dpkg -l | grep curl
ls -al
sudo dpkg -i libcurl3*.deb
sudo dpkg -i curl*.deb
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
brew install curl --with-libssh2
export PATH="/usr/local/opt/curl/bin:$PATH"
fi
# After
echo "After:"
curl -V
fi
cd /tmp/builds
for file in *; do
if [ "$TEST_BUILD" = true ]; then
# Upload to fs2downloads
curl -k "ftp://swc.fs2downloads.com/swc.fs2downloads.com/builds/test/$VERSION_NAME/" --user "$FS2DOWNLOADS_USER:$FS2DOWNLOADS_PASSWORD" -T "$file" --ftp-create-dirs
else
# Upload to indiegames
curl -k "sftp://scp.indiegames.us/~/public_html/builds/nightly/$VERSION_NAME/" --user "$INDIEGAMES_USER:$INDIEGAMES_PASSWORD" -T "$file" --ftp-create-dirs
# Upload to fs2downloads
curl -k "ftp://swc.fs2downloads.com/swc.fs2downloads.com/builds/nightly/$VERSION_NAME/" --user "$FS2DOWNLOADS_USER:$FS2DOWNLOADS_PASSWORD" -T "$file" --ftp-create-dirs
fi
done
+1 -1
View File
@@ -22,7 +22,7 @@ if [ "$TRAVIS_OS_NAME" = "linux" ]; then
chmod a+x ./AppImageAssistant
fi
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
gem install xcpretty
gem install xcpretty xcpretty-travis-formatter thefox-pastebin
brew update
brew outdated cmake || brew upgrade cmake
+3 -3
View File
@@ -8,11 +8,11 @@ if [ "$TRAVIS_OS_NAME" = "linux" ]; then
for config in $BUILD_CONFIGS
do
cd "$config"
ninja appimage
ninja install appimage
cd ..
done
cp `find /tmp/release -name '*.AppImage' -print` /tmp/release
ls -al /tmp/release
(cd /tmp/release && tar -cvzf /tmp/builds/$PACKAGE_NAME-builds-Linux.tar.gz *.AppImage)
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
cd build
@@ -20,7 +20,7 @@ elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
for config in $BUILD_CONFIGS
do
cmake --build . --config "$config" --target install | tee build.log \
| xcpretty
| xcpretty -f `xcpretty-travis-formatter`
XCODE_RET=${PIPESTATUS[0]}
if [ "$XCODE_RET" -ne "0" ]; then
tar -cvzf build.log.tar.gz build.log
+3 -6
View File
@@ -5,16 +5,13 @@ set -e
cd build
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
ninja all
valgrind --leak-check=full --error-exitcode=1 --gen-suppressions=all \
--suppressions="$TRAVIS_BUILD_DIR/ci/travis/valgrind.supp" ./bin/unittests --gtest_shuffle
ninja
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
cmake --build . --config "$CONFIGURATION" | tee build.log | xcpretty
cmake --build . --config "$CONFIGURATION" | tee build.log | xcpretty -f `xcpretty-travis-formatter`
XCODE_RET=${PIPESTATUS[0]}
if [ "$XCODE_RET" -ne "0" ]; then
tar -cvzf build.log.tar.gz build.log
curl --upload-file build.log.tar.gz "https://transfer.sh/build.log.tar.gz"
exit $XCODE_RET
fi
fi
fi
-28
View File
@@ -1,28 +0,0 @@
{
liblsan Invalid read
Memcheck:Addr8
obj:/usr/lib64/liblsan.so.0.0.0
obj:/usr/lib64/liblsan.so.0.0.0
obj:/usr/lib64/liblsan.so.0.0.0
obj:*
obj:*
obj:*
}
{
Travis memleak
Memcheck:Leak
match-leak-kinds: definite
fun:malloc
fun:_dl_signal_error
fun:_dl_open
fun:dlopen_doit
fun:_dl_catch_error
fun:_dlerror_run
fun:dlopen@@GLIBC_2.2.5
obj:/usr/lib/x86_64-linux-gnu/libmirclient.so.7
fun:call_init.part.0
fun:call_init
fun:_dl_init
fun:dl_open_worker
fun:_dl_catch_error
}
+1 -1
View File
@@ -1,4 +1,4 @@
#!/bin/sh
HERE=$(dirname $(readlink -f "${0}"))
export LD_LIBRARY_PATH="${HERE}"/lib:"$LD_LIBRARY_PATH"
export LD_LIBRARY_PATH="${HERE}"/lib:$PATH
"${HERE}"/bin/$<TARGET_FILE_NAME:Freespace2> $@
-3
View File
@@ -1,9 +1,6 @@
include(WriteCompilerDetectionHeader)
set(CMAKE_CXX_STANDARD_REQUIRED 11)
set(CMAKE_CXX_STANDARD 11)
set(REQUIRED_CXX_FEATURES cxx_rvalue_references cxx_nullptr)
get_property(CMAKE_CXX_KNOWN_FEATURES GLOBAL PROPERTY CMAKE_CXX_KNOWN_FEATURES)
+1 -8
View File
@@ -27,7 +27,6 @@ int main( int argc, char* argv[] )
int SSE = false;
int SSE2 = false;
int AVX = false;
int AVX2 = false;
int info[4];
cpuid(info, 0);
@@ -41,14 +40,8 @@ int main( int argc, char* argv[] )
AVX = (info[2] & ((int)1 << 28)) != 0;
}
if (nIds >= 7){
cpuid(info,0x00000007);
AVX2 = (info[1] & ((int)1 << 5)) != 0;
}
if (AVX2)
std::cout << "AVX2";
else if(AVX)
if(AVX)
std::cout << "AVX";
else if(SSE2)
std::cout << "SSE2";
-26
View File
@@ -1,26 +0,0 @@
# Sample toolchain file for building for Windows from a Linux system.
#
# Typical usage:
# *) install cross compiler: `sudo apt-get install mingw-w64 g++-mingw-w64`
# *) cd build
# *) cmake -DCMAKE_TOOLCHAIN_FILE=~/Toolchain-Ubuntu-mingw64.cmake ..
set(CMAKE_SYSTEM_NAME Windows)
set(TOOLCHAIN_PREFIX x86_64-w64-mingw32)
# cross compilers to use for C and C++
set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc)
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++)
set(CMAKE_RC_COMPILER ${TOOLCHAIN_PREFIX}-windres)
# target environment on the build host system
# set 1st to dir with the cross compiler's C/C++ headers/libs
set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX})
# modify default behavior of FIND_XXX() commands to
# search for headers/libs in the target environment and
# don't search for programs in the build host environment
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
Vendored Submodule
+1
Submodule cmake/external/cotire added at 40a46bf2fb.
-4054
View File
File diff suppressed because it is too large. Load diff
+23 -6
View File
@@ -1,16 +1,33 @@
include(CheckIncludeFile)
add_library(speech INTERFACE)
if (WIN32)
CHECK_INCLUDE_FILE_CXX("sapi.h" HAVE_SAPI_H)
find_package(WindowsSDK REQUIRED)
foreach(dir ${WINDOWSSDK_DIRS})
get_windowssdk_library_dirs("${dir}" LIB_DIRS)
if (NOT HAVE_SAPI_H)
message(SEND_ERROR "sapi.h could not be found on your platform. Please disable speech support.")
find_library(SPEECH_LIBRARY
NAMES sapi
PATHS ${LIB_DIRS}
NO_DEFAULT_PATH)
if (SPEECH_LIBRARY)
set(SDK_DIR "${dir}")
break()
endif()
endforeach()
if (NOT SPEECH_LIBRARY)
message(SEND_ERROR "Text to speech library could not be found! Either install it or disable the speech option.")
return()
endif()
get_windowssdk_include_dirs("${SDK_DIR}" INCLUDE_DIRS)
target_include_directories(speech INTERFACE ${INCLUDE_DIRS})
else()
message(SEND_ERROR "Text to Speech is not supported on this platform!")
endif()
target_compile_definitions(speech INTERFACE -DFS2_SPEECH)
target_compile_definitions(speech INTERFACE -DFS2_SPEECH)
-9
View File
@@ -1,9 +0,0 @@
#ifndef __FREDRC_H
#define __FREDRC_H
#define ABOUT_LINE_1 "FRED2_OPEN - FreeSpace Editor, Version @FSO_PRODUCT_VERSION_STRING@ OpenGL"
#define MAINFRAME_CONTENTS "FRED2_OPEN @FSO_PRODUCT_VERSION_STRING@ - FreeSpace2 Mission Editor\nUntitled\nFRED2\nFreeSpace2 Missions (*.fs2)\n.fs2\nFreeSpace2Mission\nFreeSpace2 Mission"
#endif // __FREDRC_H
+1 -3
View File
@@ -1,7 +1,5 @@
include(Cxx11)
include(platformChecks)
include(Cxx11)
CONFIGURE_FILE(${CMAKE_CURRENT_LIST_DIR}/project.h.in ${GENERATED_SOURCE_DIR}/project.h)
CONFIGURE_FILE(${CMAKE_CURRENT_LIST_DIR}/fred_rc.h.in ${GENERATED_SOURCE_DIR}/fred_rc.h)
-6
View File
@@ -1,9 +1,3 @@
SET(BINARY_DESTINATION ".")
SET(LIBRAY_DESTINATION "${BINARY_DESTINATION}")
if (CMAKE_SIZEOF_VOID_P EQUAL 8)
set(IS_64BIT TRUE)
else()
set(IS_64BIT FALSE)
endif()
-23
View File
@@ -1,6 +1,5 @@
MESSAGE(STATUS "Doing Mac OSX specific things...")
target_compile_definitions(platform INTERFACE APPLE_APP)
SET(EXE_GUI_TYPE MACOSX_BUNDLE)
FIND_LIBRARY(COCOA_LIBRARY Cocoa)
@@ -10,25 +9,3 @@ if (NOT COCOA_LIBRARY)
endif()
target_link_libraries(platform INTERFACE ${COCOA_LIBRARY})
SET(CMAKE_OSX_DEPLOYMENT_TARGET "10.9")
SET(CMAKE_SKIP_RPATH FALSE)
SET(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
SET(CMAKE_INSTALL_RPATH @loader_path/../Frameworks/)
# Set the path where library dependencies are copied to
SET(LIBRAY_DESTINATION "../Frameworks")
set(PLATFORM_MAC TRUE CACHE INTERNAL "" FORCE)
# Generate and don't strip debug symbols
# These settings don't seem to generate debug symbols for code and Freespace2
# so those settings are set manually in code and Freespace2's CMakeLists.txt files
set(CMAKE_XCODE_ATTRIBUTE_GCC_GENERATE_DEBUGGING_SYMBOLS "YES")
set(CMAKE_XCODE_ATTRIBUTE_COPY_PHASE_STRIP "NO")
set(CMAKE_XCODE_ATTRIBUTE_STRIP_INSTALLED_PRODUCT "NO")
set(CMAKE_XCODE_ATTRIBUTE_GCC_SYMBOLS_PRIVATE_EXTERN "NO")
# Generate .dSYM file
set(CMAKE_XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT "dwarf-with-dsym")
+1 -1
View File
@@ -7,4 +7,4 @@ if (NOT EXECINFO_LIB)
message(FATAL_ERROR "Couldn't find libexecinfo! Please install it and rerun the configuration.")
else()
target_link_libraries(platform INTERFACE "${EXECINFO_LIB}")
endif()
endif()
-16
View File
@@ -1,18 +1,2 @@
target_compile_definitions(platform INTERFACE SCP_SOLARIS)
find_library(SOCKET_LIB socket)
if (NOT SOCKET_LIB)
message(FATAL_ERROR "Couldn't find libsocket! Please install it and rerun the configuration.")
else()
target_link_libraries(platform INTERFACE "${SOCKET_LIB}")
endif()
find_library(NSL_LIB nsl)
if (NOT NSL_LIB)
message(FATAL_ERROR "Couldn't find libnsl! Please install it and rerun the configuration.")
else()
target_link_libraries(platform INTERFACE "${NSL_LIB}")
endif()
-7
View File
@@ -4,10 +4,3 @@ INCLUDE(util)
MESSAGE(STATUS "Configuring UNIX specific things and stuff...")
target_compile_definitions(platform INTERFACE SCP_UNIX USE_OPENAL)
# Set RPATH
set(CMAKE_SKIP_BUILD_RPATH TRUE)
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
set(CMAKE_INSTALL_RPATH "\$ORIGIN")
set(PLATFORM_UNIX TRUE CACHE INTERNAL "" FORCE)
+9 -16
View File
@@ -1,27 +1,20 @@
MESSAGE(STATUS "Configuring Windows specific things and stuff...")
SET(WIN32_LIBS
comctl32
msacm32
odbc32
odbccp32
vfw32
winmm
wsock32
psapi
target_link_libraries(platform INTERFACE
comctl32.lib
msacm32.lib
odbc32.lib
odbccp32.lib
vfw32.lib
winmm.lib
wsock32.lib
Psapi.lib
)
IF (MINGW)
SET(WIN32_LIBS ${WIN32_LIBS} mingw32)
ENDIF (MINGW)
target_link_libraries(platform INTERFACE ${WIN32_LIBS})
target_compile_definitions(platform INTERFACE WIN32 USE_OPENAL _WINDOWS)
# Specify minimum Windows version for the headers (currently this is XP)
target_compile_definitions(platform INTERFACE NTDDI_VERSION=0x05010000 _WIN32_WINNT=0x0501)
SET(EXE_GUI_TYPE WIN32)
set(PLATFORM_WINDOWS TRUE CACHE INTERNAL "" FORCE)
-28
View File
@@ -7,39 +7,11 @@ include(CheckLibraryExists)
include(CheckPrototypeDefinition)
include(CheckStructHasMember)
include(CheckSymbolExists)
include(CheckCXXSymbolExists)
include(CheckTypeSize)
CHECK_INCLUDE_FILE("execinfo.h" HAVE_EXECINFO_H)
CHECK_INCLUDE_FILE_CXX("cxxabi.h" HAVE_CXXAPI_H)
CHECK_TYPE_SIZE("max_align_t" MAX_ALIGN_T)
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
set(CMAKE_REQUIRED_FLAGS "-std=c++11") # required for g++ <= 5
endif()
set(CMAKE_EXTRA_INCLUDE_FILES "cstddef")
CHECK_TYPE_SIZE("std::max_align_t" STD_MAX_ALIGN_T LANGUAGE CXX)
set(CMAKE_EXTRA_INCLUDE_FILES "type_traits")
CHECK_TYPE_SIZE("std::is_trivially_copyable<int>" STD_IS_TRIVIALLY_COPYABLE LANGUAGE CXX)
set(CMAKE_EXTRA_INCLUDE_FILES)
CHECK_TYPE_SIZE("char32_t" CHAR32_T LANGUAGE CXX)
CHECK_TYPE_SIZE("U'b'" UNICODE_CHAR_LITERAL LANGUAGE CXX)
set(CMAKE_REQUIRED_FLAGS)
CHECK_FUNCTION_EXISTS(strcasecmp HAVE_STRCASECMP)
CHECK_FUNCTION_EXISTS(strncasecmp HAVE_STRNCASECMP)
CHECK_FUNCTION_EXISTS(_stricmp HAVE__STRICMP)
CHECK_FUNCTION_EXISTS(_strnicmp HAVE__STRNICMP)
CHECK_FUNCTION_EXISTS(strlwr HAVE_STRLWR)
CHECK_INCLUDE_FILE("strings.h" HAVE_STRINGS_H)
set(PLATFORM_CHECK_HEADER "${GENERATED_SOURCE_DIR}/platformChecks.h")
CONFIGURE_FILE(${CMAKE_CURRENT_LIST_DIR}/platformChecks.h.in "${PLATFORM_CHECK_HEADER}")
-19
View File
@@ -5,24 +5,5 @@
#cmakedefine HAVE_EXECINFO_H
#cmakedefine HAVE_CXXAPI_H
#cmakedefine HAVE_MAX_ALIGN_T
#cmakedefine HAVE_STD_MAX_ALIGN_T
#cmakedefine HAVE_STD_IS_TRIVIALLY_COPYABLE
#cmakedefine HAVE_STD_IS_TRIVIALLY_COPYABLE_ARRAY
#cmakedefine01 IS_64BIT
#cmakedefine01 HAVE_STRCASECMP
#cmakedefine01 HAVE_STRNCASECMP
#cmakedefine01 HAVE__STRICMP
#cmakedefine01 HAVE__STRNICMP
#cmakedefine01 HAVE_STRLWR
#cmakedefine01 HAVE_STRINGS_H
#cmakedefine01 HAVE_CHAR32_T
#cmakedefine01 HAVE_UNICODE_CHAR_LITERAL
#endif // __PLATFORM_CHECKS_H__
+1 -8
View File
@@ -5,11 +5,6 @@ IF(FSO_CMAKE_DEBUG)
INCLUDE(debug-vars)
ENDIF(FSO_CMAKE_DEBUG)
set(PLATFORM_WINDOWS FALSE CACHE INTERNAL "" FORCE)
set(PLATFORM_UNIX FALSE CACHE INTERNAL "" FORCE)
set(PLATFORM_LINUX FALSE CACHE INTERNAL "" FORCE)
set(PLATFORM_MAC FALSE CACHE INTERNAL "" FORCE)
IF(WIN32)
INCLUDE(platform-win32)
ELSEIF(UNIX)
@@ -21,9 +16,7 @@ ELSEIF(UNIX)
INCLUDE(platform-solaris)
ELSEIF(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
include(platform-darwin)
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
set(PLATFORM_LINUX TRUE CACHE INTERNAL "" FORCE)
ENDIF()
ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
ELSE(WIN32)
MESSAGE(STATUS "This platform is not supported, good luck!")
ENDIF(WIN32)
+16 -64
View File
@@ -4,28 +4,16 @@ include(CheckCXXCompilerFlag)
MESSAGE(STATUS "Doing configuration specific to clang...")
option(CLANG_ENABLE_LEAK_CHECK "Enable -fsanitize=leak" OFF)
option(CLANG_ENABLE_ADDRESS_SANITIZER "Enable -fsanitize=address" OFF)
# These are the default values
set(C_BASE_FLAGS "-march=native -pipe")
set(CXX_BASE_FLAGS "-march=native -pipe")
# For C and C++, the values can be overwritten independently
unset(COMPILER_FLAGS)
if(DEFINED ENV{CXXFLAGS})
set(CXX_BASE_FLAGS $ENV{CXXFLAGS})
endif()
if(DEFINED ENV{CFLAGS})
set(C_BASE_FLAGS $ENV{CFLAGS})
set(COMPILER_FLAGS $ENV{CXXFLAGS})
endif()
# Initialize with an empty string to make sure we always get a clean start
set(COMPILER_FLAGS "")
# This is a slight hack since our flag setup is a bit more complicated
_enable_extra_compiler_warnings_flags()
set(COMPILER_FLAGS "${COMPILER_FLAGS} ${_flags}")
if(NOT COMPILER_FLAGS)
set(COMPILER_FLAGS "-march=native -pipe")
endif()
globally_enable_extra_compiler_warnings()
set(COMPILER_FLAGS "${COMPILER_FLAGS} -funroll-loops -fsigned-char -Wno-unknown-pragmas")
# Omit "argument unused during compilation" when clang is used with ccache.
@@ -38,40 +26,12 @@ if ("${CMAKE_GENERATOR}" STREQUAL "Ninja")
set(COMPILER_FLAGS "${COMPILER_FLAGS} -fdiagnostics-color")
endif()
# Start with an empty list
set(SANITIZE_FLAGS)
if(CLANG_ENABLE_ADDRESS_SANITIZER)
set(CMAKE_REQUIRED_FLAGS "-fsanitize=address")
CHECK_C_COMPILER_FLAG("-fsanitize=address" SUPPORTS_SANITIZE_ADDRESS)
if (SUPPORTS_SANITIZE_ADDRESS)
set(SANITIZE_FLAGS ${SANITIZE_FLAGS} "address")
endif()
endif()
if (CLANG_ENABLE_LEAK_CHECK)
check_linker_flag("-fsanitize=leak" SUPPORTS_FSANITIZE_LEAK)
if (SUPPORTS_FSANITIZE_LEAK)
set(SANITIZE_FLAGS ${SANITIZE_FLAGS} "leak")
endif()
endif()
string(REPLACE ";" "," SANITIZE_FLAGS "${SANITIZE_FLAGS}")
if (NOT "${SANITIZE_FLAGS}" STREQUAL "")
set(SANITIZE_FLAGS "-fsanitize=${SANITIZE_FLAGS}")
endif()
set(COMPILER_FLAGS "${COMPILER_FLAGS} ${SANITIZE_FLAGS}")
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wformat-security")
# Omit "deprecated conversion from string constant to 'char*'" warnings.
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wno-write-strings")
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-deprecated -Wno-char-subscripts")
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wno-unused-parameter")
@@ -84,9 +44,13 @@ set(COMPILER_FLAGS_RELEASE "-O2 -Wno-unused-variable")
set(COMPILER_FLAGS_DEBUG "-O0 -g -Wshadow")
# Always use the base flags and add our compiler flags at the bacl
set(CMAKE_CXX_FLAGS "${CXX_BASE_FLAGS} ${COMPILER_FLAGS}")
set(CMAKE_C_FLAGS "${C_BASE_FLAGS} ${COMPILER_FLAGS}")
if (FSO_FATAL_WARNINGS)
# Make warnings fatal if the right variable is set
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Werror")
endif()
set(CMAKE_CXX_FLAGS ${COMPILER_FLAGS})
set(CMAKE_C_FLAGS ${COMPILER_FLAGS})
set(CMAKE_CXX_FLAGS_RELEASE ${COMPILER_FLAGS_RELEASE})
set(CMAKE_C_FLAGS_RELEASE ${COMPILER_FLAGS_RELEASE})
@@ -97,17 +61,5 @@ set(CMAKE_C_FLAGS_DEBUG ${COMPILER_FLAGS_DEBUG})
set(CMAKE_EXE_LINKER_FLAGS "")
if (SANITIZE_FLAGS)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${SANITIZE_FLAGS}")
endif()
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "")
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "-g -rdynamic")
if (FSO_FATAL_WARNINGS)
# Make warnings fatal if the right variable is set
target_compile_options(compiler INTERFACE "-Werror")
endif()
# Always define this to make sure that the fixed width format macros are available
target_compile_definitions(compiler INTERFACE __STDC_FORMAT_MACROS)
+22 -83
View File
@@ -5,35 +5,20 @@ include(util)
MESSAGE(STATUS "Doing configuration specific to gcc...")
option(GCC_ENABLE_LEAK_CHECK "Enable -fsanitize=leak" OFF)
option(GCC_ENABLE_ADDRESS_SANITIZER "Enable -fsanitize=address" OFF)
option(GCC_ENABLE_SANITIZE_UNDEFINED "Enable -fsanitize=undefined" OFF)
option(GCC_ENABLE_LEAK_CHECK "Enable the -fsanitize=leak" OFF)
# These are the default values
set(C_BASE_FLAGS "-march=native -pipe")
set(CXX_BASE_FLAGS "-march=native -pipe")
# For C and C++, the values can be overwritten independently
if(DEFINED ENV{CFLAGS})
set(C_BASE_FLAGS $ENV{CFLAGS})
endif()
unset(COMPILER_FLAGS)
if(DEFINED ENV{CXXFLAGS})
set(CXX_BASE_FLAGS $ENV{CXXFLAGS})
set(COMPILER_FLAGS $ENV{CXXFLAGS})
endif()
# Initialize with an empty string to make sure we always get a clean start
set(COMPILER_FLAGS "")
# This is a slight hack since our flag setup is a bit more complicated
_enable_extra_compiler_warnings_flags()
set(COMPILER_FLAGS "${COMPILER_FLAGS} ${_flags}")
if(NOT COMPILER_FLAGS)
set(COMPILER_FLAGS "-march=native -pipe")
endif()
globally_enable_extra_compiler_warnings()
set(COMPILER_FLAGS "${COMPILER_FLAGS} -funroll-loops -fsigned-char -Wno-unknown-pragmas")
# Place each function and data in its own section so the linker can
# perform dead code elimination
set(COMPILER_FLAGS "${COMPILER_FLAGS} -fdata-sections -ffunction-sections")
if ("${CMAKE_GENERATOR}" STREQUAL "Ninja")
# Force color diagnostics for Ninja generator
CHECK_C_COMPILER_FLAG(-fdiagnostics-color SUPPORTS_DIAGNOSTIC_COLOR)
@@ -43,46 +28,11 @@ if ("${CMAKE_GENERATOR}" STREQUAL "Ninja")
endif()
endif()
# Start with an empty list
set(SANITIZE_FLAGS)
if(GCC_ENABLE_ADDRESS_SANITIZER)
set(CMAKE_REQUIRED_FLAGS "-fsanitize=address")
CHECK_C_COMPILER_FLAG("-fsanitize=address" SUPPORTS_SANITIZE_ADDRESS)
if (SUPPORTS_SANITIZE_ADDRESS)
set(SANITIZE_FLAGS ${SANITIZE_FLAGS} "address")
endif()
endif()
if (GCC_ENABLE_LEAK_CHECK)
check_linker_flag("-fsanitize=leak" SUPPORTS_FSANITIZE_LEAK)
if (SUPPORTS_FSANITIZE_LEAK)
set(SANITIZE_FLAGS ${SANITIZE_FLAGS} "leak")
endif()
endif()
if (GCC_ENABLE_SANITIZE_UNDEFINED)
check_linker_flag("-fsanitize=undefined" SUPPORTS_SANITIZE_UNDEFINED)
if (SUPPORTS_SANITIZE_UNDEFINED)
set(SANITIZE_FLAGS ${SANITIZE_FLAGS} "undefined")
endif()
endif()
string(REPLACE ";" "," SANITIZE_FLAGS "${SANITIZE_FLAGS}")
if (NOT "${SANITIZE_FLAGS}" STREQUAL "")
set(SANITIZE_FLAGS "-fsanitize=${SANITIZE_FLAGS}")
endif()
set(COMPILER_FLAGS "${COMPILER_FLAGS} ${SANITIZE_FLAGS}")
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wformat-security")
# Omit "deprecated conversion from string constant to 'char*'" warnings.
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wno-write-strings")
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")
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wno-unused-parameter")
@@ -91,9 +41,13 @@ set(COMPILER_FLAGS_RELEASE "-O2 -Wno-unused-variable -Wno-unused-but-set-variabl
set(COMPILER_FLAGS_DEBUG "-O0 -g -Wshadow")
# Always use the base flags and add our compiler flags at the bacl
set(CMAKE_CXX_FLAGS "${CXX_BASE_FLAGS} ${COMPILER_FLAGS}")
set(CMAKE_C_FLAGS "${C_BASE_FLAGS} ${COMPILER_FLAGS}")
if (FSO_FATAL_WARNINGS)
# Make warnings fatal if the right variable is set
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Werror")
endif()
set(CMAKE_CXX_FLAGS ${COMPILER_FLAGS})
set(CMAKE_C_FLAGS ${COMPILER_FLAGS})
set(CMAKE_CXX_FLAGS_RELEASE ${COMPILER_FLAGS_RELEASE})
set(CMAKE_C_FLAGS_RELEASE ${COMPILER_FLAGS_RELEASE})
@@ -103,32 +57,17 @@ set(CMAKE_C_FLAGS_DEBUG ${COMPILER_FLAGS_DEBUG})
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")
ENDIF(MINGW)
if (GCC_ENABLE_LEAK_CHECK)
check_linker_flag("-fsanitize=leak" SUPPORTS_FSANITIZE_LEAK)
if (SANITIZE_FLAGS)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${SANITIZE_FLAGS}")
if (SUPPORTS_FSANITIZE_LEAK)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=leak")
endif()
endif()
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "")
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "-g")
IF(NOT MINGW)
SET(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -rdynamic")
# Allow the linker to perform dead code elimination; this is considered
# experimental for COFF and PE formats and thus disabled for Windows builds
# (https://sourceware.org/binutils/docs/ld/Options.html)
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections")
ENDIF(NOT MINGW)
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "-g -rdynamic")
IF(${CMAKE_SYSTEM_NAME} MATCHES "SunOS")
SET(CMAKE_EXE_LINKER_FLAGS "-Wl,-zignore")
ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "SunOS")
if (FSO_FATAL_WARNINGS)
# Make warnings fatal if the right variable is set
target_compile_options(compiler INTERFACE "-Werror")
endif()
# Always define this to make sure that the fixed width format macros are available
target_compile_definitions(compiler INTERFACE __STDC_FORMAT_MACROS)
+27 -41
View File
@@ -8,41 +8,36 @@ MESSAGE(STATUS "Doing configuration specific to visual studio...")
set_property(GLOBAL PROPERTY DEBUG_CONFIGURATIONS Debug)
option(MSVC_USE_RUNTIME_DLL "Use the dynamically linked version of the runtime" OFF)
option(MSVC_RELEASE_DEBUGGING "Set options that allow to debug release builds" OFF)
MARK_AS_ADVANCED(FORCE MSVC_USE_RUNTIME_DLL)
MARK_AS_ADVANCED(FORCE MSVC_RELEASE_DEBUGGING)
# These are the warnings we disable
set(WARNING_FLAGS
/wd4100 # unreferenced formal parameters
/wd4127 # constant conditional (assert)
/wd4201 # nonstandard extension used: nameless struct/union (happens a lot in Windows include headers)
/wd4290 # C++ exception specification ignored except to indicate a function is not __declspec(nothrow)
/wd4390 # empty control statement (triggered by nprintf and mprintf's inside of one-line if's, etc)
/wd4410 # illegal size for operand... ie... fxch st(1)
/wd4511 # copy constructor could not be generated (happens a lot in Windows include headers)
/wd4512 # assignment operator could not be generated (happens a lot in Windows include headers)
/wd4514 # unreferenced inline function removed
/wd4611 # _setjmp warning. Since we use setjmp alot, and we don't really use constructors or destructors, this warning doesn't really apply to us.
/wd4663 # C++ language change (template specification)
/wd4710 # is inline function not expanded (who cares?)
/wd4711 # tells us an inline function was expanded (who cares?)
/wd4786 # is identifier truncated to 255 characters (happens all the time in Microsoft #includes) -- Goober5000"
/wd4996 # deprecated strcpy, strcat, sprintf, etc. (from MSVC 2005) - taylor
/wd4311 # Disables warnings about casting pointer types to ints. The funny thing is these warnings can't be resolved, just disabled... - m!m
/wd4302 # Same as above - m!m
/wd4366 # The result of the unary '&' operator may be unaligned - m!m
/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
/wd"4100" # unreferenced formal parameters
/wd"4127" # constant conditional (assert)
/wd"4201" # nonstandard extension used: nameless struct/union (happens a lot in Windows include headers)
/wd"4290" # C++ exception specification ignored except to indicate a function is not __declspec(nothrow)
/wd"4390" # empty control statement (triggered by nprintf and mprintf's inside of one-line if's, etc)
/wd"4410" # illegal size for operand... ie... fxch st(1)
/wd"4511" # copy constructor could not be generated (happens a lot in Windows include headers)
/wd"4512" # assignment operator could not be generated (happens a lot in Windows include headers)
/wd"4514" # unreferenced inline function removed
/wd"4611" # _setjmp warning. Since we use setjmp alot, and we don't really use constructors or destructors, this warning doesn't really apply to us.
/wd"4663" # C++ language change (template specification)
/wd"4710" # is inline function not expanded (who cares?)
/wd"4711" # tells us an inline function was expanded (who cares?)
/wd"4786" # is identifier truncated to 255 characters (happens all the time in Microsoft #includes) -- Goober5000"
/wd"4996" # deprecated strcpy, strcat, sprintf, etc. (from MSVC 2005) - taylor
/wd"4311" # Disables warnings about casting pointer types to ints. The funny thing is these warnings can't be resolved, just disabled... - m!m
/wd"4302" # Same as above - m!m
/wd"4366" # The result of the unary '&' operator may be unaligned - m!m
$<$<CONFIG:Release>:/wd"4101"> # In release mode there are unreferenced variables because debug needs them
)
target_compile_options(compiler INTERFACE ${WARNING_FLAGS})
# Base
set(CMAKE_C_FLAGS "/MP /GS- /analyze- /Zc:wchar_t /errorReport:prompt /WX- /Zc:forScope /Gd /EHsc /nologo /Zm200")
set(CMAKE_CXX_FLAGS "/MP /GS- /analyze- /Zc:wchar_t /errorReport:prompt /WX- /Zc:forScope /Gd /EHsc /nologo /Zm200")
set(CMAKE_C_FLAGS "/MP /GS- /analyze- /Zc:wchar_t /errorReport:prompt /WX- /Zc:forScope /Gd /EHsc /nologo")
set(CMAKE_CXX_FLAGS "/MP /GS- /analyze- /Zc:wchar_t /errorReport:prompt /WX- /Zc:forScope /Gd /EHsc /nologo")
set(CMAKE_EXE_LINKER_FLAGS "/MANIFEST /DYNAMICBASE:NO /SAFESEH:NO /ERRORREPORT:PROMPT /NOLOGO")
set(CMAKE_STATIC_LINKER_FLAGS "")
@@ -55,15 +50,11 @@ set(CMAKE_STATIC_LINKER_FLAGS_RELEASE "/LTCG")
globally_enable_extra_compiler_warnings()
if (MSVC_RELEASE_DEBUGGING)
CHECK_CXX_COMPILER_FLAG("/Zo" MSVC_COMPILER_SUPPORTS_ARCH_ZO)
CHECK_CXX_COMPILER_FLAG("/Zo" MSVC_COMPILER_SUPPORTS_ARCH_ZO)
if (MSVC_COMPILER_SUPPORTS_ARCH_ZO)
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /Zo")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Zo")
endif()
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /DEBUG")
if (MSVC_COMPILER_SUPPORTS_ARCH_ZO)
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /Zo")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Zo")
endif()
IF(MSVC_USE_RUNTIME_DLL)
@@ -90,7 +81,7 @@ ENDIF(MSVC_USE_RUNTIME_DLL)
INCLUDE(MSVCMultipleProcessCompile)
# Visual Studio supports compiling for multiple vector instruction sets
SET(POSSIBLE_INSTUCTION_SETS "" SSE SSE2 AVX AVX2)
SET(POSSIBLE_INSTUCTION_SETS "" SSE SSE2 AVX)
if (NOT DEFINED MSVC_SIMD_INSTRUCTIONS)
detect_simd_instructions(MSVC_DETECTED_SIMD_INSTRUCTIONS)
@@ -136,9 +127,4 @@ else()
endif()
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")
endif()
_CRT_SECURE_NO_WARNINGS _SECURE_SCL=0 NOMINMAX)
+2 -2
View File
@@ -20,7 +20,7 @@ ENDIF("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
# Copy release settings to FastDebug
set(CMAKE_C_FLAGS_FASTDEBUG "${CMAKE_C_FLAGS_RELEASE}")
set(CMAKE_CXX_FLAGS_FASTDEBUG "${CMAKE_CXX_FLAGS_RELEASE}")
set(CMAKE_EXE_LINKER_FLAGS_FASTDEBUG "${CMAKE_EXE_LINKER_FLAGS_RELEASE}")
set(CMAKE_EXE_LINKER_FLAGS_FASTDEBUG "${CMAKE_EXE_LINKER_RELEASE}")
set(CMAKE_STATIC_LINKER_FLAGS_FASTDEBUG "${CMAKE_STATIC_LINKER_FLAGS_RELEASE}")
if (MSVC)
@@ -30,4 +30,4 @@ if (MSVC)
string(REPLACE "/MD" "/MDd" CMAKE_CXX_FLAGS_FASTDEBUG "${CMAKE_CXX_FLAGS_FASTDEBUG}")
string(REPLACE "/MT" "/MTd" CMAKE_CXX_FLAGS_FASTDEBUG "${CMAKE_CXX_FLAGS_FASTDEBUG}")
endif()
endif()
+21 -49
View File
@@ -66,33 +66,13 @@ ENDIF(EXISTS \"${CMAKE_CURRENT_BINARY_DIR}/${TARGET}/${FILE}\")
SET(${OUTVAR} "${CMAKE_COMMAND}" -P ${CMAKE_CURRENT_BINARY_DIR}/${TARGET}/${NAME} PARENT_SCOPE)
ENDFUNCTION(EP_CHECK_FILE_EXISTS)
MACRO(COPY_FILE_TO_TARGET _target _file)
if(UNIX)
ADD_CUSTOM_COMMAND(
TARGET ${_target} POST_BUILD
COMMAND cp -a "${_file}" "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/"
COMMENT "copying '${_file}'..."
)
else()
ADD_CUSTOM_COMMAND(
TARGET ${_target} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${_file}" "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/"
COMMENT "copying '${_file}'..."
)
endif()
endmacro(COPY_FILE_TO_TARGET)
MACRO(COPY_FILES_TO_TARGET _target)
if(UNIX)
FOREACH(file IN LISTS TARGET_COPY_FILES)
ADD_CUSTOM_COMMAND(
TARGET ${_target} POST_BUILD
COMMAND mkdir -p "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/"
COMMENT "Creating '$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/'..."
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${file}" "$<TARGET_FILE_DIR:${_target}>"
COMMENT "copying '${file}'..."
)
endif()
FOREACH(file IN LISTS TARGET_COPY_FILES)
COPY_FILE_TO_TARGET("${_target}" "${file}")
ENDFOREACH(file)
ENDMACRO(COPY_FILES_TO_TARGET)
@@ -116,7 +96,7 @@ function(CONVERT_OLD_LIBRARIES)
else("${lib}" STREQUAL "debug")
# Expecting normal library
if(is_debug)
list(APPEND out_list "$<$<CONFIG:Debug>:${lib}>" "$<$<CONFIG:FastDebug>:${lib}>")
list(APPEND out_list "$<$<CONFIG:Debug>:${lib}>")
elseif(is_optimized)
list(APPEND out_list "$<$<CONFIG:Release>:${lib}>")
else(is_debug)
@@ -141,26 +121,28 @@ macro(set_if_not_defined VAR VALUE)
endmacro(set_if_not_defined)
macro(configure_cotire target)
# Disable unity build as it doesn't work well for us
set_target_properties(${target} PROPERTIES COTIRE_ADD_UNITY_BUILD FALSE)
IF(COTIRE_ENABLE)
# Disable unity build as it doesn't work well for us
set_target_properties(${target} PROPERTIES COTIRE_ADD_UNITY_BUILD FALSE)
cotire(${target})
# add ignored paths for the precompiled header here
set_target_properties(code PROPERTIES COTIRE_PREFIX_HEADER_IGNORE_PATH
"${CMAKE_SOURCE_DIR};${CMAKE_BINARY_DIR}")
IF(DEFINED CMAKE_CONFIGURATION_TYPES)
cotire(${target} CONFIGURATIONS ${CMAKE_CONFIGURATION_TYPES})
ELSE(DEFINED CMAKE_CONFIGURATION_TYPES)
cotire(${target})
ENDIF(DEFINED CMAKE_CONFIGURATION_TYPES)
ENDIF(COTIRE_ENABLE)
endmacro(configure_cotire)
macro(add_target_copy_files)
foreach(file ${ARGN})
if (IS_DIRECTORY "${file}")
INSTALL(DIRECTORY ${file}
DESTINATION ${LIBRAY_DESTINATION}
)
else()
INSTALL(FILES ${file}
DESTINATION ${LIBRAY_DESTINATION}
)
endif()
INSTALL(FILES ${ARGN}
DESTINATION ${BINARY_DESTINATION}
)
SET(TARGET_COPY_FILES ${TARGET_COPY_FILES} ${file} CACHE INTERNAL "" FORCE)
endforeach()
SET(TARGET_COPY_FILES ${TARGET_COPY_FILES} ${ARGN} CACHE INTERNAL "" FORCE)
endmacro(add_target_copy_files)
function(detect_simd_instructions _out_var)
@@ -185,13 +167,3 @@ function (check_linker_flag _flag _out_var)
SET(CMAKE_REQUIRED_FLAGS "${_flag}")
CHECK_C_COMPILER_FLAG("" ${_out_var})
endfunction(check_linker_flag)
# Suppresses warnings for the specified target
function(suppress_warnings _target)
if (MSVC)
target_compile_options(${_target} PRIVATE "/W0")
else()
# Assume everything else uses GCC style options
target_compile_options(${_target} PRIVATE "-w")
endif()
endfunction(suppress_warnings)
+3 -3
View File
@@ -7,8 +7,8 @@ if (EXISTS "${PROJECT_SOURCE_DIR}/version_override.cmake")
endif()
set_if_not_defined(FSO_VERSION_MAJOR 3)
set_if_not_defined(FSO_VERSION_MINOR 8)
set_if_not_defined(FSO_VERSION_BUILD 1)
set_if_not_defined(FSO_VERSION_MINOR 7)
set_if_not_defined(FSO_VERSION_BUILD 5)
# A numeric revision e.g. the CI build number
set_if_not_defined(FSO_VERSION_REVISION 0)
@@ -35,7 +35,7 @@ ELSE()
SET(FSO_BINARY_SUFFIX "${FSO_VERSION_MAJOR}_${FSO_VERSION_MINOR}_${FSO_VERSION_BUILD}_${FSO_VERSION_REVISION_STR}")
ENDIF()
IF(IS_64BIT)
IF(CMAKE_SIZEOF_VOID_P EQUAL 8)
# This is a 64-bit builds
SET(FSO_BINARY_SUFFIX "${FSO_BINARY_SUFFIX}_x64")
ENDIF()
+6 -17
View File
@@ -19,33 +19,28 @@ TARGET_INCLUDE_DIRECTORIES(code PUBLIC ${FREESPACE_HEADERS})
TARGET_INCLUDE_DIRECTORIES(code PUBLIC ${GENERATED_SOURCE_DIR})
TARGET_INCLUDE_DIRECTORIES(code PUBLIC ${GENERATED_SOURCE_DIR}/code)
target_link_libraries(code PUBLIC OpenGL)
target_link_libraries(code PUBLIC gl_12)
TARGET_LINK_LIBRARIES(code PUBLIC openal)
TARGET_LINK_LIBRARIES(code PUBLIC ${OPENAL_LIBS})
TARGET_LINK_LIBRARIES(code PUBLIC ${LUA_LIBS})
TARGET_LINK_LIBRARIES(code PUBLIC ${PNG_LIBS})
TARGET_LINK_LIBRARIES(code PUBLIC ${JPEG_LIBS})
TARGET_LINK_LIBRARIES(code PUBLIC sdl2)
TARGET_LINK_LIBRARIES(code PUBLIC oggvorbis)
TARGET_LINK_LIBRARIES(code PUBLIC ffmpeg)
TARGET_LINK_LIBRARIES(code PUBLIC utfcpp)
TARGET_LINK_LIBRARIES(code PUBLIC ${SDL_LIBS})
TARGET_LINK_LIBRARIES(code PUBLIC platform)
TARGET_LINK_LIBRARIES(code PUBLIC compiler)
target_link_libraries(code PUBLIC md5)
IF (FSO_USE_SPEECH)
find_package(Speech REQUIRED)
target_link_libraries(code PUBLIC speech)
ENDIF(FSO_USE_SPEECH)
TARGET_LINK_LIBRARIES(code PUBLIC jansson)
# Headers for standalone "gui" on UNIX
IF(UNIX)
TARGET_LINK_LIBRARIES(code PUBLIC jansson)
TARGET_LINK_LIBRARIES(code PUBLIC ${MONGOOSE_LIBS})
ENDIF(UNIX)
@@ -55,13 +50,7 @@ IF(FSO_BUILD_TOOLS)
ADD_SUBDIRECTORY(cfileextractor)
ENDIF(FSO_BUILD_TOOLS)
set_target_properties(code PROPERTIES COTIRE_CXX_PREFIX_HEADER_INIT "prefix_header.h")
include(util)
configure_cotire(code)
# Ensure that Xcode generates debug symbols on macOS for Debug builds
set_target_properties(code PROPERTIES XCODE_ATTRIBUTE_GCC_GENERATE_DEBUGGING_SYMBOLS[variant=Debug] "YES")
set_target_properties(code PROPERTIES XCODE_ATTRIBUTE_COPY_PHASE_STRIP[variant=Debug] "NO")
set_target_properties(code PROPERTIES XCODE_ATTRIBUTE_STRIP_INSTALLED_PRODUCT[variant=Debug] "NO")
set_target_properties(code PROPERTIES XCODE_ATTRIBUTE_GCC_SYMBOLS_PRIVATE_EXTERN[variant=Debug] "NO")
include(../cmake/Cxx11.cmake)
+73 -13
View File
@@ -18,9 +18,8 @@
#include "globalincs/systemvars.h"
#include "object/waypoint.h"
#include "physics/physics.h"
#include "ship/ship_flags.h"
class ship_weapon;
struct ship_weapon;
class ship_subsys;
class object;
class ship_info;
@@ -28,13 +27,48 @@ class ship_info;
#define AI_DEFAULT_CLASS 3 // default AI class for new ships (Fred)
typedef struct ai_flag_name {
AI::AI_Flags flag;
int flag;
char flag_name[TOKEN_LENGTH];
int flag_list;
} ai_flag_name;
#define MAX_AI_FLAG_NAMES 2
extern ai_flag_name Ai_flag_names[];
#define AIF_FORMATION_WING (1 << 0) // Fly in formation as part of wing.
#define AIF_AWAITING_REPAIR (1 << 1) // Awaiting a repair ship.
#define AIF_BEING_REPAIRED (1 << 2) // Currently docked with repair ship.
#define AIF_REPAIRING (1 << 3) // Repairing a ship (or going to repair a ship)
#define AIF_SEEK_LOCK (1 << 4) // set if should focus on gaining aspect lock, not hitting with lasers
#define AIF_FORMATION_OBJECT (1 << 5) // Fly in formation off a specific object.
#define AIF_TEMPORARY_IGNORE (1 << 6) // Means current ignore_objnum is only temporary, not an order from the player.
#define AIF_USE_EXIT_PATH (1 << 7) // Used by path code, to flag path as an exit path
#define AIF_USE_STATIC_PATH (1 << 8) // Used by path code, use fixed path, don't try to recreate
#define AIF_TARGET_COLLISION (1 << 9) // Collided with aip->target_objnum last frame. Avoid that ship for half a second or so.
#define AIF_UNLOAD_SECONDARIES (1 << 10) // Fire secondaries as fast as possible!
#define AIF_ON_SUBSYS_PATH (1 << 11) // Current path leads to a subsystem
#define AIF_AVOID_SHOCKWAVE_SHIP (1 << 12) // Avoid an existing shockwave from a ship.
#define AIF_AVOID_SHOCKWAVE_WEAPON (1 << 13) // Avoid an expected shockwave from a weapon. shockwave_object field contains object index.
#define AIF_AVOID_SHOCKWAVE_STARTED (1 << 14) // Already started avoiding shockwave, don't keep deciding whether to avoid.
#define AIF_ATTACK_SLOWLY (1 << 15) // Move slowly while attacking.
#define AIF_REPAIR_OBSTRUCTED (1 << 16) // Ship wants to be repaired, but path is obstructed.
#define AIF_KAMIKAZE (1 << 17) // Crash into target
#define AIF_NO_DYNAMIC (1 << 18) // Not allowed to get dynamic goals
#define AIF_AVOIDING_SMALL_SHIP (1 << 19) // Avoiding a player ship.
#define AIF_AVOIDING_BIG_SHIP (1 << 20) // Avoiding a large ship.
#define AIF_BIG_SHIP_COLLIDE_RECOVER_1 (1 << 21) // Collided into a big ship. Recovering by flying away.
#define AIF_BIG_SHIP_COLLIDE_RECOVER_2 (1 << 22) // Collided into a big ship. Fly towards big ship sphere perimeter.
#define AIF_STEALTH_PURSUIT (1 << 23) // AI is trying to fight stealth ship
// Goober5000
#define AIF_UNLOAD_PRIMARIES (1 << 24) // Fire primaries as fast as possible!
#define AIF_TRYING_UNSUCCESSFULLY_TO_WARP (1 << 25) // Trying to warp, but can't warp at the moment
#define AIF_FREE_AFTERBURNER_USE (1 << 26) // Use afterburners while following waypoints or flying towards objects
#define AIF_AVOID_SHOCKWAVE (AIF_AVOID_SHOCKWAVE_SHIP | AIF_AVOID_SHOCKWAVE_WEAPON)
#define AIF_FORMATION (AIF_FORMATION_WING | AIF_FORMATION_OBJECT)
// dock_orient_and_approach() modes.
#define DOA_APPROACH 1 // Approach the current point on the path (aip->path_cur)
#define DOA_DOCK 2 // Dock with goal object.
@@ -66,6 +100,19 @@ extern ai_flag_name Ai_flag_names[];
#define AIG_TYPE_PLAYER_WING 4 // from player direct to wing
#define AIG_TYPE_DYNAMIC 5 // created on the fly
// flags for AI_GOALS
#define AIGF_DOCKER_INDEX_VALID (1<<0) // when set, index field for docker is valid
#define AIGF_DOCKEE_INDEX_VALID (1<<1) // when set, index field for dockee is valid
#define AIGF_GOAL_ON_HOLD (1<<2) // when set, this goal cannot currently be satisfied, although it could be in the future
#define AIGF_SUBSYS_NEEDS_FIXUP (1<<3) // when set, the subsystem index (for a destroy subsystem goal) is invalid and must be gotten from the subsys name stored in docker.name field!!
#define AIGF_GOAL_OVERRIDE (1<<4) // paired with AIG_TYPE_DYNAMIC to mean this goal overrides any other goal
#define AIGF_PURGE (1<<5) // purge this goal next time we process
#define AIGF_GOALS_PURGED (1<<6) // this goal has already caused other goals to get purged
#define AIGF_DEPART_SOUND_PLAYED (1<<7) // Goober5000 - replacement for AL's hack ;)
#define AIGF_TARGET_OWN_TEAM (1<<8) // Goober5000 - removes standard precautions against AI ships taking traitorous actions
#define AIGF_DOCK_INDEXES_VALID (AIGF_DOCKER_INDEX_VALID|AIGF_DOCKEE_INDEX_VALID)
// Flags to ai_turn_towards_vector().
#define AITTV_FAST (1<<0) // Turn fast, not slowed down based on skill level.
#define AITTV_VIA_SEXP (1<<1) // Goober5000 - via sexp
@@ -73,13 +120,23 @@ extern ai_flag_name Ai_flag_names[];
#define KAMIKAZE_HULL_ON_DEATH -1000.0f // Hull strength ship gets set to if it crash-dies.
// flags for possible ai overrides
#define AIORF_FULL (1<<0) // Full sexp control
#define AIORF_ROLL (1<<1) // Sexp forced roll maneuver
#define AIORF_PITCH (1<<2) // Sexp forced pitch change
#define AIORF_HEADING (1<<3) // Sexp forced heading change
#define AIORF_FULL_LAT (1<<4) // full control over up/side/forward movement
#define AIORF_UP (1<<5) // vertical movement
#define AIORF_SIDEWAYS (1<<6) // horizontal movement
#define AIORF_FORWARD (1<<7) // forward movement
// structure for AI goals
typedef struct ai_goal {
int signature; // Unique identifier. All goals ever created (per mission) have a unique signature.
int ai_mode; // one of the AIM_* modes for this goal
int ai_submode; // maybe need a submode
int type; // one of the AIG_TYPE_* values above
flagset<AI::Goal_Flags> flags; // one of the AIGF_* values above
int flags; // one of the AIGF_* values above
fix time; // time at which this goal was issued.
int priority; // how important is this goal -- number 0 - 100
@@ -170,8 +227,10 @@ typedef struct ai_class {
int ai_chance_to_use_missiles_on_plr[NUM_SKILL_LEVELS];
float ai_max_aim_update_delay[NUM_SKILL_LEVELS];
float ai_turret_max_aim_update_delay[NUM_SKILL_LEVELS];
flagset<AI::Profile_Flags> ai_profile_flags; //Holds the state of flags that are set
flagset<AI::Profile_Flags> ai_profile_flags_set; //Holds which flags are set and which are just left alone
int ai_profile_flags; //Holds the state of flags that are set
int ai_profile_flags_set; //Holds which flags are set and which are just left alone
int ai_profile_flags2;
int ai_profile_flags2_set;
//SUSHI: These are optional overrides to an AI class to prevent the automatic scaling based on AI class index
int ai_aburn_use_factor[NUM_SKILL_LEVELS];
@@ -268,7 +327,7 @@ extern pnode *Ppfp; // Free pointer in path points.
#define MAX_IGNORE_NEW_OBJECTS 7
typedef struct ai_info {
flagset<AI::AI_Flags> ai_flags; // Special flags for AI behavior.
int ai_flags; // Special flags for AI behavior.
int shipnum; // Ship using this slot, -1 means none.
int type; //
int wing; // Member of what wing? -1 means none.
@@ -401,7 +460,8 @@ typedef struct ai_info {
int ai_chance_to_use_missiles_on_plr;
float ai_max_aim_update_delay;
float ai_turret_max_aim_update_delay;
flagset<AI::Profile_Flags> ai_profile_flags; //Holds AI_Profiles flags (possibly overriden by AI class) that actually apply to AI
int ai_profile_flags; //Holds AI_Profiles flags (possibly overriden by AI class) that actually apply to AI
int ai_profile_flags2;
union {
@@ -485,7 +545,7 @@ typedef struct ai_info {
vec3d artillery_lock_pos; // base position of the lock point on (in model's frame of reference)
float lethality; // measure of how dangerous ship is to enemy BIG|HUGE ships (likelyhood of targeting)
flagset<AI::Maneuver_Override_Flags> ai_override_flags; // flags for marking ai overrides from sexp or lua systems
int ai_override_flags; // flags for marking ai overrides from sexp or lua systems
control_info ai_override_ci; // ai override control info
int ai_override_timestamp; // mark for when to end the current override
} ai_info;
@@ -559,7 +619,7 @@ void set_wingnum(int objnum, int wingnum);
char *ai_get_goal_target_name(const char *name, int *index);
extern void init_ai_system(void);
extern void ai_attack_object(object *attacker, object *attacked, ship_subsys *ssp, int ship_info_index = -1);
extern void ai_attack_object(object *attacker, object *attacked, ship_subsys *ssp);
extern void ai_evade_object(object *evader, object *evaded);
extern void ai_ignore_object(object *ignorer, object *ignored, int ignore_new);
extern void ai_ignore_wing(object *ignorer, int wingnum);
@@ -568,7 +628,7 @@ 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 *hitpos, int shield_quadrant, vec3d *hit_normal);
extern void ai_ship_destroy(int shipnum, Ship::Exit_Flags method);
extern void ai_ship_destroy(int shipnum, int 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.
@@ -629,7 +689,7 @@ extern int ai_maybe_fire_afterburner(object *objp, ai_info *aip);
extern void set_predicted_enemy_pos(vec3d *predicted_enemy_pos, object *pobjp, vec3d *enemy_pos, vec3d *enemy_vel, ai_info *aip);
extern int is_instructor(object *objp);
extern int find_enemy(int objnum, float range, int max_attackers, int ship_info_index = -1);
extern int find_enemy(int objnum, float range, int max_attackers);
float ai_get_weapon_speed(ship_weapon *swp);
void set_predicted_enemy_pos_turret(vec3d *predicted_enemy_pos, vec3d *gun_pos, object *pobjp, vec3d *enemy_pos, vec3d *enemy_vel, float weapon_speed, float time_enemy_in_range);
@@ -651,7 +711,7 @@ extern int find_danger_weapon(object *sobjp, float dtime, float *atime, float do
void ai_set_mode_warp_out(object *objp, ai_info *aip);
// prototyped by Goober5000
int get_nearest_objnum(int objnum, int enemy_team_mask, int enemy_wing, float range, int max_attackers, int ship_info_index);
int get_nearest_objnum(int objnum, int enemy_team_mask, int enemy_wing, float range, int max_attackers);
// moved to header file by Goober5000
void ai_announce_ship_dying(object *dying_objp);
-121
View File
@@ -1,121 +0,0 @@
#ifndef AI_FLAGS_H
#define AI_FLAGS_H
#include "globalincs/flagset.h"
namespace AI {
FLAG_LIST(AI_Flags) {
Formation_wing, // Fly in formation as part of wing.
Awaiting_repair, // Awaiting a repair ship.
Being_repaired, // Currently docked with repair ship.
Repairing, // Repairing a ship (or going to repair a ship)
Seek_lock, // set if should focus on gaining aspect lock, not hitting with lasers
Formation_object, // Fly in formation off a specific object.
Temporary_ignore, // Means current ignore_objnum is only temporary, not an order from the player.
Use_exit_path, // Used by path code, to flag path as an exit path
Use_static_path, // Used by path code, use fixed path, don't try to recreate
Target_collision, // Collided with aip->target_objnum last frame. Avoid that ship for half a second or so.
Unload_secondaries, // Fire secondaries as fast as possible!
On_subsys_path, // Current path leads to a subsystem
Avoid_shockwave_ship, // Avoid an existing shockwave from a ship.
Avoid_shockwave_weapon, // Avoid an expected shockwave from a weapon. shockwave_object field contains object index.
Avoid_shockwave_started, // Already started avoiding shockwave, don't keep deciding whether to avoid.
Attack_slowly, // Move slowly while attacking.
Repair_obstructed, // Ship wants to be repaired, but path is obstructed.
Kamikaze, // Crash into target
No_dynamic, // Not allowed to get dynamic goals
Avoiding_small_ship, // Avoiding a player ship.
Avoiding_big_ship, // Avoiding a large ship.
Big_ship_collide_recover_1, // Collided into a big ship. Recovering by flying away.
Big_ship_collide_recover_2, // Collided into a big ship. Fly towards big ship sphere perimeter.
Stealth_pursuit, // AI is trying to fight stealth ship
Unload_primaries, // Fire primaries as fast as possible!
Trying_unsuccessfully_to_warp, // Trying to warp, but can't warp at the moment
Free_afterburner_use, // Use afterburners while following waypoints or flying towards objects
NUM_VALUES
};
FLAG_LIST(Goal_Flags) {
Docker_index_valid, // when set, index field for docker is valid
Dockee_index_valid, // when set, index field for dockee is valid
Goal_on_hold, // when set, this goal cannot currently be satisfied, although it could be in the future
Subsys_needs_fixup, // when set, the subsystem index (for a destroy subsystem goal) is invalid and must be gotten from the subsys name stored in docker.name field!!
Goal_override, // paired with AIG_TYPE_DYNAMIC to mean this goal overrides any other goal
Purge, // purge this goal next time we process
Goals_purged, // this goal has already caused other goals to get purged
Depart_sound_played,// Goober5000 - replacement for AL's hack ;)
Target_own_team,
NUM_VALUES
};
FLAG_LIST(Maneuver_Override_Flags) {
Full, // Full sexp control
Roll, // Sexp forced roll maneuver
Pitch, // Sexp forced pitch change
Heading, // Sexp forced heading change
Full_lat, // full control over up/side/forward movement
Up, // vertical movement
Sideways, // horizontal movement
Forward, // forward movement
NUM_VALUES
};
FLAG_LIST(Profile_Flags) {
Advanced_turret_fov_edge_checks,
Ai_aims_from_ship_center,
Ai_can_slow_down_attacking_big_ships,
Ai_guards_specific_ship_in_wing,
All_ships_manage_shields,
Allow_multi_event_scoring,
Allow_primary_link_at_start,
Allow_rapid_secondary_dumbfire,
Allow_turrets_target_weapons_freely,
Allow_vertical_dodge,
Aspect_invulnerability_fix,
Aspect_lock_countermeasure,
Assist_scoring_scales_with_damage,
Beams_damage_weapons,
Big_ships_can_attack_beam_turrets_on_untargeted_ships,
Disable_linked_fire_penalty,
Disable_weapon_damage_scaling,
Dont_insert_random_turret_fire_delay,
Fix_ai_class_bug,
Fix_ai_path_order_bug,
Fix_heat_seeker_stealth_bug,
Fix_linked_primary_bug,
Force_beam_turret_fov,
Glide_decay_requires_thrust,
Hack_improve_non_homing_swarm_turret_fire_accuracy,
Huge_turret_weapons_ignore_bombs,
Include_beams_in_stat_calcs,
Kill_scoring_scales_with_damage,
Multi_allow_empty_primaries,
Multi_allow_empty_secondaries,
Navigation_subsys_governs_warp,
No_min_dock_speed_cap,
No_special_player_avoid,
No_warp_camera,
Perform_fewer_scream_checks,
Player_weapon_scale_fix,
Prevent_targeting_bombs_beyond_range,
Require_turret_to_have_target_in_fov,
Shockwaves_damage_small_ship_subsystems,
Smart_afterburner_management,
Smart_primary_weapon_selection,
Smart_secondary_weapon_selection,
Smart_shield_management,
Smart_subsystem_targeting_for_turrets,
Strict_turred_tagged_only_targeting,
Turrets_ignore_target_radius,
Use_additive_weapon_velocity,
Use_newtonian_dampening,
Use_only_single_fov_for_turrets,
NUM_VALUES
};
}
#endif
+74 -126
View File
@@ -28,17 +28,28 @@ static char Default_profile_name[NAME_LENGTH];
// utility
void set_flag(ai_profile_t *profile, const char *name, AI::Profile_Flags flag)
void set_flag(ai_profile_t *profile, char *name, int flag, int type)
{
if (optional_string(name))
{
bool val;
stuff_boolean(&val);
profile->flags.set(flag, val);
if (type == AIP_FLAG) {
if (val)
profile->flags |= flag;
else
profile->flags &= ~flag;
} else {
if (val)
profile->flags2 |= flag;
else
profile->flags2 &= ~flag;
}
}
}
const char *AI_path_types[] = {
char *AI_path_types[] = {
"normal",
"alt1",
};
@@ -141,12 +152,12 @@ void parse_ai_profiles_tbl(const char *filename)
// base profile, so zero it out
if (profile == &Ai_profiles[0])
{
profile->reset();
memset(profile, 0, sizeof(ai_profile_t));
}
// brand new profile, so set it to the base defaults
else
{
*profile = Ai_profiles[0];
memcpy(profile, &Ai_profiles[0], sizeof(ai_profile_t));
}
}
@@ -345,93 +356,93 @@ void parse_ai_profiles_tbl(const char *filename)
}
if (optional_string("$Detail Distance Multiplier:"))
parse_float_list(profile->detail_distance_mult, MAX_DETAIL_LEVEL + 1);
parse_float_list(profile->detail_distance_mult, NUM_SKILL_LEVELS);
set_flag(profile, "$big ships can attack beam turrets on untargeted ships:", AI::Profile_Flags::Big_ships_can_attack_beam_turrets_on_untargeted_ships);
set_flag(profile, "$big ships can attack beam turrets on untargeted ships:", AIPF_BIG_SHIPS_CAN_ATTACK_BEAM_TURRETS_ON_UNTARGETED_SHIPS, AIP_FLAG);
set_flag(profile, "$smart primary weapon selection:", AI::Profile_Flags::Smart_primary_weapon_selection);
set_flag(profile, "$smart primary weapon selection:", AIPF_SMART_PRIMARY_WEAPON_SELECTION, AIP_FLAG);
set_flag(profile, "$smart secondary weapon selection:", AI::Profile_Flags::Smart_secondary_weapon_selection);
set_flag(profile, "$smart secondary weapon selection:", AIPF_SMART_SECONDARY_WEAPON_SELECTION, AIP_FLAG);
set_flag(profile, "$smart shield management:", AI::Profile_Flags::Smart_shield_management);
set_flag(profile, "$smart shield management:", AIPF_SMART_SHIELD_MANAGEMENT, AIP_FLAG);
set_flag(profile, "$smart afterburner management:", AI::Profile_Flags::Smart_afterburner_management);
set_flag(profile, "$smart afterburner management:", AIPF_SMART_AFTERBURNER_MANAGEMENT, AIP_FLAG);
set_flag(profile, "$allow rapid secondary dumbfire:", AI::Profile_Flags::Allow_rapid_secondary_dumbfire);
set_flag(profile, "$allow rapid secondary dumbfire:", AIPF_ALLOW_RAPID_SECONDARY_DUMBFIRE, AIP_FLAG);
set_flag(profile, "$huge turret weapons ignore bombs:", AI::Profile_Flags::Huge_turret_weapons_ignore_bombs);
set_flag(profile, "$huge turret weapons ignore bombs:", AIPF_HUGE_TURRET_WEAPONS_IGNORE_BOMBS, AIP_FLAG);
set_flag(profile, "$don't insert random turret fire delay:", AI::Profile_Flags::Dont_insert_random_turret_fire_delay);
set_flag(profile, "$don't insert random turret fire delay:", AIPF_DONT_INSERT_RANDOM_TURRET_FIRE_DELAY, AIP_FLAG);
set_flag(profile, "$hack improve non-homing swarm turret fire accuracy:", AI::Profile_Flags::Hack_improve_non_homing_swarm_turret_fire_accuracy);
set_flag(profile, "$hack improve non-homing swarm turret fire accuracy:", AIPF_HACK_IMPROVE_NON_HOMING_SWARM_TURRET_FIRE_ACCURACY, AIP_FLAG);
set_flag(profile, "$shockwaves damage small ship subsystems:", AI::Profile_Flags::Shockwaves_damage_small_ship_subsystems);
set_flag(profile, "$shockwaves damage small ship subsystems:", AIPF_SHOCKWAVES_DAMAGE_SMALL_SHIP_SUBSYSTEMS, AIP_FLAG);
set_flag(profile, "$navigation subsystem governs warpout capability:", AI::Profile_Flags::Navigation_subsys_governs_warp);
set_flag(profile, "$navigation subsystem governs warpout capability:", AIPF_NAVIGATION_SUBSYS_GOVERNS_WARP, AIP_FLAG);
set_flag(profile, "$ignore lower bound for minimum speed of docked ship:", AI::Profile_Flags::No_min_dock_speed_cap);
set_flag(profile, "$ignore lower bound for minimum speed of docked ship:", AIPF_NO_MIN_DOCK_SPEED_CAP, AIP_FLAG);
set_flag(profile, "$disable linked fire penalty:", AI::Profile_Flags::Disable_linked_fire_penalty);
set_flag(profile, "$disable linked fire penalty:", AIPF_DISABLE_LINKED_FIRE_PENALTY, AIP_FLAG);
set_flag(profile, "$disable weapon damage scaling:", AI::Profile_Flags::Disable_weapon_damage_scaling);
set_flag(profile, "$disable weapon damage scaling:", AIPF_DISABLE_WEAPON_DAMAGE_SCALING, AIP_FLAG);
set_flag(profile, "$use additive weapon velocity:", AI::Profile_Flags::Use_additive_weapon_velocity);
set_flag(profile, "$use additive weapon velocity:", AIPF_USE_ADDITIVE_WEAPON_VELOCITY, AIP_FLAG);
set_flag(profile, "$use newtonian dampening:", AI::Profile_Flags::Use_newtonian_dampening);
set_flag(profile, "$use newtonian dampening:", AIPF_USE_NEWTONIAN_DAMPENING, AIP_FLAG);
set_flag(profile, "$include beams for kills and assists:", AI::Profile_Flags::Include_beams_in_stat_calcs);
set_flag(profile, "$include beams for kills and assists:", AIPF_INCLUDE_BEAMS_IN_STAT_CALCS, AIP_FLAG);
set_flag(profile, "$score kills based on damage caused:", AI::Profile_Flags::Kill_scoring_scales_with_damage);
set_flag(profile, "$score kills based on damage caused:", AIPF_KILL_SCORING_SCALES_WITH_DAMAGE, AIP_FLAG);
set_flag(profile, "$score assists based on damage caused:", AI::Profile_Flags::Assist_scoring_scales_with_damage);
set_flag(profile, "$score assists based on damage caused:", AIPF_ASSIST_SCORING_SCALES_WITH_DAMAGE, AIP_FLAG);
set_flag(profile, "$allow event and goal scoring in multiplayer:", AI::Profile_Flags::Allow_multi_event_scoring);
set_flag(profile, "$allow event and goal scoring in multiplayer:", AIPF_ALLOW_MULTI_EVENT_SCORING, AIP_FLAG);
set_flag(profile, "$fix linked primary weapon decision bug:", AI::Profile_Flags::Fix_linked_primary_bug);
set_flag(profile, "$fix linked primary weapon decision bug:", AIPF_FIX_LINKED_PRIMARY_BUG, AIP_FLAG);
set_flag(profile, "$prevent turrets targeting too distant bombs:", AI::Profile_Flags::Prevent_targeting_bombs_beyond_range);
set_flag(profile, "$prevent turrets targeting too distant bombs:", AIPF_PREVENT_TARGETING_BOMBS_BEYOND_RANGE, AIP_FLAG);
set_flag(profile, "$smart subsystem targeting for turrets:", AI::Profile_Flags::Smart_subsystem_targeting_for_turrets);
set_flag(profile, "$smart subsystem targeting for turrets:", AIPF_SMART_SUBSYSTEM_TARGETING_FOR_TURRETS, AIP_FLAG);
set_flag(profile, "$fix heat seekers homing on stealth ships bug:", AI::Profile_Flags::Fix_heat_seeker_stealth_bug);
set_flag(profile, "$fix heat seekers homing on stealth ships bug:", AIPF_FIX_HEAT_SEEKER_STEALTH_BUG, AIP_FLAG);
set_flag(profile, "$multi allow empty primaries:", AI::Profile_Flags::Multi_allow_empty_primaries);
set_flag(profile, "$multi allow empty primaries:", AIPF_MULTI_ALLOW_EMPTY_PRIMARIES, AIP_FLAG);
set_flag(profile, "$multi allow empty secondaries:", AI::Profile_Flags::Multi_allow_empty_secondaries);
set_flag(profile, "$multi allow empty secondaries:", AIPF_MULTI_ALLOW_EMPTY_SECONDARIES, AIP_FLAG);
set_flag(profile, "$allow turrets target weapons freely:", AI::Profile_Flags::Allow_turrets_target_weapons_freely);
set_flag(profile, "$allow turrets target weapons freely:", AIPF_ALLOW_TURRETS_TARGET_WEAPONS_FREELY, AIP_FLAG);
set_flag(profile, "$use only single fov for turrets:", AI::Profile_Flags::Use_only_single_fov_for_turrets);
set_flag(profile, "$use only single fov for turrets:", AIPF_USE_ONLY_SINGLE_FOV_FOR_TURRETS, AIP_FLAG);
set_flag(profile, "$allow vertical dodge:", AI::Profile_Flags::Allow_vertical_dodge);
set_flag(profile, "$allow vertical dodge:", AIPF_ALLOW_VERTICAL_DODGE, AIP_FLAG);
set_flag(profile, "$force beam turrets to use normal fov:", AI::Profile_Flags::Force_beam_turret_fov);
set_flag(profile, "$force beam turrets to use normal fov:", AIPF_FORCE_BEAM_TURRET_FOV, AIP_FLAG);
set_flag(profile, "$fix ai class bug:", AI::Profile_Flags::Fix_ai_class_bug);
set_flag(profile, "$fix ai class bug:", AIPF_FIX_AI_CLASS_BUG, AIP_FLAG);
set_flag(profile, "$turrets ignore targets radius in range checks:", AI::Profile_Flags::Turrets_ignore_target_radius);
set_flag(profile, "$turrets ignore targets radius in range checks:", AIPF2_TURRETS_IGNORE_TARGET_RADIUS, AIP_FLAG2);
set_flag(profile, "$no extra collision avoidance vs player:", AI::Profile_Flags::No_special_player_avoid);
set_flag(profile, "$no extra collision avoidance vs player:", AIPF2_NO_SPECIAL_PLAYER_AVOID, AIP_FLAG2);
set_flag(profile, "$perform fewer checks for death screams:", AI::Profile_Flags::Perform_fewer_scream_checks);
set_flag(profile, "$perform fewer checks for death screams:", AIPF2_PERFORM_FEWER_SCREAM_CHECKS, AIP_FLAG2);
set_flag(profile, "$advanced turret fov edge checks:", AI::Profile_Flags::Advanced_turret_fov_edge_checks);
set_flag(profile, "$advanced turret fov edge checks:", AIPF2_ADVANCED_TURRET_FOV_EDGE_CHECKS, AIP_FLAG2);
set_flag(profile, "$require turrets to have target in fov:", AI::Profile_Flags::Require_turret_to_have_target_in_fov);
set_flag(profile, "$require turrets to have target in fov:", AIPF2_REQUIRE_TURRET_TO_HAVE_TARGET_IN_FOV, AIP_FLAG2);
set_flag(profile, "$all ships manage shields:", AI::Profile_Flags::All_ships_manage_shields);
set_flag(profile, "$all ships manage shields:", AIPF2_ALL_SHIPS_MANAGE_SHIELDS, AIP_FLAG2);
set_flag(profile, "$ai aims from ship center:", AI::Profile_Flags::Ai_aims_from_ship_center);
set_flag(profile, "$ai aims from ship center:", AIPF2_AI_AIMS_FROM_SHIP_CENTER, AIP_FLAG2);
set_flag(profile, "$allow primary link at mission start:", AI::Profile_Flags::Allow_primary_link_at_start);
set_flag(profile, "$allow primary link at mission start:", AIPF2_ALLOW_PRIMARY_LINK_AT_START, AIP_FLAG2);
set_flag(profile, "$allow beams to damage bombs:", AI::Profile_Flags::Beams_damage_weapons);
set_flag(profile, "$allow beams to damage bombs:", AIPF2_BEAMS_DAMAGE_WEAPONS, AIP_FLAG2);
set_flag(profile, "$disable weapon damage scaling for player:", AI::Profile_Flags::Player_weapon_scale_fix);
set_flag(profile, "$disable weapon damage scaling for player:", AIPF2_PLAYER_WEAPON_SCALE_FIX, AIP_FLAG2);
set_flag(profile, "$countermeasures affect aspect seekers:", AI::Profile_Flags::Aspect_lock_countermeasure);
set_flag(profile, "$countermeasures affect aspect seekers:", AIPF2_ASPECT_LOCK_COUNTERMEASURE, AIP_FLAG2);
set_flag(profile, "$ai guards specific ship in wing:", AI::Profile_Flags::Ai_guards_specific_ship_in_wing);
set_flag(profile, "$ai guards specific ship in wing:", AIPF2_AI_GUARDS_SPECIFIC_SHIP_IN_WING, AIP_FLAG2);
profile->ai_path_mode = AI_PATH_MODE_NORMAL;
if (optional_string("$ai path mode:"))
@@ -446,17 +457,17 @@ void parse_ai_profiles_tbl(const char *filename)
}
}
set_flag(profile, "$no warp camera:", AI::Profile_Flags::No_warp_camera);
set_flag(profile, "$no warp camera:", AIPF2_NO_WARP_CAMERA, AIP_FLAG2);
set_flag(profile, "$fix ai path order bug:", AI::Profile_Flags::Fix_ai_path_order_bug);
set_flag(profile, "$fix ai path order bug:", AIPF2_FIX_AI_PATH_ORDER_BUG, AIP_FLAG2);
set_flag(profile, "$strict turret-tagged-only targeting:", AI::Profile_Flags::Strict_turred_tagged_only_targeting);
set_flag(profile, "$strict turret-tagged-only targeting:", AIPF2_STRICT_TURRET_TAGGED_ONLY_TARGETING, AIP_FLAG2);
set_flag(profile, "$aspect bomb invulnerability fix:", AI::Profile_Flags::Aspect_invulnerability_fix);
set_flag(profile, "$aspect bomb invulnerability fix:", AIPF2_ASPECT_INVULNERABILITY_FIX, AIP_FLAG2);
set_flag(profile, "$glide decay requires thrust:", AI::Profile_Flags::Glide_decay_requires_thrust);
set_flag(profile, "$glide decay requires thrust:", AIPF2_GLIDE_DECAY_REQUIRES_THRUST, AIP_FLAG2);
set_flag(profile, "$ai can slow down when attacking big ships:", AI::Profile_Flags::Ai_can_slow_down_attacking_big_ships);
set_flag(profile, "$ai can slow down when attacking big ships:", AIPF2_AI_CAN_SLOW_DOWN_ATTACKING_BIG_SHIPS, AIP_FLAG2);
profile->bay_arrive_speed_mult = 1.0f;
profile->bay_depart_speed_mult = 1.0f;
@@ -475,14 +486,20 @@ void parse_ai_profiles_tbl(const char *filename)
mprintf(("Warning: \"$perform less checks for death screams\" flag is deprecated in favor of \"$perform fewer checks for death screams\"\n"));
bool temp;
stuff_boolean(&temp);
profile->flags.set(AI::Profile_Flags::Perform_fewer_scream_checks, temp);
if (temp)
profile->flags2 |= AIPF2_PERFORM_FEWER_SCREAM_CHECKS;
else
profile->flags2 &= ~AIPF2_PERFORM_FEWER_SCREAM_CHECKS;
}
if (optional_string("$allow primary link delay:"))
{
mprintf(("Warning: \"$allow primary link delay\" flag is deprecated in favor of \"$allow primary link at mission start\"\n"));
bool temp;
stuff_boolean(&temp);
profile->flags.set(AI::Profile_Flags::Allow_primary_link_at_start, !temp);
if (temp)
profile->flags2 &= ~AIPF2_ALLOW_PRIMARY_LINK_AT_START;
else
profile->flags2 |= AIPF2_ALLOW_PRIMARY_LINK_AT_START;
}
@@ -553,72 +570,3 @@ int ai_profile_lookup(char *name)
return -1;
}
void ai_profile_t::reset()
{
memset(profile_name, 0, sizeof(profile_name));
flags.reset();
ai_path_mode = 0;
bay_arrive_speed_mult = 0;
bay_depart_speed_mult = 0;
for (int i = 0; i < NUM_SKILL_LEVELS; ++i) {
max_incoming_asteroids[i] = 0;
max_allowed_player_homers[i] = 0;
max_attackers[i] = 0;
predict_position_delay[i] = 0;
in_range_time[i] = 0;
shield_manage_delay[i] = 0;
link_energy_levels_always[i] = 0;
link_energy_levels_maybe[i] = 0;
link_ammo_levels_always[i] = 0;
link_ammo_levels_maybe[i] = 0;
primary_ammo_burst_mult[i] = 0;
cmeasure_life_scale[i] = 0;
cmeasure_fire_chance[i] = 0;
weapon_energy_scale[i] = 0;
shield_energy_scale[i] = 0;
afterburner_recharge_scale[i] = 0;
player_damage_scale[i] = 0;
subsys_damage_scale[i] = 0;
beam_friendly_damage_cap[i] = 0;
turn_time_scale[i] = 0;
glide_attack_percent[i] = 0;
circle_strafe_percent[i] = 0;
glide_strafe_percent[i] = 0;
random_sidethrust_percent[i] = 0;
stalemate_time_thresh[i] = 0;
stalemate_dist_thresh[i] = 0;
max_aim_update_delay[i] = 0;
turret_max_aim_update_delay[i] = 0;
ship_fire_delay_scale_hostile[i] = 0;
ship_fire_delay_scale_friendly[i] = 0;
ship_fire_secondary_delay_scale_hostile[i] = 0;
ship_fire_secondary_delay_scale_friendly[i] = 0;
max_turret_ownage_target[i] = 0;
max_turret_ownage_player[i] = 0;
kill_percentage_scale[i] = 0;
assist_percentage_scale[i] = 0;
assist_award_percentage_scale[i] = 0;
repair_penalty[i] = 0;
delay_bomb_arm_timer[i] = 0;
chance_to_use_missiles_on_plr[i] = 0;
player_autoaim_fov[i] = 0;
}
for (int i = 0; i <= MAX_DETAIL_LEVEL; ++i) {
detail_distance_mult[i] = 0;
}
}
+62 -7
View File
@@ -12,7 +12,63 @@
#include "globalincs/globals.h"
#include "globalincs/pstypes.h"
#include "globalincs/systemvars.h"
#include "ai/ai_flags.h"
// flag int defines
#define AIP_FLAG 1
#define AIP_FLAG2 2
// flags
#define AIPF_SMART_SHIELD_MANAGEMENT (1 << 0)
#define AIPF_BIG_SHIPS_CAN_ATTACK_BEAM_TURRETS_ON_UNTARGETED_SHIPS (1 << 1)
#define AIPF_SMART_PRIMARY_WEAPON_SELECTION (1 << 2)
#define AIPF_SMART_SECONDARY_WEAPON_SELECTION (1 << 3)
#define AIPF_ALLOW_RAPID_SECONDARY_DUMBFIRE (1 << 4)
#define AIPF_HUGE_TURRET_WEAPONS_IGNORE_BOMBS (1 << 5)
#define AIPF_DONT_INSERT_RANDOM_TURRET_FIRE_DELAY (1 << 6)
#define AIPF_HACK_IMPROVE_NON_HOMING_SWARM_TURRET_FIRE_ACCURACY (1 << 7)
#define AIPF_SHOCKWAVES_DAMAGE_SMALL_SHIP_SUBSYSTEMS (1 << 8)
#define AIPF_NAVIGATION_SUBSYS_GOVERNS_WARP (1 << 9)
#define AIPF_NO_MIN_DOCK_SPEED_CAP (1 << 10)
#define AIPF_DISABLE_LINKED_FIRE_PENALTY (1 << 11)
#define AIPF_DISABLE_WEAPON_DAMAGE_SCALING (1 << 12)
#define AIPF_USE_ADDITIVE_WEAPON_VELOCITY (1 << 13)
#define AIPF_USE_NEWTONIAN_DAMPENING (1 << 14)
#define AIPF_INCLUDE_BEAMS_IN_STAT_CALCS (1 << 15)
#define AIPF_KILL_SCORING_SCALES_WITH_DAMAGE (1 << 16)
#define AIPF_ASSIST_SCORING_SCALES_WITH_DAMAGE (1 << 17)
#define AIPF_ALLOW_MULTI_EVENT_SCORING (1 << 18)
#define AIPF_SMART_AFTERBURNER_MANAGEMENT (1 << 19)
#define AIPF_FIX_LINKED_PRIMARY_BUG (1 << 20)
#define AIPF_PREVENT_TARGETING_BOMBS_BEYOND_RANGE (1 << 21)
#define AIPF_SMART_SUBSYSTEM_TARGETING_FOR_TURRETS (1 << 22)
#define AIPF_FIX_HEAT_SEEKER_STEALTH_BUG (1 << 23)
#define AIPF_MULTI_ALLOW_EMPTY_PRIMARIES (1 << 24)
#define AIPF_MULTI_ALLOW_EMPTY_SECONDARIES (1 << 25)
#define AIPF_ALLOW_TURRETS_TARGET_WEAPONS_FREELY (1 << 26)
#define AIPF_USE_ONLY_SINGLE_FOV_FOR_TURRETS (1 << 27)
#define AIPF_ALLOW_VERTICAL_DODGE (1 << 28) //Allows AI ships to evade weapons vertically as well as horizontally
#define AIPF_FORCE_BEAM_TURRET_FOV (1 << 29)
#define AIPF_FIX_AI_CLASS_BUG (1 << 30)
// flags2
#define AIPF2_TURRETS_IGNORE_TARGET_RADIUS (1 << 0)
#define AIPF2_NO_SPECIAL_PLAYER_AVOID (1 << 1)
#define AIPF2_PERFORM_FEWER_SCREAM_CHECKS (1 << 2)
#define AIPF2_ALL_SHIPS_MANAGE_SHIELDS (1 << 3)
#define AIPF2_ADVANCED_TURRET_FOV_EDGE_CHECKS (1 << 4)
#define AIPF2_REQUIRE_TURRET_TO_HAVE_TARGET_IN_FOV (1 << 5)
#define AIPF2_AI_AIMS_FROM_SHIP_CENTER (1 << 6)
#define AIPF2_ALLOW_PRIMARY_LINK_AT_START (1 << 7)
#define AIPF2_BEAMS_DAMAGE_WEAPONS (1 << 8)
#define AIPF2_PLAYER_WEAPON_SCALE_FIX (1 << 9)
#define AIPF2_NO_WARP_CAMERA (1 << 10)
#define AIPF2_ASPECT_LOCK_COUNTERMEASURE (1 << 11)
#define AIPF2_AI_GUARDS_SPECIFIC_SHIP_IN_WING (1 << 12)
#define AIPF2_FIX_AI_PATH_ORDER_BUG (1 << 13)
#define AIPF2_STRICT_TURRET_TAGGED_ONLY_TARGETING (1 << 14)
#define AIPF2_ASPECT_INVULNERABILITY_FIX (1 << 15)
#define AIPF2_GLIDE_DECAY_REQUIRES_THRUST (1 << 16)
#define AIPF2_AI_CAN_SLOW_DOWN_ATTACKING_BIG_SHIPS (1 << 17)
// AI Path types
#define AI_PATH_MODE_NORMAL 0
@@ -20,11 +76,12 @@
#define MAX_AI_PROFILES 5
class ai_profile_t {
public:
typedef struct ai_profile_t {
char profile_name[NAME_LENGTH];
flagset<AI::Profile_Flags> flags;
int flags;
int flags2;
// difficulty-related values
int max_incoming_asteroids[NUM_SKILL_LEVELS]; // max number of asteroids thrown at friendlies
@@ -102,15 +159,13 @@ public:
float bay_arrive_speed_mult;
float bay_depart_speed_mult;
void reset();
};
} ai_profile_t;
extern int Num_ai_profiles;
extern int Default_ai_profile;
extern ai_profile_t Ai_profiles[MAX_AI_PROFILES];
#define AI_PROFILES_INDEX(ai_p) ((int)((ai_p) - Ai_profiles))
void ai_profiles_init();
+33 -33
View File
@@ -350,8 +350,8 @@ void ai_big_avoid_ship()
// reset path following information
void ai_big_subsys_path_cleanup(ai_info *aip)
{
if ( aip->ai_flags[AI::AI_Flags::On_subsys_path] ) {
aip->ai_flags.remove(AI::AI_Flags::On_subsys_path);
if ( aip->ai_flags & AIF_ON_SUBSYS_PATH ) {
aip->ai_flags &= ~AIF_ON_SUBSYS_PATH;
aip->path_goal_dist = -1;
aip->path_start = -1;
aip->path_cur = -1;
@@ -438,7 +438,7 @@ int ai_big_maybe_follow_subsys_path(int do_dot_check)
Assert(aip->target_objnum >= 0);
ai_find_path(Pl_objp, aip->target_objnum, subsys_path_num, 0, 1);
if ( aip->path_start >= 0 ) {
aip->ai_flags.set(AI::AI_Flags::On_subsys_path);
aip->ai_flags |= AIF_ON_SUBSYS_PATH;
}
}
}
@@ -593,7 +593,7 @@ void ai_big_chase_attack(ai_info *aip, ship_info *sip, vec3d *enemy_pos, float d
} // end if ( Pl_objp->phys_info.speed < 3.0f )
//Maybe enter glide strafe (check every 8 seconds, on a different schedule for each ship)
if ((sip->can_glide == true) && !(aip->ai_flags[AI::AI_Flags::Kamikaze]) && static_randf((Missiontime + static_rand(aip->shipnum)) >> 19) < aip->ai_glide_strafe_percent) {
if ((sip->can_glide == true) && !(aip->ai_flags & AIF_KAMIKAZE) && static_randf((Missiontime + static_rand(aip->shipnum)) >> 19) < aip->ai_glide_strafe_percent) {
aip->previous_mode = aip->mode;
aip->mode = AIM_STRAFE;
aip->submode_parm0 = Missiontime; // use parm0 as time strafe mode entered (i.e. MODE start time)
@@ -604,7 +604,7 @@ void ai_big_chase_attack(ai_info *aip, ship_info *sip, vec3d *enemy_pos, float d
// see if Pl_objp needs to reposition to get a good shot at subsystem which is being attacked
if ( ai_big_maybe_follow_subsys_path() ) {
if ((Pl_objp->phys_info.flags & PF_AFTERBURNER_ON) && !(aip->ai_flags[AI::AI_Flags::Kamikaze])) {
if ((Pl_objp->phys_info.flags & PF_AFTERBURNER_ON) && !(aip->ai_flags & AIF_KAMIKAZE)) {
afterburners_stop(Pl_objp);
}
return;
@@ -641,19 +641,19 @@ 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]) && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) && (dot_to_enemy > 0.75f)) {
if ((aip->ai_flags & AIF_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;
}
} else if ((Pl_objp->phys_info.flags & PF_AFTERBURNER_ON) && !(aip->ai_flags[AI::AI_Flags::Kamikaze])) {
} else if ((Pl_objp->phys_info.flags & PF_AFTERBURNER_ON) && !(aip->ai_flags & AIF_KAMIKAZE)) {
afterburners_stop(Pl_objp);
}
} else {
// AL 12-31-97: Move at least as quickly as your target is moving...
accelerate_ship(aip, MAX(1.0f - dot_to_enemy, Objects[aip->target_objnum].phys_info.fspeed/sip->max_speed));
if ((Pl_objp->phys_info.flags & PF_AFTERBURNER_ON) && !(aip->ai_flags[AI::AI_Flags::Kamikaze])) {
if ((Pl_objp->phys_info.flags & PF_AFTERBURNER_ON) && !(aip->ai_flags & AIF_KAMIKAZE)) {
afterburners_stop(Pl_objp);
}
}
@@ -676,19 +676,19 @@ void ai_big_chase_attack(ai_info *aip, ship_info *sip, vec3d *enemy_pos, float d
if (dist_to_enemy < ATTACK_STOP_DISTANCE) {
// accelerate_ship(aip, accel * 0.5f);
accelerate_ship(aip, -1.0f);
if ((Pl_objp->phys_info.flags & PF_AFTERBURNER_ON) && !(aip->ai_flags[AI::AI_Flags::Kamikaze])) {
if ((Pl_objp->phys_info.flags & PF_AFTERBURNER_ON) && !(aip->ai_flags & AIF_KAMIKAZE)) {
afterburners_stop(Pl_objp);
}
} else {
accelerate_ship(aip, accel);
ship *shipp = &Ships[Pl_objp->instance];
if ((aip->ai_flags[AI::AI_Flags::Free_afterburner_use]) && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) && (accel > 0.95f)) {
if ((aip->ai_flags & AIF_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;
}
} else if ((Pl_objp->phys_info.flags & PF_AFTERBURNER_ON) && !(aip->ai_flags[AI::AI_Flags::Kamikaze])) {
} else if ((Pl_objp->phys_info.flags & PF_AFTERBURNER_ON) && !(aip->ai_flags & AIF_KAMIKAZE)) {
afterburners_stop(Pl_objp);
}
}
@@ -754,10 +754,10 @@ void ai_big_maybe_fire_weapons(float dist_to_enemy, float dot_to_enemy, vec3d *f
if (current_bank > -1) {
weapon_info *swip = &Weapon_info[tswp->secondary_bank_weapons[current_bank]];
if(!(En_objp->flags[Object::Object_Flags::Protected]) || ((aip->goals[0].ai_mode & (AI_GOAL_DISABLE_SHIP | AI_GOAL_DISARM_SHIP)) && swip->wi_flags[Weapon::Info_Flags::Puncture] )) { //override lockdown on protected ships when using anti subsystem weapons - Valathil
if(!(En_objp->flags[Object::Object_Flags::Protected]) || ((aip->goals[0].ai_mode & (AI_GOAL_DISABLE_SHIP | AI_GOAL_DISARM_SHIP)) && swip->wi_flags & WIF_PUNCTURE )) { //override lockdown on protected ships when using anti subsystem weapons - Valathil
// If ship is protected and very low on hits, don't fire missiles.
if (!(En_objp->flags[Object::Object_Flags::Protected]) || (En_objp->hull_strength > 10*swip->damage)) {
if (aip->ai_flags[AI::AI_Flags::Unload_secondaries]) {
if (aip->ai_flags & AIF_UNLOAD_SECONDARIES) {
if (timestamp_until(swp->next_secondary_fire_stamp[current_bank]) > swip->fire_wait*1000.0f) {
swp->next_secondary_fire_stamp[current_bank] = timestamp((int) (swip->fire_wait*1000.0f));
}
@@ -765,7 +765,7 @@ void ai_big_maybe_fire_weapons(float dist_to_enemy, float dot_to_enemy, vec3d *f
if (timestamp_elapsed(swp->next_secondary_fire_stamp[current_bank])) {
float firing_range;
if (swip->wi_flags[Weapon::Info_Flags::Local_ssm])
if (swip->wi_flags2 & WIF2_LOCAL_SSM)
firing_range=swip->lssm_lock_range;
else
firing_range = MIN((swip->max_speed * swip->lifetime), swip->weapon_range);
@@ -786,13 +786,13 @@ void ai_big_maybe_fire_weapons(float dist_to_enemy, float dot_to_enemy, vec3d *f
int current_bank_adjusted = MAX_SHIP_PRIMARY_BANKS + current_bank;
if ((aip->ai_flags[AI::AI_Flags::Unload_secondaries]) || (swip->burst_flags[Weapon::Burst_Flags::Fast_firing])) {
if ((aip->ai_flags & AIF_UNLOAD_SECONDARIES) || (swip->burst_flags & WBF_FAST_FIRING)) {
if (swip->burst_shots > swp->burst_counter[current_bank_adjusted]) {
t = swip->burst_delay;
swp->burst_counter[current_bank_adjusted]++;
} else {
t = swip->fire_wait;
if ((swip->burst_shots > 0) && (swip->burst_flags[Weapon::Burst_Flags::Random_length])) {
if ((swip->burst_shots > 0) && (swip->burst_flags & WBF_RANDOM_LENGTH)) {
swp->burst_counter[current_bank_adjusted] = myrand() % swip->burst_shots;
} else {
swp->burst_counter[current_bank_adjusted] = 0;
@@ -804,7 +804,7 @@ void ai_big_maybe_fire_weapons(float dist_to_enemy, float dot_to_enemy, vec3d *f
swp->burst_counter[current_bank_adjusted]++;
} else {
t = set_secondary_fire_delay(aip, temp_shipp, swip, false);
if ((swip->burst_shots > 0) && (swip->burst_flags[Weapon::Burst_Flags::Random_length])) {
if ((swip->burst_shots > 0) && (swip->burst_flags & WBF_RANDOM_LENGTH)) {
swp->burst_counter[current_bank_adjusted] = myrand() % swip->burst_shots;
} else {
swp->burst_counter[current_bank_adjusted] = 0;
@@ -881,7 +881,7 @@ void ai_big_chase()
dist_to_enemy = vm_vec_normalized_dir(&vec_to_enemy, &enemy_pos, &player_pos); // - En_objp->radius;
dot_to_enemy = vm_vec_dot(&vec_to_enemy, &Pl_objp->orient.vec.fvec);
if (aip->ai_flags[AI::AI_Flags::Target_collision]) {
if (aip->ai_flags & AIF_TARGET_COLLISION) {
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)
@@ -894,7 +894,7 @@ void ai_big_chase()
}
}
if (aip->ai_flags[AI::AI_Flags::Kamikaze]) {
if (aip->ai_flags & AIF_KAMIKAZE) {
//nprintf(("AI", "Kamikaze: %7.3f %7.3f\n", dot_to_enemy, dist_to_enemy));
accelerate_ship(aip, 1.0f);
if ((dist_to_enemy < 400.0f) && ai_maybe_fire_afterburner(Pl_objp, aip)) {
@@ -904,7 +904,7 @@ void ai_big_chase()
}
// If just acquired target, or target is not in reasonable cone, don't refine believed enemy position.
if ((dot_to_enemy < 0.25f) || (aip->target_time < 1.0f) || (aip->ai_flags[AI::AI_Flags::Seek_lock])) {
if ((dot_to_enemy < 0.25f) || (aip->target_time < 1.0f) || (aip->ai_flags & AIF_SEEK_LOCK)) {
update_aspect_lock_information(aip, &vec_to_enemy, dist_to_enemy - En_objp->radius, En_objp->radius);
} else if (aip->targeted_subsys != NULL) {
Assert(aip->targeted_subsys != NULL);
@@ -931,7 +931,7 @@ void ai_big_chase()
case SM_SUPER_ATTACK:
if (vm_vec_dist_quick(&Pl_objp->pos, &predicted_enemy_pos) > 100.0f + En_objp->radius * 2.0f) {
if (maybe_avoid_big_ship(Pl_objp, En_objp, aip, &predicted_enemy_pos, 10.0f)) {
if ((Pl_objp->phys_info.flags & PF_AFTERBURNER_ON) && !(aip->ai_flags[AI::AI_Flags::Kamikaze])) {
if ((Pl_objp->phys_info.flags & PF_AFTERBURNER_ON) && !(aip->ai_flags & AIF_KAMIKAZE)) {
afterburners_stop(Pl_objp);
}
return;
@@ -953,7 +953,7 @@ void ai_big_chase()
//
if (((aip->submode != SM_ATTACK) && (aip->submode != SM_SUPER_ATTACK) && (aip->submode != SM_ATTACK_FOREVER) && (aip->submode != SM_EVADE_WEAPON)) || (aip->mode == AIM_STRAFE)){
if ((Pl_objp->phys_info.flags & PF_AFTERBURNER_ON) && !(aip->ai_flags[AI::AI_Flags::Kamikaze])) {
if ((Pl_objp->phys_info.flags & PF_AFTERBURNER_ON) && !(aip->ai_flags & AIF_KAMIKAZE)) {
afterburners_stop(Pl_objp);
}
}
@@ -1198,7 +1198,7 @@ void ai_big_attack_get_data(vec3d *enemy_pos, float *dist_to_enemy, float *dot_t
// If just acquired target, or target is not in reasonable cone, don't refine believed enemy position.
vm_vec_normalized_dir(&vec_to_enemy, enemy_pos, &player_pos);
*dot_to_enemy=vm_vec_dot(&vec_to_enemy, &Pl_objp->orient.vec.fvec);
if ((*dot_to_enemy < 0.25f) || (aip->target_time < 1.0f) || (aip->ai_flags[AI::AI_Flags::Seek_lock])) {
if ((*dot_to_enemy < 0.25f) || (aip->target_time < 1.0f) || (aip->ai_flags & AIF_SEEK_LOCK)) {
predicted_enemy_pos=*enemy_pos;
} else {
vec3d gun_pos, pnt;
@@ -1206,7 +1206,7 @@ void ai_big_attack_get_data(vec3d *enemy_pos, float *dist_to_enemy, float *dot_t
float weapon_speed;
// Compute position of gun in absolute space and use that as fire position.
if (po->n_guns > 0 && !(The_mission.ai_profile->flags[AI::Profile_Flags::Ai_aims_from_ship_center])) {
if (po->n_guns > 0 && !(The_mission.ai_profile->flags2 & AIPF2_AI_AIMS_FROM_SHIP_CENTER)) {
pnt = po->gun_banks[0].pnt[0];
vm_vec_unrotate(&gun_pos, &pnt, &Pl_objp->orient);
vm_vec_add2(&gun_pos, &Pl_objp->pos);
@@ -1254,10 +1254,10 @@ int ai_big_strafe_maybe_retreat(float dist, vec3d *target_pos)
// Inside 2 sec retreat, setting goal point to box point + 300m
// If collision, use std collision resolution.
if ( !(aip->ai_flags[AI::AI_Flags::Kamikaze]) && ((aip->ai_flags[AI::AI_Flags::Target_collision]) || (time_to_target < STRAFE_RETREAT_COLLIDE_TIME) || (dist_normal_to_target < STRAFE_RETREAT_COLLIDE_DIST + speed_to_dist_penalty)) ) {
if (aip->ai_flags[AI::AI_Flags::Target_collision]) {
if ( !(aip->ai_flags & AIF_KAMIKAZE) && ((aip->ai_flags & AIF_TARGET_COLLISION) || (time_to_target < STRAFE_RETREAT_COLLIDE_TIME) || (dist_normal_to_target < STRAFE_RETREAT_COLLIDE_DIST + speed_to_dist_penalty)) ) {
if (aip->ai_flags & AIF_TARGET_COLLISION) {
// use standard collision resolution
aip->ai_flags.remove(AI::AI_Flags::Target_collision);
aip->ai_flags &= ~AIF_TARGET_COLLISION;
big_ship_collide_recover_start(Pl_objp, En_objp, &Pl_objp->pos, NULL);
} else {
// too close for comfort so fly to box point + 300
@@ -1301,7 +1301,7 @@ void ai_big_strafe_attack()
if ( ai_big_strafe_maybe_retreat(target_dist, &target_pos) )
return;
if (aip->ai_flags[AI::AI_Flags::Kamikaze]) {
if (aip->ai_flags & AIF_KAMIKAZE) {
if (target_dist < 1200.0f) {
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);
@@ -1313,7 +1313,7 @@ void ai_big_strafe_attack()
}
}
if (!(aip->ai_flags[AI::AI_Flags::Seek_lock]) || (aip->aspect_locked_time < 2.0f)) {
if (!(aip->ai_flags & AIF_SEEK_LOCK) || (aip->aspect_locked_time < 2.0f)) {
t = ai_endangered_by_weapon(aip);
if ( t > 0.0f && t < 1.5f ) {
// set up goal_point for avoid path to turn towards
@@ -1351,7 +1351,7 @@ void ai_big_strafe_attack()
turn_towards_point(Pl_objp, &target_pos, NULL, 0.0f);
fix last_hit = Missiontime - aip->last_hit_time;
if ( aip->ai_profile_flags[AI::Profile_Flags::Ai_can_slow_down_attacking_big_ships] ) {
if ( aip->ai_profile_flags2 & AIPF2_AI_CAN_SLOW_DOWN_ATTACKING_BIG_SHIPS ) {
// Slow down if we've not been hit for a while
if ( target_dist > 1200 || last_hit < F1_0*6) {
accel = 1.0f;
@@ -1622,7 +1622,7 @@ void ai_big_strafe_position()
aip = &Ai_info[Ships[Pl_objp->instance].ai_index];
//Maybe use AIS_STRAFE_GLIDE_ATTACK
if ((sip->can_glide == true) && !(aip->ai_flags[AI::AI_Flags::Kamikaze]) && (frand() < aip->ai_glide_strafe_percent)) {
if ((sip->can_glide == true) && !(aip->ai_flags & AIF_KAMIKAZE) && (frand() < aip->ai_glide_strafe_percent)) {
aip->submode = AIS_STRAFE_GLIDE_ATTACK;
aip->submode_parm1 = 0;
} else {
@@ -1809,8 +1809,8 @@ void ai_big_strafe_maybe_attack_turret(object *ship_objp, object *weapon_objp)
// the ai will not always go after different ships firing beams at them.
// Approx 1/4 chance we'll go after the other ship's beam.
bool attack_turret_on_different_ship = (aip->ai_profile_flags[AI::Profile_Flags::Big_ships_can_attack_beam_turrets_on_untargeted_ships])
&& (Weapon_info[Weapons[weapon_objp->instance].weapon_info_index].wi_flags[Weapon::Info_Flags::Beam]) && (frand()*100 < 25.0f);
bool attack_turret_on_different_ship = (aip->ai_profile_flags & AIPF_BIG_SHIPS_CAN_ATTACK_BEAM_TURRETS_ON_UNTARGETED_SHIPS)
&& (Weapon_info[Weapons[weapon_objp->instance].weapon_info_index].wi_flags & WIF_BEAM) && (frand()*100 < 25.0f);
// unless we're making an exception, we should only attack a turret if it sits on the current target
if ( !attack_turret_on_different_ship )
+514 -465
View File
File diff suppressed because it is too large. Load diff
+81 -130
View File
@@ -59,7 +59,6 @@ int Ai_goal_signature;
int Num_ai_dock_names = 0;
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 },
@@ -86,7 +85,6 @@ ai_goal_list Ai_goal_names[] =
{ "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);
@@ -98,34 +96,34 @@ int Num_ai_goals = sizeof(Ai_goal_names) / sizeof(ai_goal_list);
const char *Ai_goal_text(int goal)
{
switch(goal) {
case AI_GOAL_CHASE:
case AI_GOAL_CHASE_WING:
case AI_GOAL_CHASE_SHIP_CLASS:
case 1:
return XSTR( "attack ", 474);
case AI_GOAL_DOCK:
case 2:
return XSTR( "dock ", 475);
case AI_GOAL_WAYPOINTS:
case AI_GOAL_WAYPOINTS_ONCE:
case 3:
return XSTR( "waypoints", 476);
case AI_GOAL_DESTROY_SUBSYSTEM:
case 4:
return XSTR( "waypoints", 476);
case 6:
return XSTR( "destroy ", 477);
case AI_GOAL_FORM_ON_WING:
case 7:
return XSTR( "form on ", 478);
case AI_GOAL_UNDOCK:
case 8:
return XSTR( "undock ", 479);
case AI_GOAL_GUARD:
case AI_GOAL_GUARD_WING:
case 9:
return XSTR( "attack ", 474);
case 10:
return XSTR( "guard ", 480);
case AI_GOAL_DISABLE_SHIP:
case 11:
return XSTR( "disable ", 481);
case AI_GOAL_DISARM_SHIP:
case 12:
return XSTR( "disarm ", 482);
case AI_GOAL_EVADE_SHIP:
case 15:
return XSTR( "guard ", 480);
case 16:
return XSTR( "evade ", 483);
case AI_GOAL_REARM_REPAIR:
case 19:
return XSTR( "rearm ", 484);
case AI_GOAL_FLY_TO_SHIP:
return XSTR( "rendezvous with ", -1);
}
// Avoid compiler warning
@@ -240,7 +238,7 @@ void ai_remove_ship_goal( ai_info *aip, int index )
aip->goals[index].ai_mode = AI_GOAL_NONE;
aip->goals[index].signature = -1;
aip->goals[index].priority = -1;
aip->goals[index].flags.reset(); // must reset the flags since not doing so will screw up goal sorting.
aip->goals[index].flags = 0; // must reset the flags since not doing so will screw up goal sorting.
if ( index == aip->active_goal )
aip->active_goal = AI_GOAL_NONE;
@@ -289,7 +287,7 @@ void ai_clear_wing_goals( int wingnum )
wingp->ai_goals[i].ai_mode = AI_GOAL_NONE;
wingp->ai_goals[i].signature = -1;
wingp->ai_goals[i].priority = -1;
wingp->ai_goals[i].flags.reset();
wingp->ai_goals[i].flags = 0;
}
@@ -349,7 +347,7 @@ void ai_mission_wing_goal_complete( int wingnum, ai_goal *remove_goalp )
wingp->ai_goals[i].ai_mode = AI_GOAL_NONE;
wingp->ai_goals[i].signature = -1;
wingp->ai_goals[i].priority = -1;
wingp->ai_goals[i].flags.reset();
wingp->ai_goals[i].flags = 0;
break;
}
}
@@ -410,41 +408,31 @@ void ai_goal_purge_invalid_goals( ai_goal *aigp, ai_goal *goal_list, ai_info *ai
if ( purge_goal->target_name == NULL )
continue;
// goals operating on ship classes are handled slightly differently
if ( purge_ai_mode == AI_GOAL_CHASE_SHIP_CLASS ) {
// if the target of the purge goal is the same class of ship we are concerned about, then we have a match;
// if it is not, then we can continue (see standard ship check below)
if ( stricmp(purge_goal->target_name, Ship_info[Ships[ship_index].ship_info_index].name) )
continue;
}
// standard goals operating on either wings or ships
else {
// determine if the purge goal is acting either on the ship or the ship's wing.
purge_wing = wing_name_lookup( purge_goal->target_name, 1 );
// determine if the purge goal is acting either on the ship or the ship's wing.
purge_wing = wing_name_lookup( purge_goal->target_name, 1 );
// if the target of the purge goal is a ship (purge_wing will be -1), then if the names
// 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 ) )
continue;
} else if ( purge_wing != wingnum )
// if the target of the purge goal is a ship (purge_wing will be -1), then if the names
// 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 ) )
continue;
}
} else if ( purge_wing != wingnum )
continue;
switch (mode)
{
// ignore goals should get rid of any kind of attack goal
case AI_GOAL_IGNORE:
case AI_GOAL_IGNORE_NEW:
if ( purge_ai_mode & (AI_GOAL_DISABLE_SHIP | AI_GOAL_DISARM_SHIP | AI_GOAL_CHASE | AI_GOAL_CHASE_WING | AI_GOAL_CHASE_SHIP_CLASS | AI_GOAL_DESTROY_SUBSYSTEM) )
purge_goal->flags.set(AI::Goal_Flags::Purge);
if ( purge_ai_mode & (AI_GOAL_DISABLE_SHIP | AI_GOAL_DISARM_SHIP | AI_GOAL_CHASE | AI_GOAL_CHASE_WING | AI_GOAL_DESTROY_SUBSYSTEM) )
purge_goal->flags |= AIGF_PURGE;
break;
// disarm/disable goals should remove attacks from certain ships types
case AI_GOAL_DISARM_SHIP:
case AI_GOAL_DISABLE_SHIP:
if ( purge_ai_mode & (AI_GOAL_CHASE | AI_GOAL_CHASE_WING | AI_GOAL_CHASE_SHIP_CLASS) ) {
if ( purge_ai_mode & (AI_GOAL_CHASE | AI_GOAL_CHASE_WING) ) {
int ai_ship_type;
// for wings we grab the ship type of the wing leader
@@ -464,7 +452,7 @@ void ai_goal_purge_invalid_goals( ai_goal *aigp, ai_goal *goal_list, ai_info *ai
// being disarmed/disabled
for ( j=0 ; j < (int)crippled_ships_type->ai_cripple_ignores.size(); j++) {
if (crippled_ships_type->ai_cripple_ignores[j] == ai_ship_type) {
purge_goal->flags.set(AI::Goal_Flags::Purge);
purge_goal->flags |= AIGF_PURGE;
}
}
}
@@ -613,8 +601,7 @@ void ai_goal_fixup_dockpoints(ai_info *aip, ai_goal *aigp)
aigp->docker.index = docker_index;
aigp->dockee.index = dockee_index;
aigp->flags.set(AI::Goal_Flags::Dockee_index_valid);
aigp->flags.set(AI::Goal_Flags::Docker_index_valid);
aigp->flags |= AIGF_DOCK_INDEXES_VALID;
}
// these functions deal with adding goals sent from the player. They are slightly different
@@ -752,8 +739,7 @@ void ai_add_ship_goal_scripting(int mode, int submode, int priority, char *shipn
if ( mode == AI_GOAL_DOCK ) {
aigp->docker.name = Ships[aip->shipnum].ship_name;
aigp->dockee.name = shipname;
aigp->flags.remove(AI::Goal_Flags::Dockee_index_valid);
aigp->flags.remove(AI::Goal_Flags::Docker_index_valid);
aigp->flags &= ~AIGF_DOCK_INDEXES_VALID;
}
ai_add_goal_sub_scripting(AIG_TYPE_PLAYER_SHIP, mode, submode, priority, shipname, aigp);
@@ -832,7 +818,7 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_goal *aigp, char *actor_name )
aigp->target_name = NULL;
aigp->time = Missiontime;
aigp->type = type;
aigp->flags.reset();
aigp->flags = 0;
op = get_operator_const( text );
@@ -865,7 +851,7 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_goal *aigp, char *actor_name )
// store the name of the subsystem in the docker.name field for now -- this field must get
// fixed up when the goal is valid since we need to locate the subsystem on the ship's model
aigp->docker.name = ai_get_goal_target_name(CTEXT(CDR(CDR(node))), &dummy);
aigp->flags.set(AI::Goal_Flags::Subsys_needs_fixup);
aigp->flags |= AIGF_SUBSYS_NEEDS_FIXUP;
aigp->priority = atoi( CTEXT(CDR(CDR(CDR(node)))) );
break;
@@ -919,8 +905,7 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_goal *aigp, char *actor_name )
aigp->target_name = ai_get_goal_target_name( CTEXT(CDR(node)), &aigp->target_name_index );
aigp->docker.name = ai_add_dock_name(CTEXT(CDR(CDR(node))));
aigp->dockee.name = ai_add_dock_name(CTEXT(CDR(CDR(CDR(node)))));
aigp->flags.remove(AI::Goal_Flags::Dockee_index_valid);
aigp->flags.remove(AI::Goal_Flags::Docker_index_valid);
aigp->flags &= ~AIGF_DOCK_INDEXES_VALID;
aigp->priority = atoi( CTEXT(CDR(CDR(CDR(CDR(node))))) );
aigp->ai_mode = AI_GOAL_DOCK;
@@ -949,10 +934,9 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_goal *aigp, char *actor_name )
break;
case OP_AI_CHASE:
case OP_AI_CHASE_WING:
case OP_AI_CHASE_SHIP_CLASS:
case OP_AI_GUARD:
case OP_AI_GUARD_WING:
case OP_AI_CHASE_WING:
case OP_AI_EVADE_SHIP:
case OP_AI_STAY_NEAR_SHIP:
case OP_AI_IGNORE:
@@ -981,8 +965,6 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_goal *aigp, char *actor_name )
aigp->ai_mode = AI_GOAL_GUARD_WING;
} else if ( op == OP_AI_CHASE_WING ) {
aigp->ai_mode = AI_GOAL_CHASE_WING;
} else if (op == OP_AI_CHASE_SHIP_CLASS) {
aigp->ai_mode = AI_GOAL_CHASE_SHIP_CLASS;
} else if ( op == OP_AI_STAY_NEAR_SHIP ) {
aigp->ai_mode = AI_GOAL_STAY_NEAR_SHIP;
} else if ( op == OP_AI_IGNORE ) {
@@ -1004,13 +986,13 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_goal *aigp, char *actor_name )
}
// Goober5000 - we now have an extra optional chase argument to allow chasing our own team
if ( op == OP_AI_CHASE || op == OP_AI_CHASE_WING || op == OP_AI_CHASE_SHIP_CLASS || op == OP_AI_DISABLE_SHIP || op == OP_AI_DISARM_SHIP ) {
if ( op == OP_AI_CHASE || op == OP_AI_CHASE_WING || op == OP_AI_DISABLE_SHIP || op == OP_AI_DISARM_SHIP ) {
if ((CDDDR(node) != -1) && is_sexp_true(CDDDR(node)))
aigp->flags.set(AI::Goal_Flags::Target_own_team);
aigp->flags |= AIGF_TARGET_OWN_TEAM;
}
if ( op == OP_AI_DESTROY_SUBSYS ) {
if ((CDDDDR(node) != -1) && is_sexp_true(CDDDDR(node)))
aigp->flags.set(AI::Goal_Flags::Target_own_team);
aigp->flags |= AIGF_TARGET_OWN_TEAM;
}
// Goober5000 - since none of the goals act on the actor,
@@ -1022,7 +1004,7 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_goal *aigp, char *actor_name )
aigp->ai_mode = AI_GOAL_NONE;
aigp->signature = -1;
aigp->priority = -1;
aigp->flags.reset();
aigp->flags = 0;
}
}
@@ -1050,7 +1032,7 @@ int ai_find_goal_index( ai_goal* aigp, int mode, int submode, int priority )
/* Remove a goal from the given goals structure
* Returns the index of the goal that it clears out.
* This is important so that if active_goal == index you can set AI_GOAL_NONE
* This is importnat so that if active_goal == index you can set AI_GOAL_NONE
*/
int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp )
{
@@ -1152,10 +1134,6 @@ int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp )
priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
goalmode = AI_GOAL_CHASE_WING;
break;
case OP_AI_CHASE_SHIP_CLASS:
priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
goalmode = AI_GOAL_CHASE_SHIP_CLASS;
break;
case OP_AI_EVADE_SHIP:
priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
goalmode = AI_GOAL_EVADE_SHIP;
@@ -1188,7 +1166,7 @@ int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp )
aigp[goalindex].ai_mode = AI_GOAL_NONE;
aigp[goalindex].signature = -1;
aigp[goalindex].priority = -1;
aigp[goalindex].flags.reset(); // must reset the flags since not doing so will screw up goal sorting.
aigp[goalindex].flags = 0; // must reset the flags since not doing so will screw up goal sorting.
return goalindex;
}
@@ -1286,8 +1264,7 @@ void ai_add_goal_ship_internal( ai_info *aip, int goal_type, char *name, int doc
aigp->time = Missiontime;
aigp->type = AIG_TYPE_DYNAMIC;
aigp->flags.reset();
aigp->flags.set(AI::Goal_Flags::Goal_override);
aigp->flags = AIGF_GOAL_OVERRIDE;
switch ( goal_type ) {
@@ -1325,7 +1302,7 @@ void ai_add_goal_ship_internal( ai_info *aip, int goal_type, char *name, int doc
aigp->ai_submode = 0;
aigp->target_name = name;
aigp->priority = PLAYER_PRIORITY_MIN-1; // make the priority always less than what the player's is
aigp->flags.remove(AI::Goal_Flags::Goal_override); // don't override this goal. rearm repair requests should happen in order
aigp->flags &= ~AIGF_GOAL_OVERRIDE; // don't override this goal. rearm repair requests should happen in order
ai_goal_fixup_dockpoints( aip, aigp );
break;
@@ -1436,7 +1413,7 @@ int ai_mission_goal_achievable( int objnum, ai_goal *aigp )
if (sindex < 0)
return AI_GOAL_NOT_ACHIEVABLE;
aigp->flags.set(AI::Goal_Flags::Goal_override);
aigp->flags |= AIGF_GOAL_OVERRIDE;
return AI_GOAL_ACHIEVABLE;
}
@@ -1454,18 +1431,6 @@ int ai_mission_goal_achievable( int objnum, ai_goal *aigp )
return AI_GOAL_ACHIEVABLE;
}
// chasing all ships of a certain ship class is achievable if there are ships of that class present;
// if not, the status is not known because more ships of that class could arrive in the future
// (c.f. AI_GOAL_CHASE_WING subsequent to the next switch statement)
if ( aigp->ai_mode == AI_GOAL_CHASE_SHIP_CLASS ) {
for (objp = GET_FIRST(&obj_used_list); objp != END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp)) {
if ((objp->type == OBJ_SHIP) && !strcmp(aigp->target_name, Ship_info[Ships[objp->instance].ship_info_index].name)) {
return AI_GOAL_ACHIEVABLE;
}
}
return AI_GOAL_NOT_KNOWN;
}
return_val = AI_GOAL_SATISFIED;
@@ -1491,7 +1456,7 @@ int ai_mission_goal_achievable( int objnum, ai_goal *aigp )
// can't determine the status of this goal if ship not valid
// or we haven't found a valid subsystem index yet
if ( (sindex == -1) || (aigp->flags[AI::Goal_Flags::Subsys_needs_fixup]) ) {
if ( (sindex == -1) || (aigp->flags & AIGF_SUBSYS_NEEDS_FIXUP) ) {
status = 0;
break;
}
@@ -1608,7 +1573,7 @@ int ai_mission_goal_achievable( int objnum, ai_goal *aigp )
wing *wingp = &Wings[sindex];
if ( wingp->flags[Ship::Wing_Flags::Gone] )
if ( wingp->flags & WF_WING_GONE )
return AI_GOAL_NOT_ACHIEVABLE;
else if ( wingp->total_arrived_count == 0 )
return AI_GOAL_NOT_KNOWN;
@@ -1640,7 +1605,7 @@ int ai_mission_goal_achievable( int objnum, ai_goal *aigp )
}
else
{
mprintf(("Potentially incorrect behaviour in AI goal for ship %s: Ship %s could not be found among currently active, departed, or yet-to-arrive ships.\nPlease check the mission file.\n", Ships[objp->instance].ship_name, aigp->target_name));
Int3(); // get ALLENDER
status = SHIP_STATUS_UNKNOWN;
}
}
@@ -1655,15 +1620,15 @@ int ai_mission_goal_achievable( int objnum, ai_goal *aigp )
// if the goal is an ignore/disable/disarm goal, then
// Goober5000 - see note at PURGE_GOALS_ALL_SHIPS... this is bizarre
if ((status == SHIP_STATUS_ARRIVED) && !(aigp->flags[AI::Goal_Flags::Goals_purged]))
if ((status == SHIP_STATUS_ARRIVED) && !(aigp->flags & AIGF_GOALS_PURGED))
{
if (aigp->ai_mode & PURGE_GOALS_ALL_SHIPS) {
ai_goal_purge_all_invalid_goals(aigp);
aigp->flags.set(AI::Goal_Flags::Goals_purged);
aigp->flags |= AIGF_GOALS_PURGED;
}
else if (aigp->ai_mode & PURGE_GOALS_ONE_SHIP) {
ai_goal_purge_invalid_goals(aigp, aip->goals, aip, -1);
aigp->flags.set(AI::Goal_Flags::Goals_purged);
aigp->flags |= AIGF_GOALS_PURGED;
}
}
@@ -1671,21 +1636,21 @@ int ai_mission_goal_achievable( int objnum, ai_goal *aigp )
// only enter this calculation if the ship we are docking with has arrived. If the ship is gone, then
// this goal will get removed.
if ( (aigp->ai_mode == AI_GOAL_DOCK) && (status == SHIP_STATUS_ARRIVED) ) {
if (!(aigp->flags[AI::Goal_Flags::Docker_index_valid])) {
if (!(aigp->flags & AIGF_DOCKER_INDEX_VALID)) {
modelnum = Ship_info[Ships[objp->instance].ship_info_index].model_num;
Assert( modelnum >= 0 );
index = model_find_dock_name_index(modelnum, aigp->docker.name);
aigp->docker.index = index;
aigp->flags.set(AI::Goal_Flags::Docker_index_valid);
aigp->flags |= AIGF_DOCKER_INDEX_VALID;
}
if (!(aigp->flags[AI::Goal_Flags::Dockee_index_valid])) {
if (!(aigp->flags & AIGF_DOCKEE_INDEX_VALID)) {
sindex = ship_name_lookup(aigp->target_name);
if ( sindex != -1 ) {
modelnum = Ship_info[Ships[sindex].ship_info_index].model_num;
index = model_find_dock_name_index(modelnum, aigp->dockee.name);
aigp->dockee.index = index;
aigp->flags.set(AI::Goal_Flags::Dockee_index_valid);
aigp->flags |= AIGF_DOCKEE_INDEX_VALID;
} else
aigp->dockee.index = -1; // this will force code into if statement below making goal not achievable.
}
@@ -1735,7 +1700,7 @@ int ai_mission_goal_achievable( int objnum, ai_goal *aigp )
else if (obstacle_objp != goal_objp)
{
// if this goal isn't on hold yet, then issue the undock goal
if ( !(aigp->flags[AI::Goal_Flags::Goal_on_hold]) )
if ( !(aigp->flags & AIGF_GOAL_ON_HOLD) )
ai_add_goal_ship_internal( aip, AI_GOAL_UNDOCK, Ships[obstacle_objp->instance].ship_name, -1, -1, 0 );
// return NOT_KNOWN which will place the goal on hold until the undocking is complete.
@@ -1760,12 +1725,12 @@ int ai_mission_goal_achievable( int objnum, ai_goal *aigp )
// if the ship has arrived, and the goal is destroy subsystem, then check to see that we
// have fixed up the subsystem name (of the subsystem to destroy) into an index into
// the ship's subsystem list
if ( aigp->flags[AI::Goal_Flags::Subsys_needs_fixup] ) {
if ( aigp->flags & AIGF_SUBSYS_NEEDS_FIXUP ) {
sindex = ship_name_lookup( aigp->target_name );
if ( sindex != -1 ) {
aigp->ai_submode = ship_get_subsys_index( &Ships[sindex], aigp->docker.name );
aigp->flags.remove(AI::Goal_Flags::Subsys_needs_fixup);
aigp->flags &= ~AIGF_SUBSYS_NEEDS_FIXUP;
} else {
Int3();
return AI_GOAL_NOT_ACHIEVABLE; // force this goal to be invalid
@@ -1837,7 +1802,7 @@ int ai_mission_goal_achievable( int objnum, ai_goal *aigp )
}
// if desitnation currently being repaired, then goal is stil active
if ( Ai_info[Ships[sindex].ai_index].ai_flags[AI::AI_Flags::Being_repaired] )
if ( Ai_info[Ships[sindex].ai_index].ai_flags & AIF_BEING_REPAIRED )
return AI_GOAL_ACHIEVABLE;
// if the destination ship is dying or departing (but not completed yet), the mark goal as
@@ -1846,11 +1811,11 @@ int ai_mission_goal_achievable( int objnum, ai_goal *aigp )
return AI_GOAL_NOT_ACHIEVABLE;
// if the destination object is no longer awaiting repair, then remove the item
if ( !(Ai_info[Ships[sindex].ai_index].ai_flags[AI::AI_Flags::Awaiting_repair]) )
if ( !(Ai_info[Ships[sindex].ai_index].ai_flags & AIF_AWAITING_REPAIR) )
return AI_GOAL_NOT_ACHIEVABLE;
// not repairing anything means that he can do this goal!!!
if ( !(aip->ai_flags[AI::AI_Flags::Repairing]) )
if ( !(aip->ai_flags & AIF_REPAIRING) )
return AI_GOAL_ACHIEVABLE;
// test code!!!
@@ -1887,17 +1852,17 @@ int ai_goal_priority_compare(const void *a, const void *b)
// If the flag is set, don't push the goal higher in the list even if priority
// is higher since goal cannot currently be achieved.
if ( (ga->flags[AI::Goal_Flags::Goal_on_hold]) && !(gb->flags[AI::Goal_Flags::Goal_on_hold]) )
if ( (ga->flags & AIGF_GOAL_ON_HOLD) && !(gb->flags & AIGF_GOAL_ON_HOLD) )
return 1;
else if ( !(ga->flags[AI::Goal_Flags::Goal_on_hold]) && (gb->flags[AI::Goal_Flags::Goal_on_hold]) )
else if ( !(ga->flags & AIGF_GOAL_ON_HOLD) && (gb->flags & AIGF_GOAL_ON_HOLD) )
return -1;
// check whether or not the goal override flag is set. If it is set, then push this goal higher
// in the list
else if ( (ga->flags[AI::Goal_Flags::Goal_override]) && !(gb->flags[AI::Goal_Flags::Goal_override]) )
else if ( (ga->flags & AIGF_GOAL_OVERRIDE) && !(gb->flags & AIGF_GOAL_OVERRIDE) )
return -1;
else if ( !(ga->flags[AI::Goal_Flags::Goal_override]) && (gb->flags[AI::Goal_Flags::Goal_override]) )
else if ( !(ga->flags & AIGF_GOAL_OVERRIDE) && (gb->flags & AIGF_GOAL_OVERRIDE) )
return 1;
// now normal priority processing
@@ -1952,7 +1917,7 @@ void validate_mission_goals(int objnum, ai_info *aip)
continue;
// purge any goals which should get purged
if ( aigp->flags[AI::Goal_Flags::Purge] ) {
if ( aigp->flags & AIGF_PURGE ) {
ai_remove_ship_goal( aip, i );
continue;
}
@@ -1966,19 +1931,19 @@ void validate_mission_goals(int objnum, ai_info *aip)
}
// if the status is achievable, and the on_hold flag is set, clear the flagb
if ( (state == AI_GOAL_ACHIEVABLE) && (aigp->flags[AI::Goal_Flags::Goal_on_hold]) )
aigp->flags.remove(AI::Goal_Flags::Goal_on_hold);
if ( (state == AI_GOAL_ACHIEVABLE) && (aigp->flags & AIGF_GOAL_ON_HOLD) )
aigp->flags &= ~AIGF_GOAL_ON_HOLD;
// if the goal is not known, then set the ON_HOLD flag so that it doesn't get counted as
// a goal to be pursued
if (state == AI_GOAL_NOT_KNOWN)
aigp->flags.set(AI::Goal_Flags::Goal_on_hold); // put this goal on hold until it becomes true
if ( state == AI_GOAL_NOT_KNOWN )
aigp->flags |= AIGF_GOAL_ON_HOLD; // put this goal on hold until it becomes true
}
// if we had an active goal, and that goal is now in hold, make the mode AIM_NONE. If a new valid
// goal is produced after prioritizing, then the mode will get reset immediately. Otherwise, setting
// the mode to none will force ship to do default behavior.
if ( (aip->goals[0].ai_mode != AI_GOAL_NONE) && (aip->goals[0].flags[AI::Goal_Flags::Goal_on_hold]) )
if ( (aip->goals[0].ai_mode != AI_GOAL_NONE) && (aip->goals[0].flags & AIGF_GOAL_ON_HOLD) )
aip->mode = AIM_NONE;
// if the active goal is a rearm/repair goal, the put all other valid goals (which are not repair goals)
@@ -1987,7 +1952,7 @@ void validate_mission_goals(int objnum, ai_info *aip)
for ( i = 1; i < MAX_AI_GOALS; i++ ) {
if ( (aip->goals[i].ai_mode == AI_GOAL_NONE) || (aip->goals[i].ai_mode == AI_GOAL_REARM_REPAIR) )
continue;
aip->goals[i].flags.set(AI::Goal_Flags::Goal_on_hold);
aip->goals[i].flags |= AIGF_GOAL_ON_HOLD;
}
}
}
@@ -2055,7 +2020,7 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
// if the first goal in the list has the ON_HOLD flag, set, there is no current valid goal
// to pursue.
if ( aip->goals[0].flags[AI::Goal_Flags::Goal_on_hold] )
if ( aip->goals[0].flags & AIGF_GOAL_ON_HOLD )
return;
// Kind of a hack for now. active_goal means the goal currently being pursued.
@@ -2073,7 +2038,7 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
// if this object was flying in formation off of another object, remove the flag that tells him
// to do this. The form-on-my-wing command is removed from the goal list as soon as it is called, so
// we are safe removing this bit here.
aip->ai_flags.remove(AI::AI_Flags::Formation_object);
aip->ai_flags &= ~AIF_FORMATION_OBJECT;
// Goober5000 - we may want to use AI for the player
// AL 3-7-98: If this is a player ship, and the goal is not a formation goal, then do a quick out
@@ -2151,7 +2116,7 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
// be sure that we have indices for docking points here! If we ever had names, they should
// get fixed up in goal_achievable so that the points can be checked there for validity
Assert (current_goal->flags[AI::Goal_Flags::Dockee_index_valid] && current_goal->flags[AI::Goal_Flags::Docker_index_valid]);
Assert (current_goal->flags & AIGF_DOCK_INDEXES_VALID);
ai_dock_with_object( objp, current_goal->docker.index, other_obj, current_goal->dockee.index, AIDO_DOCK );
break;
}
@@ -2233,7 +2198,7 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
if (current_goal->ai_mode != AI_GOAL_DESTROY_SUBSYSTEM) {
if (aip->target_objnum != -1) {
// Only protect if _not_ a capital ship. We don't want the Lucifer accidentally getting protected.
if (Ship_types[Ship_info[Ships[shipnum].ship_info_index].class_type].flags[Ship::Type_Info_Flags::AI_protected_on_cripple])
if (Ship_types[Ship_info[Ships[shipnum].ship_info_index].class_type].ai_bools & STI_AI_PROTECTED_ON_CRIPPLE)
Objects[aip->target_objnum].flags.set(Object::Object_Flags::Protected);
}
} else // Just in case this ship had been protected, unprotect it.
@@ -2245,7 +2210,7 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
case AI_GOAL_CHASE_WING:
wingnum = wing_name_lookup( current_goal->target_name );
Assertion( wingnum >= 0, "The target of AI_GOAL_CHASE_WING must refer to a valid wing!" );
Assert( wingnum >= 0 );
ai_attack_wing(objp, wingnum);
break;
@@ -2253,13 +2218,6 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
ai_attack_object( objp, NULL, NULL );
break;
// chase-ship-class is chase-any but restricted to a subset of ships
case AI_GOAL_CHASE_SHIP_CLASS:
shipnum = ship_info_lookup( current_goal->target_name );
Assertion( shipnum >= 0, "The target of AI_GOAL_CHASE_SHIP_CLASS must refer to a valid ship class!" );
ai_attack_object( objp, NULL, NULL, shipnum );
break;
case AI_GOAL_WARP: {
mission_do_departure( objp, true );
break;
@@ -2389,22 +2347,15 @@ void ai_update_goal_references(ai_goal *goals, int type, const char *old_name, c
flag = 1;
}
break;
default:
Warning(LOCATION, "unhandled FRED reference type %d in ai_update_goal_references", type);
break;
}
if (flag) // is this a valid goal to parse for this conversion?
{
if (!stricmp(goals[i].target_name, old_name))
{
if (!stricmp(goals[i].target_name, old_name)) {
if (*new_name == '<') // target was just deleted..
goals[i].ai_mode = AI_GOAL_NONE;
else
goals[i].target_name = ai_get_goal_target_name(new_name, &dummy);
}
}
}
}
+1 -4
View File
@@ -26,7 +26,6 @@ struct ai_goal;
// Fred. If the goal you add doesn't have a target (such as chase_any), then you don't have
// to worry about doing this. Also add it to list in Fred\Management.cpp, and let Hoffoss know!
// WMC - Oh and add them to Ai_goal_names plz. TY! :)
// Goober5000 - As well as Ai_goal_text and Ai_goal_list, if appropriate
#define AI_GOAL_CHASE (1<<1) // 0x00000002
#define AI_GOAL_DOCK (1<<2) // 0x00000004 // used for undocking as well
#define AI_GOAL_WAYPOINTS (1<<3) // 0x00000008
@@ -52,12 +51,10 @@ struct ai_goal;
// resume regular goals
#define AI_GOAL_STAY_STILL (1<<20) // 0x00100000
#define AI_GOAL_PLAY_DEAD (1<<21) // 0x00200000
// added by SCP
#define AI_GOAL_CHASE_WEAPON (1<<22) // 0x00400000
#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
// now the masks for ship types
+179 -123
View File
@@ -14,7 +14,7 @@
#include "network/multi.h"
#include "network/multimsgs.h"
#include "object/objectdock.h"
#include "scripting/scripting.h"
#include "parse/scripting.h"
#include "render/3d.h"
#include "ship/ship.h"
#include "ship/shipfx.h"
@@ -47,7 +47,7 @@ float Player_lethality_bump[NUM_SKILL_LEVELS] = {
0.0f, 0.0f, 0.0f, 0.0f, 0.0f
};
const char *Turret_target_order_names[NUM_TURRET_ORDER_TYPES] = {
char *Turret_target_order_names[NUM_TURRET_ORDER_TYPES] = {
"Bombs",
"Ships",
"Asteroids",
@@ -158,7 +158,7 @@ bool is_object_radius_in_turret_fov(object *objp, ship_subsys *ss, vec3d *tvec,
fix_elevation = true;
}
if (tp->flags[Model::Subsystem_Flags::Turret_alt_math]) {
if (tp->flags & MSS_FLAG_TURRET_ALT_MATH) {
vec3d temp_vec2;
vm_vec_rotate(&temp_vec2, &temp_vec, &ss->world_to_turret_matrix);
@@ -256,46 +256,54 @@ int turret_select_best_weapon(ship_subsys *turret, object *target)
/**
* Returns true if all weapons in swp have the specified flag
*
* @note doesn't work for WIF2
*/
bool all_turret_weapons_have_flags(ship_weapon *swp, flagset<Weapon::Info_Flags> flags)
bool all_turret_weapons_have_flags(ship_weapon *swp, int flags)
{
int i;
for(i = 0; i < swp->num_primary_banks; i++)
{
if(!(Weapon_info[swp->primary_bank_weapons[i]].wi_flags & flags).any_set())
if(!(Weapon_info[swp->primary_bank_weapons[i]].wi_flags & flags))
return false;
}
for(i = 0; i < swp->num_secondary_banks; i++)
{
if(!(Weapon_info[swp->secondary_bank_weapons[i]].wi_flags & flags).any_set())
if(!(Weapon_info[swp->secondary_bank_weapons[i]].wi_flags & flags))
return false;
}
return true;
}
bool all_turret_weapons_have_flags(ship_weapon *swp, Weapon::Info_Flags flags)
/**
* Returns true if all weapons in swp have the specified flag
*
* @note does work for WIF2, but not WIF
*/
bool all_turret_weapons_have_flags2(ship_weapon *swp, int flags)
{
int i;
for (i = 0; i < swp->num_primary_banks; i++)
{
if (!(Weapon_info[swp->primary_bank_weapons[i]].wi_flags[flags]))
return false;
}
for (i = 0; i < swp->num_secondary_banks; i++)
{
if (!(Weapon_info[swp->secondary_bank_weapons[i]].wi_flags[flags]))
return false;
}
int i;
for(i = 0; i < swp->num_primary_banks; i++)
{
if(!(Weapon_info[swp->primary_bank_weapons[i]].wi_flags2 & flags))
return false;
}
for(i = 0; i < swp->num_secondary_banks; i++)
{
if(!(Weapon_info[swp->secondary_bank_weapons[i]].wi_flags2 & flags))
return false;
}
return true;
return true;
}
/**
* Returns true if any of the weapons in swp have flags
*
* @note doesn't work for WIF2
*/
bool turret_weapon_has_flags(ship_weapon *swp, Weapon::Info_Flags flags)
bool turret_weapon_has_flags(ship_weapon *swp, int flags)
{
Assert(swp != NULL);
@@ -303,14 +311,42 @@ bool turret_weapon_has_flags(ship_weapon *swp, Weapon::Info_Flags flags)
for(i = 0; i < swp->num_primary_banks; i++)
{
if(swp->primary_bank_weapons[i] >=0) {
if(Weapon_info[swp->primary_bank_weapons[i]].wi_flags[flags])
if(Weapon_info[swp->primary_bank_weapons[i]].wi_flags & flags)
return true;
}
}
for(i = 0; i < swp->num_secondary_banks; i++)
{
if(swp->secondary_bank_weapons[i] >=0) {
if(Weapon_info[swp->secondary_bank_weapons[i]].wi_flags[flags])
if(Weapon_info[swp->secondary_bank_weapons[i]].wi_flags & flags)
return true;
}
}
return false;
}
/**
* Returns true if any of the weapons in swp have flags
*
* @note does work for WIF2, but not WIF
*/
bool turret_weapon_has_flags2(ship_weapon *swp, int flags)
{
Assert(swp != NULL);
int i = 0;
for(i = 0; i < swp->num_primary_banks; i++)
{
if(swp->primary_bank_weapons[i] >=0) {
if(Weapon_info[swp->primary_bank_weapons[i]].wi_flags2 & flags)
return true;
}
}
for(i = 0; i < swp->num_secondary_banks; i++)
{
if(swp->secondary_bank_weapons[i] >=0) {
if(Weapon_info[swp->secondary_bank_weapons[i]].wi_flags2 & flags)
return true;
}
}
@@ -321,12 +357,11 @@ bool turret_weapon_has_flags(ship_weapon *swp, Weapon::Info_Flags flags)
/**
* Just gloms all the flags from all the weapons into one variable. More efficient if all you need to do is test for the existence of a flag.
*/
flagset<Weapon::Info_Flags> turret_weapon_aggregate_flags(ship_weapon *swp)
int turret_weapon_aggregate_flags(ship_weapon *swp)
{
Assert(swp != NULL);
int i = 0;
flagset<Weapon::Info_Flags> flags;
int i = 0, flags = 0;
for (i = 0; i < swp->num_primary_banks; i++)
{
if (swp->primary_bank_weapons[i] >= 0) {
@@ -343,6 +378,30 @@ flagset<Weapon::Info_Flags> turret_weapon_aggregate_flags(ship_weapon *swp)
return flags;
}
/**
* Just gloms all the flags from all the weapons into one variable. More efficient if all you need to do is test for the existence of a flag.
*/
int turret_weapon_aggregate_flags2(ship_weapon *swp)
{
Assert(swp != NULL);
int i = 0, flags2 = 0;
for (i = 0; i < swp->num_primary_banks; i++)
{
if (swp->primary_bank_weapons[i] >= 0) {
flags2 |= Weapon_info[swp->primary_bank_weapons[i]].wi_flags2;
}
}
for (i = 0; i < swp->num_secondary_banks; i++)
{
if (swp->secondary_bank_weapons[i] >= 0) {
flags2 |= Weapon_info[swp->secondary_bank_weapons[i]].wi_flags2;
}
}
return flags2;
}
/**
* Returns true if any of the weapons in swp have the subtype specified
*
@@ -414,7 +473,7 @@ float longest_turret_weapon_range(ship_weapon *swp)
for(i = 0; i < swp->num_primary_banks; i++)
{
wip = &Weapon_info[swp->primary_bank_weapons[i]];
if (wip->wi_flags[Weapon::Info_Flags::Local_ssm])
if (wip->wi_flags2 & WIF2_LOCAL_SSM)
weapon_range = wip->lssm_lock_range;
else
weapon_range = MIN(wip->lifetime * wip->max_speed, wip->weapon_range);
@@ -425,7 +484,7 @@ float longest_turret_weapon_range(ship_weapon *swp)
for(i = 0; i < swp->num_secondary_banks; i++)
{
wip = &Weapon_info[swp->secondary_bank_weapons[i]];
if (wip->wi_flags[Weapon::Info_Flags::Local_ssm])
if (wip->wi_flags2 & WIF2_LOCAL_SSM)
weapon_range = wip->lssm_lock_range;
else
weapon_range = MIN(wip->lifetime * wip->max_speed, wip->weapon_range);
@@ -478,7 +537,7 @@ int valid_turret_enemy(object *objp, object *turret_parent)
}
// Goober5000 - don't fire at cargo containers (now specified in ship_types)
if ( (sip->class_type >= 0) && !(Ship_types[sip->class_type].flags[Ship::Type_Info_Flags::AI_turrets_attack]) ) {
if ( (sip->class_type >= 0) && !(Ship_types[sip->class_type].ai_bools & STI_AI_TURRETS_ATTACK) ) {
return 0;
}
@@ -490,15 +549,15 @@ int valid_turret_enemy(object *objp, object *turret_parent)
weapon *wp = &Weapons[objp->instance];
weapon_info *wip = &Weapon_info[wp->weapon_info_index];
if (wip->subtype == WP_LASER && !(wip->wi_flags[Weapon::Info_Flags::Turret_Interceptable])) { // If the thing can't be shot down, don't try. -MageKing17
if (wip->subtype == WP_LASER && !(wip->wi_flags3 & WIF3_TURRET_INTERCEPTABLE)) { // If the thing can't be shot down, don't try. -MageKing17
return 0;
}
if ( (!((wip->wi_flags[Weapon::Info_Flags::Bomb]) || (wip->wi_flags[Weapon::Info_Flags::Turret_Interceptable])) && !(Ai_info[Ships[turret_parent->instance].ai_index].ai_profile_flags[AI::Profile_Flags::Allow_turrets_target_weapons_freely]) ) ) {
if ( (!((wip->wi_flags & WIF_BOMB) || (wip->wi_flags3 & WIF3_TURRET_INTERCEPTABLE)) && !(Ai_info[Ships[turret_parent->instance].ai_index].ai_profile_flags & AIPF_ALLOW_TURRETS_TARGET_WEAPONS_FREELY) ) ) {
return 0;
}
if ( (wip->wi_flags[Weapon::Info_Flags::Local_ssm]) && (wp->lssm_stage == 3) ) {
if ( (wip->wi_flags2 & WIF2_LOCAL_SSM) && (wp->lssm_stage == 3) ) {
return 0;
}
@@ -598,8 +657,8 @@ void evaluate_obj_as_target(object *objp, eval_enemy_obj_struct *eeo)
// however if this is removed turrets still track targets but don't fire at them (which looks silly)
if (eeo->eeo_flags & EEOF_TAGGED_ONLY) {
if (!ship_is_tagged(objp) &&
( (The_mission.ai_profile->flags[AI::Profile_Flags::Strict_turred_tagged_only_targeting]) ||
( !(objp->type == OBJ_WEAPON) && !(turret_weapon_has_flags(&eeo->turret_subsys->weapons, Weapon::Info_Flags::Spawn))) )) {
( (The_mission.ai_profile->flags2 & AIPF2_STRICT_TURRET_TAGGED_ONLY_TARGETING) ||
( !(objp->type == OBJ_WEAPON) && !(turret_weapon_has_flags(&eeo->turret_subsys->weapons, WIF_SPAWN))) )) {
return;
}
}
@@ -656,7 +715,7 @@ void evaluate_obj_as_target(object *objp, eval_enemy_obj_struct *eeo)
// check if bomb is homing on the turret parent ship
bool check_weapon = true;
if ((Ai_info[Ships[turret_parent_obj->instance].ai_index].ai_profile_flags[AI::Profile_Flags::Prevent_targeting_bombs_beyond_range]) && (dist > eeo->weapon_travel_dist)) {
if ((Ai_info[Ships[turret_parent_obj->instance].ai_index].ai_profile_flags & AIPF_PREVENT_TARGETING_BOMBS_BEYOND_RANGE) && (dist > eeo->weapon_travel_dist)) {
check_weapon = false;
}
@@ -783,12 +842,12 @@ void evaluate_obj_as_target(object *objp, eval_enemy_obj_struct *eeo)
int is_target_beam_valid(ship_weapon *swp, object *objp)
{
// check if turret has beam weapon
if (all_turret_weapons_have_flags(swp, Weapon::Info_Flags::Beam)) {
if (all_turret_weapons_have_flags(swp, WIF_BEAM)) {
if (objp->flags[Object::Object_Flags::Beam_protected]) {
return 0;
}
if (all_turret_weapons_have_flags(swp, Weapon::Info_Flags::Huge)) {
if (all_turret_weapons_have_flags(swp, WIF_HUGE)) {
if (objp->type == OBJ_SHIP && !(Ship_info[Ships[objp->instance].ship_info_index].is_big_or_huge()) ) {
return 0;
}
@@ -830,7 +889,7 @@ int get_nearest_turret_objnum(int turret_parent_objnum, ship_subsys *turret_subs
//wip=&Weapon_info[tp->turret_weapon_type];
//weapon_travel_dist = MIN(wip->lifetime * wip->max_speed, wip->weapon_range);
//if (wip->wi_flags[Weapon::Info_Flags::Local_ssm])
//if (wip->wi_flags2 & WIF2_LOCAL_SSM)
// weapon_travel_dist=wip->lssm_lock_range;
// Set flag based on strength of weapons subsystem. If weapons subsystem is destroyed, don't let turrets fire at bombs
@@ -901,8 +960,8 @@ int get_nearest_turret_objnum(int turret_parent_objnum, ship_subsys *turret_subs
n_tgt_priorities = Weapon_info[priority_weapon_idx].num_targeting_priorities;
}
if (n_tgt_priorities > 0)
{
if (n_tgt_priorities > 0) {
for(int i = 0; i < n_tgt_priorities; i++) {
// courtesy of WMC...
ai_target_priority *tt;
@@ -949,8 +1008,10 @@ int get_nearest_turret_objnum(int turret_parent_objnum, ship_subsys *turret_subs
}
}
if( (tt->wif_flags.any_set()) && (ptr->type == OBJ_WEAPON) ) {
if( ( (Weapon_info[Weapons[ptr->instance].weapon_info_index].wi_flags & tt->wif_flags ) == tt->wif_flags) ) {
if( ( (tt->wif_flags != 0) || (tt->wif2_flags != 0) || (tt->wif3_flags != 0) ) && (ptr->type == OBJ_WEAPON) ) {
if( ( (Weapon_info[Weapons[ptr->instance].weapon_info_index].wi_flags & tt->wif_flags ) == tt->wif_flags)
&& ( (Weapon_info[Weapons[ptr->instance].weapon_info_index].wi_flags2 & tt->wif2_flags ) == tt->wif2_flags)
&& ( (Weapon_info[Weapons[ptr->instance].weapon_info_index].wi_flags3 & tt->wif3_flags ) == tt->wif3_flags) ) {
found_something = true;
}
}
@@ -1026,11 +1087,7 @@ int get_nearest_turret_objnum(int turret_parent_objnum, ship_subsys *turret_subs
return return_objnum;
}
}
} else
{
flagset<Weapon::Info_Flags> tmp_flagset;
const Weapon::Info_Flags weapon_flags[] = { Weapon::Info_Flags::Huge, Weapon::Info_Flags::Flak, Weapon::Info_Flags::Homing_aspect, Weapon::Info_Flags::Homing_heat, Weapon::Info_Flags::Homing_javelin, Weapon::Info_Flags::Spawn };
tmp_flagset.set_multiple(std::begin(weapon_flags), std::end(weapon_flags));
} else {
for(int i = 0; i < NUM_TURRET_ORDER_TYPES; i++)
{
@@ -1044,14 +1101,14 @@ int get_nearest_turret_objnum(int turret_parent_objnum, ship_subsys *turret_subs
case 0:
//Return if a bomb is found
//don't fire anti capital ship turrets at bombs.
if ( !((aip->ai_profile_flags[AI::Profile_Flags::Huge_turret_weapons_ignore_bombs]) && big_only_flag) )
if ( !((aip->ai_profile_flags & AIPF_HUGE_TURRET_WEAPONS_IGNORE_BOMBS) && big_only_flag) )
{
// Missile_obj_list
for( mo = GET_FIRST(&Missile_obj_list); mo != END_OF_LIST(&Missile_obj_list); mo = GET_NEXT(mo) ) {
objp = &Objects[mo->objnum];
Assert(objp->type == OBJ_WEAPON);
if ((Weapon_info[Weapons[objp->instance].weapon_info_index].wi_flags[Weapon::Info_Flags::Bomb]) || (Weapon_info[Weapons[objp->instance].weapon_info_index].wi_flags[Weapon::Info_Flags::Turret_Interceptable]))
if ((Weapon_info[Weapons[objp->instance].weapon_info_index].wi_flags & WIF_BOMB) || (Weapon_info[Weapons[objp->instance].weapon_info_index].wi_flags3 & WIF3_TURRET_INTERCEPTABLE))
{
evaluate_obj_as_target(objp, &eeo);
}
@@ -1094,8 +1151,7 @@ int get_nearest_turret_objnum(int turret_parent_objnum, ship_subsys *turret_subs
// - lasers
// - dumbfire type missiles
// - AAA beams
if ( !all_turret_weapons_have_flags(swp, tmp_flagset) ) {
if ( !all_turret_weapons_have_flags(swp, WIF_HUGE | WIF_FLAK | WIF_HOMING | WIF_SPAWN) ) {
// Asteroid_obj_list
for ( ao = GET_FIRST(&Asteroid_obj_list); ao != END_OF_LIST(&Asteroid_obj_list); ao = GET_NEXT(ao) ) {
objp = &Objects[ao->objnum];
@@ -1136,12 +1192,12 @@ int find_turret_enemy(ship_subsys *turret_subsys, int objnum, vec3d *tpos, vec3d
enemy_team_mask = iff_get_attackee_mask(obj_team(&Objects[objnum]));
bool big_only_flag = all_turret_weapons_have_flags(&turret_subsys->weapons, Weapon::Info_Flags::Huge);
bool small_only_flag = all_turret_weapons_have_flags(&turret_subsys->weapons, Weapon::Info_Flags::Small_only);
bool tagged_only_flag = all_turret_weapons_have_flags(&turret_subsys->weapons, Weapon::Info_Flags::Tagged_only) || (turret_subsys->weapons.flags[Ship::Weapon_Flags::Tagged_Only]);
bool big_only_flag = all_turret_weapons_have_flags(&turret_subsys->weapons, WIF_HUGE);
bool small_only_flag = all_turret_weapons_have_flags2(&turret_subsys->weapons, WIF2_SMALL_ONLY);
bool tagged_only_flag = all_turret_weapons_have_flags2(&turret_subsys->weapons, WIF2_TAGGED_ONLY) || (turret_subsys->weapons.flags & SW_FLAG_TAGGED_ONLY);
bool beam_flag = turret_weapon_has_flags(&turret_subsys->weapons, Weapon::Info_Flags::Beam);
bool flak_flag = turret_weapon_has_flags(&turret_subsys->weapons, Weapon::Info_Flags::Flak);
bool beam_flag = turret_weapon_has_flags(&turret_subsys->weapons, WIF_BEAM);
bool flak_flag = turret_weapon_has_flags(&turret_subsys->weapons, WIF_FLAK);
bool laser_flag = turret_weapon_has_subtype(&turret_subsys->weapons, WP_LASER);
bool missile_flag = turret_weapon_has_subtype(&turret_subsys->weapons, WP_MISSILE);
@@ -1149,7 +1205,7 @@ int find_turret_enemy(ship_subsys *turret_subsys, int objnum, vec3d *tpos, vec3d
ai_info *aip = &Ai_info[Ships[Objects[objnum].instance].ai_index];
sip = &Ship_info[Ships[Objects[objnum].instance].ship_info_index];
if ((Ship_types[sip->class_type].flags[Ship::Type_Info_Flags::Turret_tgt_ship_tgt]) && (aip->target_objnum != -1)) {
if ((Ship_types[sip->class_type].ship_bools & STI_TURRET_TGT_SHIP_TGT) && (aip->target_objnum != -1)) {
int target_objnum = aip->target_objnum;
if (Objects[target_objnum].signature == aip->target_signature) {
@@ -1283,7 +1339,7 @@ void ship_get_global_turret_gun_info(object *objp, ship_subsys *ssp, vec3d *gpos
if (use_angles) {
model_instance_find_world_dir(gvec, &tp->turret_norm, Ships[objp->instance].model_instance_num, tp->turret_gun_sobj, &objp->orient);
} else if (tp->flags[Model::Subsystem_Flags::Share_fire_direction]) {
} else if (tp->flags2 & MSS_FLAG2_SHARE_FIRE_DIRECTION) {
vec3d avg, tmp_pos, tmp_target, enemy_point, turret_norm;
vm_vec_avg_n(&avg, tp->turret_num_firing_points, tp->turret_firing_point);
@@ -1321,7 +1377,7 @@ void ship_get_global_turret_gun_info(object *objp, ship_subsys *ssp, vec3d *gpos
vec3d target_moving_direction = ssp->last_aim_enemy_vel;
//Try to guess where the enemy will be, and store that spot in predicted_enemy_pos
if (The_mission.ai_profile->flags[AI::Profile_Flags::Use_additive_weapon_velocity]) {
if (The_mission.ai_profile->flags & AIPF_USE_ADDITIVE_WEAPON_VELOCITY) {
vm_vec_scale_sub2(&target_moving_direction, &objp->phys_info.vel, wip->vel_inherit_amount);
}
@@ -1417,7 +1473,7 @@ int aifft_rotate_turret(ship *shipp, int parent_objnum, ship_subsys *ss, object
target_moving_direction = ss->last_aim_enemy_vel;
//Try to guess where the enemy will be, and store that spot in predicted_enemy_pos
if (The_mission.ai_profile->flags[AI::Profile_Flags::Use_additive_weapon_velocity]) {
if (The_mission.ai_profile->flags & AIPF_USE_ADDITIVE_WEAPON_VELOCITY) {
vm_vec_scale_sub2(&target_moving_direction, &objp->phys_info.vel, wip->vel_inherit_amount);
}
@@ -1451,10 +1507,10 @@ int aifft_rotate_turret(ship *shipp, int parent_objnum, ship_subsys *ss, object
tp, &Objects[parent_objnum].orient,
&ss->submodel_info_1.angs, &ss->submodel_info_2.angs,
&Objects[parent_objnum].pos, predicted_enemy_pos, shipp->objnum);
} else if ((tp->flags[Model::Subsystem_Flags::Turret_reset_idle]) &&(timestamp_elapsed(ss->rotation_timestamp))) {
} else if ((tp->flags & MSS_FLAG_TURRET_RESET_IDLE) &&(timestamp_elapsed(ss->rotation_timestamp))) {
ret_val = model_rotate_gun(Ship_info[shipp->ship_info_index].model_num, tp, &Objects[parent_objnum].orient, &ss->submodel_info_1.angs, &ss->submodel_info_2.angs, &Objects[parent_objnum].pos, predicted_enemy_pos, shipp->objnum, true);
}
} else if ((ss->system_info->flags[Model::Subsystem_Flags::Turret_reset_idle]) && (timestamp_elapsed(ss->rotation_timestamp))) {
} else if ((ss->system_info->flags & MSS_FLAG_TURRET_RESET_IDLE) && (timestamp_elapsed(ss->rotation_timestamp))) {
ret_val = model_rotate_gun(Ship_info[shipp->ship_info_index].model_num, ss->system_info, &Objects[parent_objnum].orient, &ss->submodel_info_1.angs, &ss->submodel_info_2.angs, &Objects[parent_objnum].pos, predicted_enemy_pos, shipp->objnum, true);
}
@@ -1465,7 +1521,7 @@ int aifft_rotate_turret(ship *shipp, int parent_objnum, ship_subsys *ss, object
// return 0 by default (to preserve retail behavior) but allow for a per-subsystem option
// for using the turret normals for firing
if (ss->system_info->flags[Model::Subsystem_Flags::Fire_on_normal])
if (ss->system_info->flags & MSS_FLAG_FIRE_ON_NORMAL)
return 1;
return 0;
@@ -1490,7 +1546,7 @@ float aifft_compute_turret_dot(object *objp, object *enemy_objp, vec3d *abs_gunp
vm_vec_unrotate(&turret_norm, &turret_subsysp->system_info->turret_norm, &objp->orient);
float dot_return = vm_vec_dot(&turret_norm, &vector_out);
if (Ai_info[Ships[objp->instance].ai_index].ai_profile_flags[AI::Profile_Flags::Smart_subsystem_targeting_for_turrets]) {
if (Ai_info[Ships[objp->instance].ai_index].ai_profile_flags & AIPF_SMART_SUBSYSTEM_TARGETING_FOR_TURRETS) {
if (dot_return > turret_subsysp->system_info->turret_fov) {
// target is in sight and in fov
return dot_return;
@@ -1619,7 +1675,7 @@ ship_subsys *aifft_find_turret_subsys(object *objp, ship_subsys *ssp, object *en
int idx;
float dot_fov_modifier = 0.0f;
if (Ai_info[shipp->ai_index].ai_profile_flags[AI::Profile_Flags::Smart_subsystem_targeting_for_turrets]) {
if (Ai_info[shipp->ai_index].ai_profile_flags & AIPF_SMART_SUBSYSTEM_TARGETING_FOR_TURRETS) {
if (ssp->system_info->turret_fov < 0)
dot_fov_modifier = ssp->system_info->turret_fov;
}
@@ -1677,7 +1733,7 @@ void turret_set_next_fire_timestamp(int weapon_num, weapon_info *wip, ship_subsy
turret->weapons.burst_counter[weapon_num]++;
} else {
wait *= wip->fire_wait;
if ((wip->burst_shots > 0) && (wip->burst_flags[Weapon::Burst_Flags::Random_length])) {
if ((wip->burst_shots > 0) && (wip->burst_flags & WBF_RANDOM_LENGTH)) {
turret->weapons.burst_counter[weapon_num] = (myrand() % wip->burst_shots);
} else {
turret->weapons.burst_counter[weapon_num] = 0;
@@ -1691,13 +1747,13 @@ void turret_set_next_fire_timestamp(int weapon_num, weapon_info *wip, ship_subsy
fs_dest = &turret->weapons.next_secondary_fire_stamp[weapon_num - MAX_SHIP_PRIMARY_BANKS];
//Check for the new cooldown flag
if(!((wip->wi_flags[Weapon::Info_Flags::Same_turret_cooldown]) || ((wip->burst_shots > 0) && (wip->burst_flags[Weapon::Burst_Flags::Fast_firing]))))
if(!((wip->wi_flags2 & WIF2_SAME_TURRET_COOLDOWN) || ((wip->burst_shots > 0) && (wip->burst_flags & WBF_FAST_FIRING))))
{
// make side even for team vs. team
if (MULTI_TEAM) {
// flak guns need to fire more rapidly
if (wip->wi_flags[Weapon::Info_Flags::Flak]) {
if (wip->wi_flags & WIF_FLAK) {
wait *= aip->ai_ship_fire_delay_scale_friendly * 0.5f;
if (aip->ai_class_autoscale)
wait += (Num_ai_classes - aip->ai_class - 1) * 40.0f;
@@ -1708,7 +1764,7 @@ void turret_set_next_fire_timestamp(int weapon_num, weapon_info *wip, ship_subsy
}
} else {
// flak guns need to fire more rapidly
if (wip->wi_flags[Weapon::Info_Flags::Flak]) {
if (wip->wi_flags & WIF_FLAK) {
if (Ships[aip->shipnum].team == Player_ship->team) {
wait *= aip->ai_ship_fire_delay_scale_friendly * 0.5f;
} else {
@@ -1717,7 +1773,7 @@ void turret_set_next_fire_timestamp(int weapon_num, weapon_info *wip, ship_subsy
if (aip->ai_class_autoscale)
wait += (Num_ai_classes - aip->ai_class - 1) * 40.0f;
} else if (wip->wi_flags[Weapon::Info_Flags::Huge]) {
} else if (wip->wi_flags & WIF_HUGE) {
// make huge weapons fire independently of team
wait *= aip->ai_ship_fire_delay_scale_friendly;
if (aip->ai_class_autoscale)
@@ -1786,7 +1842,7 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
object *objp;
bool last_shot_in_salvo = true;
if (turret->system_info->flags[Model::Subsystem_Flags::Turret_salvo])
if (turret->system_info->flags & MSS_FLAG_TURRET_SALVO)
{
if ((turret->turret_next_fire_pos + 1) == (turret->system_info->turret_num_firing_points))
{
@@ -1813,12 +1869,12 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
object *tobjp = &Objects[turret->turret_enemy_objnum];
// should not get this far. check if ship is protected from beam and weapon is type beam
if ( (wip->wi_flags[Weapon::Info_Flags::Beam]) && (tobjp->flags[Object::Object_Flags::Beam_protected]) ) {
if ( (wip->wi_flags & WIF_BEAM) && (tobjp->flags[Object::Object_Flags::Beam_protected]) ) {
Int3();
return 0;
}
// should not get this far. check if ship is protected from flak and weapon is type flak
else if ( (wip->wi_flags[Weapon::Info_Flags::Flak]) && (tobjp->flags[Object::Object_Flags::Flak_protected]) ) {
else if ( (wip->wi_flags & WIF_FLAK) && (tobjp->flags[Object::Object_Flags::Flak_protected]) ) {
Int3();
return 0;
}
@@ -1844,9 +1900,9 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
turret_set_next_fire_timestamp(weapon_num, wip, turret, parent_aip);
// if this weapon is a beam weapon, handle it specially
if (wip->wi_flags[Weapon::Info_Flags::Beam]) {
if (wip->wi_flags & WIF_BEAM) {
// if this beam isn't free to fire
if (!(turret->weapons.flags[Ship::Weapon_Flags::Beam_Free])) {
if (!(turret->weapons.flags & SW_FLAG_BEAM_FREE)) {
return false;
}
beam_fire_info fire_info;
@@ -1858,7 +1914,7 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
fire_info.beam_info_override = NULL;
fire_info.shooter = &Objects[parent_objnum];
fire_info.target = &Objects[turret->turret_enemy_objnum];
if (wip->wi_flags[Weapon::Info_Flags::Antisubsysbeam])
if (wip->wi_flags2 & WIF2_ANTISUBSYSBEAM)
fire_info.target_subsys = turret->targeted_subsys;
else
fire_info.target_subsys = NULL;
@@ -1882,14 +1938,14 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
return true;
}
// don't fire swam, but set up swarm info instead
else if ((wip->wi_flags[Weapon::Info_Flags::Swarm]) || (wip->wi_flags[Weapon::Info_Flags::Corkscrew])) {
else if ((wip->wi_flags & WIF_SWARM) || (wip->wi_flags & WIF_CORKSCREW)) {
ship_weapon *swp = &turret->weapons;
if (swp->current_secondary_bank < 0) {
swp->current_secondary_bank = 0;
}
int bank_to_fire = swp->current_secondary_bank;
if ((turret->system_info->flags[Model::Subsystem_Flags::Turret_use_ammo]) && (swp->secondary_bank_ammo[bank_to_fire] < 0)) {
if (!(turret->system_info->flags[Model::Subsystem_Flags::Use_multiple_guns])) {
if ((turret->system_info->flags2 & MSS_FLAG2_TURRET_USE_AMMO) && (swp->secondary_bank_ammo[bank_to_fire] < 0)) {
if (!(turret->system_info->flags & MSS_FLAG_USE_MULTIPLE_GUNS)) {
swp->current_secondary_bank++;
if (swp->current_secondary_bank >= swp->num_secondary_banks) {
swp->current_secondary_bank = 0;
@@ -1908,7 +1964,7 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
// now do anything else
else {
for (int i = 0; i < wip->shots; i++) {
if (turret->system_info->flags[Model::Subsystem_Flags::Turret_use_ammo]) {
if (turret->system_info->flags2 & MSS_FLAG2_TURRET_USE_AMMO) {
ship_weapon *swp;
swp = &turret->weapons;
int bank_to_fire, num_slots = turret->system_info->turret_num_firing_points;
@@ -1932,7 +1988,7 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
bank_to_fire = swp->current_primary_bank;
if (turret->system_info->flags[Model::Subsystem_Flags::Turret_salvo]) {
if (turret->system_info->flags & MSS_FLAG_TURRET_SALVO) {
points = num_slots;
} else {
points = 1;
@@ -1940,7 +1996,7 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
if (swp->primary_bank_ammo[bank_to_fire] >= 0) {
swp->primary_bank_ammo[bank_to_fire] -= points;
} else if (!(turret->system_info->flags[Model::Subsystem_Flags::Use_multiple_guns]) && (swp->primary_bank_ammo[bank_to_fire] < 0)) {
} else if (!(turret->system_info->flags & MSS_FLAG_USE_MULTIPLE_GUNS) && (swp->primary_bank_ammo[bank_to_fire] < 0)) {
swp->current_primary_bank++;
if (swp->current_primary_bank >= swp->num_primary_banks) {
swp->current_primary_bank = 0;
@@ -1976,7 +2032,7 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
if (swp->secondary_bank_ammo[bank_to_fire] >= 0) {
swp->secondary_bank_ammo[bank_to_fire]--;
} else if (!(turret->system_info->flags[Model::Subsystem_Flags::Use_multiple_guns]) && (swp->secondary_bank_ammo[bank_to_fire] < 0)) {
} else if (!(turret->system_info->flags & MSS_FLAG_USE_MULTIPLE_GUNS) && (swp->secondary_bank_ammo[bank_to_fire] < 0)) {
swp->current_secondary_bank++;
if (swp->current_secondary_bank >= swp->num_secondary_banks) {
swp->current_secondary_bank = 0;
@@ -2013,7 +2069,7 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
Script_system.RemHookVars(4, "Ship", "Weapon", "Beam", "Target");
// if the gun is a flak gun
if (wip->wi_flags[Weapon::Info_Flags::Flak]) {
if (wip->wi_flags & WIF_FLAK) {
// show a muzzle flash
flak_muzzle_flash(turret_pos, turret_fvec, &Objects[parent_ship->objnum].phys_info, turret_weapon_class);
@@ -2041,7 +2097,7 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
subsys_index = ship_get_index_from_subsys(turret, parent_objnum );
Assert( subsys_index != -1 );
if(wip->wi_flags[Weapon::Info_Flags::Flak]){
if(wip->wi_flags & WIF_FLAK){
send_flak_fired_packet( parent_objnum, subsys_index, weapon_objnum, flak_range );
} else {
send_turret_fired_packet( parent_objnum, subsys_index, weapon_objnum );
@@ -2051,7 +2107,7 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
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 );
snd_play_3d( &Snds[wip->launch_snd], turret_pos, &View_position );
}
}
}
@@ -2065,7 +2121,7 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
}
}
//Not useful -WMC
else if (!(parent_aip->ai_profile_flags[AI::Profile_Flags::Dont_insert_random_turret_fire_delay]) && last_shot_in_salvo)
else if (!(parent_aip->ai_profile_flags & AIPF_DONT_INSERT_RANDOM_TURRET_FIRE_DELAY) && last_shot_in_salvo)
{
float wait = 1000.0f * frand_range(0.9f, 1.1f);
turret->turret_next_fire_stamp = timestamp((int) wait);
@@ -2091,7 +2147,7 @@ void turret_swarm_fire_from_turret(turret_swarm_info *tsi)
}
// if fixed fp make sure to use constant fp
if (tsi->turret->system_info->flags[Model::Subsystem_Flags::Turret_fixed_fp])
if (tsi->turret->system_info->flags & MSS_FLAG_TURRET_FIXED_FP)
tsi->turret->turret_next_fire_pos = tsi->weapon_num;
// change firing point
@@ -2099,13 +2155,13 @@ void turret_swarm_fire_from_turret(turret_swarm_info *tsi)
tsi->turret->turret_next_fire_pos++;
//check if this really is a swarm. If not, how the hell did it get here?
Assert((Weapon_info[tsi->weapon_class].wi_flags[Weapon::Info_Flags::Swarm]) || (Weapon_info[tsi->weapon_class].wi_flags[Weapon::Info_Flags::Corkscrew]));
Assert((Weapon_info[tsi->weapon_class].wi_flags & WIF_SWARM) || (Weapon_info[tsi->weapon_class].wi_flags & WIF_CORKSCREW));
// *If it's a non-homer, then use the last fire direction instead of turret orientation to fix inaccuracy
// problems with non-homing swarm weapons -Et1
if ( (Weapon_info[tsi->weapon_class].subtype == WP_LASER) || ((The_mission.ai_profile->flags[AI::Profile_Flags::Hack_improve_non_homing_swarm_turret_fire_accuracy])
&& !(Weapon_info[tsi->weapon_class].is_homing())) )
if ( (Weapon_info[tsi->weapon_class].subtype == WP_LASER) || ((The_mission.ai_profile->flags & AIPF_HACK_IMPROVE_NON_HOMING_SWARM_TURRET_FIRE_ACCURACY)
&& !(Weapon_info[tsi->weapon_class].wi_flags & WIF_HOMING)) )
{
turret_fvec = tsi->turret->turret_last_fire_direction;
}
@@ -2138,7 +2194,7 @@ void turret_swarm_fire_from_turret(turret_swarm_info *tsi)
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 );
snd_play_3d( &Snds[Weapon_info[tsi->weapon_class].launch_snd], &turret_pos, &View_position );
}
}
@@ -2194,7 +2250,7 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
}
// Check turret free
if (ss->weapons.flags[Ship::Weapon_Flags::Turret_Lock]) {
if (ss->weapons.flags & SW_FLAG_TURRET_LOCK) {
return;
}
@@ -2217,7 +2273,7 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
}
// If beam weapon, check beam free
if ( all_turret_weapons_have_flags(swp, Weapon::Info_Flags::Beam) && !(swp->flags[Ship::Weapon_Flags::Beam_Free]) ) {
if ( all_turret_weapons_have_flags(swp, WIF_BEAM) && !(swp->flags & SW_FLAG_BEAM_FREE) ) {
return;
}
@@ -2255,7 +2311,7 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
//aip = &Ai_info[Ships[objp->instance].ai_index];
// Wanderer - make sure turrets already have all the data
if ( !(tp->flags[Model::Subsystem_Flags::Turret_matrix]) )
if ( !(tp->flags & MSS_FLAG_TURRET_MATRIX) )
{
if (!(tp->turret_gun_sobj == tp->subobj_num))
{
@@ -2267,14 +2323,14 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
vec3d gvec, gpos;
ship_get_global_turret_info(&Objects[parent_objnum], tp, &gpos, &gvec);
if (tp->flags[Model::Subsystem_Flags::Turret_alt_math]) {
if (tp->flags & MSS_FLAG_TURRET_ALT_MATH) {
vm_matrix_x_matrix( &ss->world_to_turret_matrix, &Objects[parent_objnum].orient, &tp->turret_matrix );
}
// Rotate the turret even if time hasn't elapsed, since it needs to turn to face its target.
int use_angles = aifft_rotate_turret(shipp, parent_objnum, ss, objp, lep, &predicted_enemy_pos, &gvec);
if ((tp->flags[Model::Subsystem_Flags::Fire_on_target]) && (ss->points_to_target >= 0.0f))
if ((tp->flags & MSS_FLAG_FIRE_ON_TARGET) && (ss->points_to_target >= 0.0f))
{
// value probably needs tweaking... could perhaps be made into table option?
if (ss->points_to_target > 0.010f)
@@ -2292,7 +2348,7 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
//WMC - build a list of valid weapons. Fire spawns if there are any.
float dist_to_enemy = 0.0f;
if(lep != NULL) {
if (The_mission.ai_profile->flags[AI::Profile_Flags::Turrets_ignore_target_radius])
if (The_mission.ai_profile->flags2 & AIPF2_TURRETS_IGNORE_TARGET_RADIUS)
dist_to_enemy = MAX(0,vm_vec_normalized_dir(&v2e, &predicted_enemy_pos, &gpos));
else
dist_to_enemy = MAX(0,vm_vec_normalized_dir(&v2e, &predicted_enemy_pos, &gpos) - lep->radius);
@@ -2308,7 +2364,7 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
for(i = 0; i < (MAX_SHIP_WEAPONS); i++)
{
//WMC - Only fire more than once if we have multiple guns flag set.
if(num_valid > 0 && !(tp->flags[Model::Subsystem_Flags::Use_multiple_guns]))
if(num_valid > 0 && !(tp->flags & MSS_FLAG_USE_MULTIPLE_GUNS))
break;
if(i < MAX_SHIP_PRIMARY_BANKS)
@@ -2340,7 +2396,7 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
//If this is a spawning type weapon, shoot it!
//If 'smart spawn' just use it like normal weapons
if ( (wip->wi_flags[Weapon::Info_Flags::Spawn]) && !(wip->wi_flags[Weapon::Info_Flags::Smart_spawn]) )
if ( (wip->wi_flags & WIF_SPAWN) && !(wip->wi_flags2 & WIF2_SMART_SPAWN) )
{
if (( num_ships_nearby >= 3 ) || ((num_ships_nearby >= 2) && (frand() < 0.1f))) {
turret_fire_weapon(i, ss, parent_objnum, &gpos, &ss->turret_last_fire_direction);
@@ -2353,7 +2409,7 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
}
if(wip->wi_flags[Weapon::Info_Flags::Local_ssm])
if(wip->wi_flags2 & WIF2_LOCAL_SSM)
{
weapon_firing_range=wip->lssm_lock_range;
WeaponMinRange = 0.0f;
@@ -2365,7 +2421,7 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
}
if (wip->wi_flags[Weapon::Info_Flags::Beam]) {
if (wip->wi_flags & WIF_BEAM) {
if ( !((shipp->tag_left > 0) || (shipp->level2_tag_left > 0)) ) {
if (Nebula_sec_range)
{
@@ -2383,7 +2439,7 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
{
if( (dist_to_enemy <= weapon_firing_range) && (dist_to_enemy >= WeaponMinRange) )
{
if ( wip->wi_flags[Weapon::Info_Flags::Huge] ) {
if ( wip->wi_flags & WIF_HUGE ) {
if ( lep->type != OBJ_SHIP ) {
continue;
}
@@ -2392,13 +2448,13 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
}
}
if ( wip->wi_flags[Weapon::Info_Flags::Small_only] ) {
if ( wip->wi_flags2 & WIF2_SMALL_ONLY ) {
if ( (lep->type == OBJ_SHIP) && (Ship_info[Ships[lep->instance].ship_info_index].is_big_or_huge()) ) {
continue;
}
}
bool tagged_only = ((wip->wi_flags[Weapon::Info_Flags::Tagged_only]) || (ss->weapons.flags[Ship::Weapon_Flags::Tagged_Only]));
bool tagged_only = ((wip->wi_flags2 & WIF2_TAGGED_ONLY) || (ss->weapons.flags & SW_FLAG_TAGGED_ONLY));
if (lep->type == OBJ_SHIP) {
// Check if we're targeting a protected ship
@@ -2409,13 +2465,13 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
}
// Check if we're targeting a beam protected ship with a beam weapon
if ( (lep->flags[Object::Object_Flags::Beam_protected]) && (wip->wi_flags[Weapon::Info_Flags::Beam]) ) {
if ( (lep->flags[Object::Object_Flags::Beam_protected]) && (wip->wi_flags & WIF_BEAM) ) {
ss->turret_enemy_objnum = -1;
ss->turret_time_enemy_in_range = 0.0f;
continue;
}
// Check if we're targeting a flak protected ship with a flak weapon
else if ( (lep->flags[Object::Object_Flags::Flak_protected]) && (wip->wi_flags[Weapon::Info_Flags::Flak]) ) {
else if ( (lep->flags[Object::Object_Flags::Flak_protected]) && (wip->wi_flags & WIF_FLAK) ) {
ss->turret_enemy_objnum = -1;
ss->turret_time_enemy_in_range = 0.0f;
continue;
@@ -2441,7 +2497,7 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
else
{
// check tagged-only for non-ship targets
if (tagged_only && (!(lep->type == OBJ_WEAPON) || (The_mission.ai_profile->flags[AI::Profile_Flags::Strict_turred_tagged_only_targeting]))) {
if (tagged_only && (!(lep->type == OBJ_WEAPON) || (The_mission.ai_profile->flags2 & AIPF2_STRICT_TURRET_TAGGED_ONLY_TARGETING))) {
continue;
}
}
@@ -2543,7 +2599,7 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
// Do salvo thing separately - to prevent messing up things
int number_of_firings;
if (tp->flags[Model::Subsystem_Flags::Turret_salvo])
if (tp->flags & MSS_FLAG_TURRET_SALVO)
{
number_of_firings = tp->turret_num_firing_points;
ss->turret_next_fire_pos = 0;
@@ -2555,7 +2611,7 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
for(i = 0; i < number_of_firings; i++)
{
if (tp->flags[Model::Subsystem_Flags::Turret_fixed_fp])
if (tp->flags & MSS_FLAG_TURRET_FIXED_FP)
{
int ffp_pos = 0;
int ffp_bank;
@@ -2581,7 +2637,7 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
dist_to_enemy = vm_vec_normalize(&v2e);
dot = vm_vec_dot(&v2e, &gvec);
if (tp->flags[Model::Subsystem_Flags::Turret_salvo])
if (tp->flags & MSS_FLAG_TURRET_SALVO)
wip = get_turret_weapon_wip(&ss->weapons, valid_weapons[0]);
else
wip = get_turret_weapon_wip(&ss->weapons, valid_weapons[i]);
@@ -2597,7 +2653,7 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
// if the weapon is a flak gun, add some jitter to its aim so it fires in a "cone"
// to make a cool visual effect and make them less lethal
if(wip->wi_flags[Weapon::Info_Flags::Flak]){
if(wip->wi_flags & WIF_FLAK){
flak_jitter_aim(&tv2e, dist_to_enemy, ship_get_subsystem_strength(shipp, SUBSYSTEM_WEAPONS), wip);
}
@@ -2608,11 +2664,11 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
//turret_weapon_class = tp->turret_weapon_type;
bool in_sight = false;
if (The_mission.ai_profile->flags[AI::Profile_Flags::Use_only_single_fov_for_turrets]) {
if (The_mission.ai_profile->flags & AIPF_USE_ONLY_SINGLE_FOV_FOR_TURRETS) {
// we have already passed the FOV test of the turret so...
in_sight = true;
} else {
if (wip->wi_flags[Weapon::Info_Flags::Homing_heat]) {
if (wip->wi_flags & WIF_HOMING_HEAT) {
if (dot > AICODE_TURRET_HEATSEEK_ANGLE) {
in_sight = true;
}
@@ -2623,7 +2679,7 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
}
}
if ( !(wip->is_homing()) )
if ( !(wip->wi_flags & WIF_HOMING) )
{
if ((dist_to_enemy < 75.0f) || in_sight)
{
@@ -2631,7 +2687,7 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
ok_to_fire = true;
}
}
else if ( wip->wi_flags[Weapon::Info_Flags::Homing_heat] )
else if ( wip->wi_flags & WIF_HOMING_HEAT )
{ // if heat seekers
if ((dist_to_enemy < 50.0f) || in_sight)
{
@@ -2639,7 +2695,7 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
ok_to_fire = true;
}
}
else if ( wip->wi_flags[Weapon::Info_Flags::Homing_aspect] )
else if ( wip->wi_flags & WIF_HOMING_ASPECT )
{ // if aspect seeker
if ((dist_to_enemy < 50.0f) || in_sight)
{
@@ -2650,7 +2706,7 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
ok_to_fire = true;
}
}
else if ( wip->wi_flags[Weapon::Info_Flags::Homing_javelin] )
else if ( wip->wi_flags & WIF_HOMING_JAVELIN )
{ // if javelin heat seeker
if ((dist_to_enemy < 50.0f) || in_sight)
{
@@ -2665,7 +2721,7 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
}
}
if ( ok_to_fire && (tp->flags[Model::Subsystem_Flags::Turret_hull_check]) ) {
if ( ok_to_fire && (tp->flags & MSS_FLAG_TURRET_HULL_CHECK) ) {
int model_num = Ship_info[shipp->ship_info_index].model_num;
vec3d end;
vm_vec_scale_add(&end, &gpos, &gvec, model_get_radius(model_num));
@@ -2696,7 +2752,7 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
}
//Wait until the animation is done to actually fire
if (tp->flags[Model::Subsystem_Flags::Turret_anim_wait] && (ss->turret_animation_position != MA_POS_READY))
if (tp->flags & MSS_FLAG_TURRET_ANIM_WAIT && (ss->turret_animation_position != MA_POS_READY))
{
ok_to_fire = false;
}
@@ -2708,13 +2764,13 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
Num_turrets_fired++;
//Pass along which gun we are using
if (tp->flags[Model::Subsystem_Flags::Turret_salvo])
if (tp->flags & MSS_FLAG_TURRET_SALVO)
turret_fire_weapon(valid_weapons[0], ss, parent_objnum, &gpos, &tv2e, &predicted_enemy_pos);
else
turret_fire_weapon(valid_weapons[i], ss, parent_objnum, &gpos, &tv2e, &predicted_enemy_pos);
} else {
// make sure salvo fire mode does not turn into autofire
if ((tp->flags[Model::Subsystem_Flags::Turret_salvo]) && ((i + 1) == number_of_firings)) {
if ((tp->flags & MSS_FLAG_TURRET_SALVO) && ((i + 1) == number_of_firings)) {
ai_info *parent_aip = &Ai_info[Ships[Objects[parent_objnum].instance].ai_index];
turret_set_next_fire_timestamp(valid_weapons[0], wip, ss, parent_aip);
}
@@ -2734,7 +2790,7 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
// If nothing is OK to fire (lost track of the target?)
// reset the target (so we don't continue to track what we can't hit)
if (tp->flags[Model::Subsystem_Flags::Turret_only_target_if_can_fire])
if (tp->flags2 & MSS_FLAG2_TURRET_ONLY_TARGET_IF_CAN_FIRE)
{
ss->turret_enemy_objnum = -1; // Reset enemy objnum, find a new one next frame.
ss->turret_time_enemy_in_range = 0.0f;
@@ -2818,7 +2874,7 @@ bool turret_adv_fov_test(ship_subsys *ss, vec3d *gvec, vec3d *v2e, float size_mo
bool turret_fov_test(ship_subsys *ss, vec3d *gvec, vec3d *v2e, float size_mod)
{
bool in_fov = false;
if (ss->system_info->flags[Model::Subsystem_Flags::Turret_alt_math])
if (ss->system_info->flags & MSS_FLAG_TURRET_ALT_MATH)
in_fov = turret_adv_fov_test(ss, gvec, v2e, size_mod);
else
in_fov = turret_std_fov_test(ss, gvec, v2e, size_mod);
+5 -17
View File
@@ -19,8 +19,8 @@
#include "io/timer.h"
#include "pcxutils/pcxutils.h"
#include "render/3d.h"
#include "graphics/material.h"
#include "tracing/Monitor.h"
static color Color_xparent;
@@ -505,10 +505,7 @@ int anim_show_next_frame(anim_instance *instance, float frametime)
else {
g3_rotate_vertex(&image_vertex,instance->world_pos);
Assert(instance->radius != 0.0f);
//g3_draw_bitmap(&image_vertex, 0, instance->radius*1.5f, TMAP_FLAG_TEXTURED | TMAP_HTL_2D);
material mat_params;
material_set_unlit(&mat_params, bitmap_id, 1.0f, false, false);
g3_render_rect_screen_aligned_2d(&mat_params, &image_vertex, 0, instance->radius*1.5f);
g3_draw_bitmap(&image_vertex, 0, instance->radius*1.5f, TMAP_FLAG_TEXTURED | TMAP_HTL_2D);
}
instance->last_bitmap = bitmap_id;
@@ -687,7 +684,7 @@ void anim_read_header(anim *ptr, CFILE *fp)
* @details Memory-mapped files will page in the animation from disk as it is needed, but performance is not as good.
* @return Pointer to anim that is loaded if sucess, NULL if failure.
*/
anim *anim_load(const char *real_filename, int cf_dir_type, int file_mapped)
anim *anim_load(char *real_filename, int cf_dir_type, int file_mapped)
{
anim *ptr;
CFILE *fp;
@@ -733,10 +730,6 @@ anim *anim_load(const char *real_filename, int cf_dir_type, int file_mapped)
anim_read_header(ptr, fp);
if (ptr->width < 0 || ptr->height < 0) {
Error(LOCATION, "Ani file %s has a faulty header and cannot be loaded.", name);
}
if(ptr->num_keys > 0){
ptr->keys = (key_frame*)vm_malloc(sizeof(key_frame) * ptr->num_keys);
Assert(ptr->keys != NULL);
@@ -765,7 +758,7 @@ anim *anim_load(const char *real_filename, int cf_dir_type, int file_mapped)
}
// couldn't memory-map file... must be in a packfile, so stream manually
if ( file_mapped == PAGE_FROM_MEM && !ptr->cfile_ptr ) {
if ( file_mapped && !ptr->cfile_ptr ) {
ptr->flags &= ~ANF_MEM_MAPPED;
ptr->flags |= ANF_STREAMED;
ptr->cfile_ptr = cfopen(name, "rb", CFILE_NORMAL, cf_dir_type);
@@ -973,11 +966,6 @@ void anim_display_info(char *real_filename)
}
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);
+4 -3
View File
@@ -40,8 +40,9 @@ typedef struct {
enum
{
PAGE_FROM_DISK = 0,
PAGE_FROM_MEM = 1
PAGE_FROM_MEM = 0,
PAGE_FROM_DISK = 1,
PAGE_FROM_DISK_FORCED = 2
};
extern int Anim_paused;
@@ -58,7 +59,7 @@ 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);
anim *anim_load(char *name, int cf_dir_type = CF_TYPE_ANY, int file_mapped = PAGE_FROM_MEM);
int anim_free(anim *ptr);
int anim_playing(anim_instance *ai);
int anim_write_frames_out(char *filename);
+2 -16
View File
@@ -512,14 +512,7 @@ int unpack_pixel(anim_instance *ai, ubyte *data, ubyte pix, int aabitmap, int bp
bit_16 = (ushort)pix;
break;
case 8:
// 8 bit-per-pixel aa bitmaps are a bit special since they only use value in the range [0, 15] where 15 wraps
// around back to 0. Since the rest of the code expects the value to be in the range [0, 255] the pixel value
// needs to be adjusted here. By muliplying the value with 17 the original range [0, 15] is mapped to [0, 255]
if (pix >= 15) {
bit_8 = 0;
} else {
bit_8 = (ubyte)(pix * 17);
}
bit_8 = pix;
break;
default:
Int3();
@@ -603,14 +596,7 @@ int unpack_pixel_count(anim_instance *ai, ubyte *data, ubyte pix, int count = 0,
bit_16 = (ushort)pix;
break;
case 8 :
// 8 bit-per-pixel aa bitmaps are a bit special since they only use value in the range [0, 15] where 15 wraps
// around back to 0. Since the rest of the code expects the value to be in the range [0, 255] the pixel value
// needs to be adjusted here. By muliplying the value with 17 the original range [0, 15] is mapped to [0, 255]
if (pix >= 15) {
bit_8 = 0;
} else {
bit_8 = (ubyte)(pix * 17);
}
bit_8 = pix;
break;
default :
Int3();
+7 -10
View File
@@ -14,6 +14,7 @@
#include "fireball/fireballs.h"
#include "freespace.h"
#include "gamesnd/gamesnd.h"
#include "globalincs/compatibility.h"
#include "globalincs/linklist.h"
#include "globalincs/systemvars.h"
#include "hud/hud.h"
@@ -32,7 +33,7 @@
#include "object/objcollide.h"
#include "object/object.h"
#include "parse/parselo.h"
#include "scripting/scripting.h"
#include "parse/scripting.h"
#include "particle/particle.h"
#include "render/3d.h"
#include "ship/ship.h"
@@ -1180,7 +1181,7 @@ int asteroid_check_collision(object *pasteroid, object *other_obj, vec3d *hitpos
}
}
void asteroid_render(object * obj, model_draw_list *scene)
void asteroid_render(object * obj, draw_list *scene)
{
if (Asteroids_enabled) {
int num;
@@ -1312,7 +1313,7 @@ void asteriod_explode_sound(object *objp, int type, int play_loud)
range_factor = 1.0f;
}
snd_play_3d( gamesnd_get_game_sound(sound_index), &objp->pos, &Eye_position, objp->radius, NULL, 0, 1.0f, SND_PRIORITY_MUST_PLAY, NULL, range_factor );
snd_play_3d( &Snds[sound_index], &objp->pos, &Eye_position, objp->radius, NULL, 0, 1.0f, SND_PRIORITY_MUST_PLAY, NULL, range_factor );
}
/**
@@ -1568,12 +1569,8 @@ void asteroid_maybe_break_up(object *pasteroid_obj)
vec3d tempv = dir_vec;
vm_vec_random_cone(&dir_vec, &tempv, (360.0f / total_roids / 2));
// Make the roid inherit half of parent's directional movement
if (!IS_VEC_NULL(&pasteroid_obj->phys_info.vel)) {
vm_vec_copy_normalize(&parent_vel, &pasteroid_obj->phys_info.vel);
} else {
vm_vec_rand_vec_quick(&parent_vel);
}
// Make the roid inherit half of the parent's velocity
vm_vec_copy_normalize(&parent_vel, &pasteroid_obj->phys_info.vel);
vm_vec_scale(&parent_vel, 0.5f);
// Make the hit position affect the direction, but only a little
@@ -1920,7 +1917,7 @@ void asteroid_parse_tbl()
char impact_ani_file[MAX_FILENAME_LEN];
// How did we get here without having any species defined?
Assertion(!Species_info.empty(),
Assertion(Species_info.size() > 0,
"Cannot parse asteroids/debris if there "
"are no species for them to belong to."
);
+2 -2
View File
@@ -19,7 +19,7 @@
class object;
class polymodel;
struct collision_info_struct;
class model_draw_list;
class draw_list;
#define MAX_ASTEROIDS 512
@@ -152,7 +152,7 @@ void asteroid_init();
void asteroid_level_init();
void asteroid_level_close();
void asteroid_create_all();
void asteroid_render(object * obj, model_draw_list *scene);
void asteroid_render(object * obj, draw_list *scene);
void asteroid_delete( object *asteroid_objp );
void asteroid_process_pre( object *asteroid_objp );
void asteroid_process_post( object *asteroid_objp);
+13 -13
View File
@@ -335,7 +335,7 @@ bool StartAutopilot()
{
if (Ships[i].objnum != -1 &&
(Ships[i].flags[Ship::Ship_Flags::Navpoint_carry] ||
(Ships[i].wingnum != -1 && Wings[Ships[i].wingnum].flags[Ship::Wing_Flags::Nav_carry])
(Ships[i].wingnum != -1 && Wings[Ships[i].wingnum].flags & WF_NAV_CARRY)
)
)
{
@@ -368,7 +368,7 @@ bool StartAutopilot()
{
if (Ships[i].objnum != -1 &&
(Ships[i].flags[Ship::Ship_Flags::Navpoint_carry] ||
(Ships[i].wingnum != -1 && Wings[Ships[i].wingnum].flags[Ship::Wing_Flags::Nav_carry])
(Ships[i].wingnum != -1 && Wings[Ships[i].wingnum].flags & WF_NAV_CARRY)
)
)
{
@@ -423,7 +423,7 @@ bool StartAutopilot()
// snap wings into formation
if (The_mission.flags[Mission::Mission_Flags::Use_ap_cinematics] && // only if using cinematics
(Ships[i].wingnum != -1 && Wings[Ships[i].wingnum].flags[Ship::Wing_Flags::Nav_carry]) // only if in a wing
(Ships[i].wingnum != -1 && Wings[Ships[i].wingnum].flags & WF_NAV_CARRY) // only if in a wing
&& Autopilot_flight_leader != &Objects[Ships[i].objnum]) //only if not flight leader's object
{
ai_info *aip = &Ai_info[Ships[i].ai_index];
@@ -434,7 +434,7 @@ bool StartAutopilot()
if (leader_objp != &Objects[Ships[i].objnum])
{
// not leader.. get our position relative to leader
get_absolute_wing_pos_autopilot(&goal_point, leader_objp, wing_index, aip->ai_flags[AI::AI_Flags::Formation_object]);
get_absolute_wing_pos_autopilot(&goal_point, leader_objp, wing_index, aip->ai_flags & AIF_FORMATION_OBJECT);
}
else
{
@@ -501,7 +501,7 @@ bool StartAutopilot()
{
for (i = 0; i < MAX_WINGS; i++)
{
if (Wings[i].flags[Ship::Wing_Flags::Nav_carry] )
if (Wings[i].flags & WF_NAV_CARRY )
{
//ai_add_ship_goal_player( int type, int mode, int submode, char *shipname, ai_info *aip );
@@ -540,7 +540,7 @@ bool StartAutopilot()
if (Ships[i].objnum != -1)
{
if (Ships[i].flags[Ship::Ship_Flags::Navpoint_carry] ||
(Ships[i].wingnum != -1 && Wings[Ships[i].wingnum].flags[Ship::Wing_Flags::Nav_carry]))
(Ships[i].wingnum != -1 && Wings[Ships[i].wingnum].flags & WF_NAV_CARRY))
for (j = 0; j < MAX_AI_GOALS; j++)
{
if (Ai_info[Ships[i].ai_index].goals[j].ai_mode == AI_GOAL_WAYPOINTS_ONCE ||
@@ -915,7 +915,7 @@ void EndAutoPilot()
if (Ships[i].objnum != -1 &&
(
Ships[i].flags[Ship::Ship_Flags::Navpoint_carry] ||
(Ships[i].wingnum != -1 && Wings[Ships[i].wingnum].flags[Ship::Wing_Flags::Nav_carry] )
(Ships[i].wingnum != -1 && Wings[Ships[i].wingnum].flags & WF_NAV_CARRY )
)
)
{
@@ -950,7 +950,7 @@ void EndAutoPilot()
aigp->ai_mode = AI_GOAL_NONE;
aigp->signature = -1;
aigp->priority = -1;
aigp->flags.reset();
aigp->flags = 0;
}
}
}
@@ -962,7 +962,7 @@ void EndAutoPilot()
{
for (i = 0; i < MAX_WINGS; i++)
{
if (Wings[i].flags[Ship::Wing_Flags::Nav_carry] )
if (Wings[i].flags & WF_NAV_CARRY )
{
for (j = 0; j < MAX_AI_GOALS; j++)
{
@@ -974,7 +974,7 @@ void EndAutoPilot()
aigp->ai_mode = AI_GOAL_NONE;
aigp->signature = -1;
aigp->priority = -1;
aigp->flags.reset();
aigp->flags = 0;
}
}
}
@@ -1045,7 +1045,7 @@ void nav_warp(bool prewarp=false)
{
if (Ships[i].objnum != -1
&& (Ships[i].flags[Ship::Ship_Flags::Navpoint_carry]
|| (Ships[i].wingnum != -1 && Wings[Ships[i].wingnum].flags[Ship::Wing_Flags::Nav_carry])))
|| (Ships[i].wingnum != -1 && Wings[Ships[i].wingnum].flags & WF_NAV_CARRY)))
{
vm_vec_add(&Objects[Ships[i].objnum].pos, &Objects[Ships[i].objnum].pos, &targetPos);
Objects[Ships[i].objnum].phys_info.vel = velocity;
@@ -1272,7 +1272,7 @@ void NavSystem_Init()
// ********************************************************************************************
void parse_autopilot_table(const char *filename)
void parse_autopilot_table(char *filename)
{
SCP_vector<SCP_string> lines;
@@ -1315,7 +1315,7 @@ void parse_autopilot_table(const char *filename)
Cmdline_autopilot_interruptable = 0;
// No Nav selected message
const char *msg_tags[] = { "$No Nav Selected:", "$Gliding:",
char *msg_tags[] = { "$No Nav Selected:", "$Gliding:",
"$Too Close:", "$Hostiles:", "$Linked:", "$Hazard:",
"$Support Present:", "$Support Working:" };
for (int i = 0; i < NP_NUM_MESSAGES; i++)
+1 -1
View File
@@ -118,7 +118,7 @@ void NavSystem_Do();
void NavSystem_Init();
// parse autopilot.tbl
void parse_autopilot_table(const char *filename);
void parse_autopilot_table(char *filename);
// Finds a Nav point by name
int FindNav(char *Nav);
+1 -2
View File
@@ -31,7 +31,6 @@ union bm_extra_info {
int keyframe; //!< used for animations -- keyframe info
float total_time; //!< used for animations -- total animation time (not always derived from num_frames/fps)
ubyte fps; //!< used for animations -- frames per second
bool is_array; //!< Flag for if all frames of an animation have the same size which means that it can be put into a texture array
struct {
// stuff for static animations
@@ -90,7 +89,7 @@ struct bitmap_entry {
#endif
};
extern bitmap_entry* bm_bitmaps;
extern bitmap_entry bm_bitmaps[MAX_BITMAPS];
// image specific lock functions
void bm_lock_ani( int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, int bpp, ubyte flags );
+37 -144
View File
@@ -24,19 +24,17 @@
#include "debugconsole/console.h"
#include "globalincs/systemvars.h"
#include "graphics/2d.h"
#include "graphics/matrix.h"
#include "graphics/grinternal.h"
#include "io/key.h"
#include "io/timer.h"
#include "jpgutils/jpgutils.h"
#include "network/multiutil.h"
#include "palman/palman.h"
#include "parse/parselo.h"
#include "pcxutils/pcxutils.h"
#include "pngutils/pngutils.h"
#include "ship/ship.h"
#include "tgautils/tgautils.h"
#include "tracing/Monitor.h"
#include "tracing/tracing.h"
#include <ctype.h>
#include <limits.h>
@@ -57,6 +55,7 @@ MONITOR(SizeBitmapPage)
// --------------------------------------------------------------------------------------------------------------------
// Definition of public variables (declared as extern in bmpman.h).
int UNLITMAP = -1;
int GLOWMAP = -1;
int SPECMAP = -1;
int SPECGLOSSMAP = -1;
@@ -84,19 +83,17 @@ const int BM_ANI_NUM_TYPES = sizeof(bm_ani_type_list) / sizeof(bm_ani_type_list[
void(*bm_set_components)(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a) = NULL;
void(*bm_set_components_32)(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a) = NULL;
int MAX_BITMAPS = DEFAULT_MAX_BITMAPS;
// --------------------------------------------------------------------------------------------------------------------
// Declaration of protected variables (defined in cmdline.cpp).
extern int Cmdline_cache_bitmaps;
// --------------------------------------------------------------------------------------------------------------------
// Definition of public variables (declared as extern in bm_internal.h).
bitmap_entry* bm_bitmaps = nullptr;
bitmap_entry bm_bitmaps[MAX_BITMAPS];
// --------------------------------------------------------------------------------------------------------------------
// Definition of private variables at file scope (static).
static bool bm_inited = false;
static int bm_inited = 0;
static uint Bm_next_signature = 0x1234;
static int bm_next_handle = 1;
static int Bm_low_mem = 0;
@@ -422,7 +419,7 @@ DCF(bmpman, "Shows/changes bitmap caching parameters and usage") {
}
if (dc_optional_string_either("status", "--status") || dc_optional_string_either("?", "--?")) {
dc_printf("Total RAM usage: " SIZE_T_ARG " bytes\n", bm_texture_ram);
dc_printf("Total RAM usage: %d bytes\n", bm_texture_ram);
if (Bm_max_ram > 1024 * 1024) {
dc_printf("\tMax RAM allowed: %.1f MB\n", i2fl(Bm_max_ram) / (1024.0f*1024.0f));
@@ -438,14 +435,14 @@ DCF(bmpman, "Shows/changes bitmap caching parameters and usage") {
if (dc_optional_string("flush")) {
dc_printf("Total RAM usage before flush: " SIZE_T_ARG " bytes\n", bm_texture_ram);
dc_printf("Total RAM usage before flush: %d bytes\n", bm_texture_ram);
int i;
for (i = 0; i < MAX_BITMAPS; i++) {
if (bm_bitmaps[i].type != BM_TYPE_NONE) {
bm_free_data(i);
}
}
dc_printf("Total RAM after flush: " SIZE_T_ARG " bytes\n", bm_texture_ram);
dc_printf("Total RAM after flush: %d bytes\n", bm_texture_ram);
} else if (dc_optional_string("ram")) {
dc_stuff_int(&Bm_max_ram);
@@ -483,11 +480,7 @@ void bm_close() {
for (i = 0; i<MAX_BITMAPS; i++) {
bm_free_data(i); // clears flags, bbp, data, etc
}
if (bm_bitmaps != nullptr) {
delete[] bm_bitmaps;
bm_bitmaps = nullptr;
}
bm_inited = false;
bm_inited = 0;
}
}
@@ -498,7 +491,7 @@ int bm_create(int bpp, int w, int h, void *data, int flags) {
Assert((bpp == 16) || (bpp == 24) || (bpp == 32));
}
Assertion(bm_inited, "bmpman must be initialized before this function can be called!");
if (!bm_inited) bm_init();
int n = -1;
@@ -532,7 +525,6 @@ int bm_create(int bpp, int w, int h, void *data, int flags) {
bm_bitmaps[n].bm.h = (short)h;
bm_bitmaps[n].bm.rowsize = (short)w;
bm_bitmaps[n].bm.bpp = (ubyte)bpp;
bm_bitmaps[n].bm.true_bpp = (ubyte)bpp;
bm_bitmaps[n].bm.flags = (ubyte)flags;
bm_bitmaps[n].bm.data = 0;
bm_bitmaps[n].bm.palette = NULL;
@@ -878,7 +870,7 @@ int bm_get_info(int handle, int *w, int * h, ubyte * flags, int *nframes, int *f
if (h) *h = bmp->h;
if (flags) *flags = bmp->flags;
if (bm_is_anim(bitmapnum)) {
if (bm_is_anim(bitmapnum) == true) {
if (nframes) {
*nframes = bm_bitmaps[bitmapnum].info.ani.num_frames;
}
@@ -949,7 +941,7 @@ void bm_get_palette(int handle, ubyte *pal, char *name) {
}
uint bm_get_signature(int handle) {
Assertion(bm_inited, "bmpman must be initialized before this function can be called!");
if (!bm_inited) bm_init();
int bitmapnum = handle % MAX_BITMAPS;
Assertion(bm_bitmaps[bitmapnum].handle == handle, "Invalid bitmap handle %d passed to bm_get_signature().\nThis might be due to an invalid animation somewhere else.\n", handle); // INVALID BITMAP HANDLE!
@@ -974,7 +966,7 @@ int bm_get_tcache_type(int num) {
}
BM_TYPE bm_get_type(int handle) {
Assertion(bm_inited, "bmpman must be initialized before this function can be called!");
if (!bm_inited) bm_init();
int bitmapnum = handle % MAX_BITMAPS;
Assertion(bm_bitmaps[bitmapnum].handle == handle, "Invalid bitmap handle %d passed to bm_get_type().\nThis might be due to an invalid animation somewhere else.\n", handle); // INVALID BITMAP HANDLE!
@@ -996,17 +988,16 @@ bool bm_has_alpha_channel(int handle) {
}
void bm_init() {
Assertion(!bm_inited, "bmpman cannot be initialized more than once!");
int i;
if (bm_bitmaps == nullptr) {
bm_bitmaps = new bitmap_entry[MAX_BITMAPS];
}
mprintf(("Size of bitmap info = " SIZE_T_ARG " KB\n", (sizeof(bm_bitmaps[0]) * MAX_BITMAPS) / 1024));
mprintf(("Size of bitmap info = " SIZE_T_ARG " KB\n", sizeof(bm_bitmaps) / 1024));
mprintf(("Size of bitmap extra info = " SIZE_T_ARG " bytes\n", sizeof(bm_extra_info)));
if (!bm_inited) {
bm_inited = 1;
atexit(bm_close);
}
for (i = 0; i<MAX_BITMAPS; i++) {
bm_bitmaps[i].filename[0] = '\0';
bm_bitmaps[i].type = BM_TYPE_NONE;
@@ -1030,8 +1021,6 @@ void bm_init() {
bm_free_data(i); // clears flags, bbp, data, etc
}
bm_inited = true;
}
int bm_is_compressed(int num) {
@@ -1213,7 +1202,8 @@ int bm_load(const char *real_filename) {
CFILE *img_cfp = NULL;
int handle = -1;
Assertion(bm_inited, "bmpman must be initialized before this function can be called!");
if (!bm_inited)
bm_init();
// if no file was passed then get out now
if ((real_filename == NULL) || (strlen(real_filename) <= 0))
@@ -1518,7 +1508,8 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
size_t img_size = 0;
char clean_name[MAX_FILENAME_LEN];
Assertion(bm_inited, "bmpman must be initialized before this function can be called!");
if (!bm_inited)
bm_init();
// set output param defaults before going any further
if (nframes != nullptr)
@@ -1627,10 +1618,6 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
#endif
anim_read_header(&the_anim, img_cfp);
if (the_anim.width < 0 || the_anim.height < 0) {
Error(LOCATION, "Ani file %s has a faulty header and cannot be loaded.", real_filename);
}
anim_frames = the_anim.total_frames;
anim_fps = the_anim.fps;
if (anim_fps == 0) {
@@ -1709,8 +1696,6 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
}
int first_handle = bm_get_next_handle();
// if all images of the animation have the same size then we can use a texture array
bool is_array = true;
for (i = 0; i < anim_frames; i++) {
memset(&bm_bitmaps[n + i], 0, sizeof(bitmap_entry));
@@ -1797,39 +1782,8 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
bm_bitmaps[n + i].info.ani.apng.is_apng = false;
}
if (bm_bitmaps[n].bm.w != bm_bitmaps[n + i].bm.w || bm_bitmaps[n].bm.h != bm_bitmaps[n + i].bm.h) {
// We found a frame with a different size than the first frame -> this can't be used as a texture array
is_array = false;
Warning(LOCATION, "Animation '%s' has images that are of different sizes (currently at frame %d)."
"Performance could be improved by making all images the same size.", filename, i + 1);
}
if (bm_bitmaps[n].comp_type != bm_bitmaps[n + i].comp_type) {
// Different compression type
is_array = false;
Warning(LOCATION, "Animation '%s' has images that are of different compression formats (currently at frame %d)."
"Performance could be improved by making all images the same compression format.", filename, i + 1);
}
if (bm_bitmaps[n].bm.true_bpp != bm_bitmaps[n + i].bm.true_bpp) {
// We found a frame with an incompatible pixel format
is_array = false;
Warning(LOCATION, "Animation '%s' has images that are of different pixel formats (currently at frame %d)."
"Performance could be improved by making all images the same pixel format.", filename, i + 1);
}
if (bm_bitmaps[n].num_mipmaps != bm_bitmaps[n + i].num_mipmaps) {
// We found a frame with a different number of mipmaps
is_array = false;
Warning(LOCATION, "Animation '%s' has images that have a different number of mipmaps (currently at frame %d)."
"Performance could be improved by giving all frames the same number of mipmaps.", filename, i + 1);
}
}
// Set array flag of first frame
bm_bitmaps[n].info.ani.is_array = is_array;
if (nframes != nullptr)
*nframes = anim_frames;
@@ -1938,7 +1892,7 @@ bitmap * bm_lock(int handle, int bpp, ubyte flags, bool nodebug) {
bitmap *bmp;
bitmap_entry *be;
Assertion(bm_inited, "bmpman must be initialized before this function can be called!");
if (!bm_inited) bm_init();
int bitmapnum = handle % MAX_BITMAPS;
@@ -2204,7 +2158,7 @@ void bm_lock_apng(int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, int
cumulative_frame_delay += the_apng->frame.delay;
be->info.ani.apng.frame_delay = cumulative_frame_delay;
nprintf(("apng", "locking apng frame: %s (%i|%i|%i) (%f) " SIZE_T_ARG "\n", be->filename, bpp, bmp->bpp, bm->true_bpp, be->info.ani.apng.frame_delay, be->mem_taken));
nprintf(("apng", "locking apng frame: %s (%i|%i|%i) (%f) %lu\n", be->filename, bpp, bmp->bpp, bm->true_bpp, be->info.ani.apng.frame_delay, be->mem_taken));
}
}
@@ -2280,9 +2234,6 @@ void bm_lock_jpg(int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, int b
// Unload any existing data
bm_free_data(bitmapnum);
// JPEG actually only support 24 bits per pixel so we enforce that here
bpp = 24;
d_size = (bpp >> 3);
// allocate bitmap data
@@ -2328,7 +2279,7 @@ void bm_lock_pcx(int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, int b
data = (ubyte *)bm_malloc(bitmapnum, be->mem_taken);
bmp->bpp = bpp;
bmp->data = (ptr_u)data;
bmp->palette = NULL;
bmp->palette = (bpp == 8) ? gr_palette : NULL;
memset(data, 0, be->mem_taken);
Assert(&be->bm == bmp);
@@ -2343,7 +2294,7 @@ void bm_lock_pcx(int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, int b
// this will populate filename[] whether it's EFF or not
EFF_FILENAME_CHECK;
pcx_error = pcx_read_bitmap(filename, data, NULL, (bpp >> 3), (flags & BMP_AABITMAP), (flags & BMP_MASK_BITMAP) != 0, be->dir_type);
pcx_error = pcx_read_bitmap(filename, data, NULL, (bpp >> 3), (flags & BMP_AABITMAP), 0, be->dir_type);
if (pcx_error != PCX_ERROR_NONE) {
mprintf(("Couldn't load PCX!!! (%s)\n", filename));
@@ -2422,7 +2373,7 @@ void bm_lock_tga(int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, int b
Assert(byte_size);
Assert(be->mem_taken > 0);
data = (ubyte*)bm_malloc(bitmapnum, static_cast<size_t>(bmp->w * bmp->h * byte_size));
data = (ubyte*)bm_malloc(bitmapnum, be->mem_taken);
if (data) {
memset(data, 0, be->mem_taken);
@@ -2507,7 +2458,8 @@ int bm_make_render_target(int width, int height, int flags) {
int bpp = 32;
int size = 0;
Assertion(bm_inited, "bmpman must be initialized before this function can be called!");
if (!bm_inited)
bm_init();
// Find an open slot (starting from the end)
for (n = -1, i = MAX_BITMAPS - 1; i >= 0; i--) {
@@ -2625,8 +2577,6 @@ void bm_page_in_start() {
}
void bm_page_in_stop() {
TRACE_SCOPE(tracing::PageInStop);
int i;
#ifndef NDEBUG
@@ -2643,7 +2593,6 @@ void bm_page_in_stop() {
for (i = 0; i < MAX_BITMAPS; i++) {
if ((bm_bitmaps[i].type != BM_TYPE_NONE) && (bm_bitmaps[i].type != BM_TYPE_RENDER_TARGET_DYNAMIC) && (bm_bitmaps[i].type != BM_TYPE_RENDER_TARGET_STATIC)) {
if (bm_bitmaps[i].preloaded) {
TRACE_SCOPE(tracing::PageInSingleBitmap);
if (bm_preloading) {
if (!gr_preload(bm_bitmaps[i].handle, (bm_bitmaps[i].preloaded == 2))) {
mprintf(("Out of VRAM. Done preloading.\n"));
@@ -2880,16 +2829,12 @@ int bm_release(int handle, int clear_render_targets) {
}
// be sure that all frames of an ani are unloaded - taylor
if (bm_is_anim(n)) {
if (bm_is_anim(n) == true) {
int i, first = be->info.ani.first_frame, total = bm_bitmaps[first].info.ani.num_frames;
// The graphics system requires that the bitmap information for the whole animation is still valid when the data
// is freed so we first free all the data and then clear the bitmaps data
for (i = 0; i < total; i++) {
bm_free_data(first + i, true); // clears flags, bbp, data, etc
}
for (i = 0; i < total; i++) {
memset(&bm_bitmaps[first + i], 0, sizeof(bitmap_entry));
bm_bitmaps[first + i].type = BM_TYPE_NONE;
@@ -2938,7 +2883,8 @@ int bm_release(int handle, int clear_render_targets) {
}
int bm_reload(int bitmap_handle, const char* filename) {
Assertion(bm_inited, "bmpman must be initialized before this function can be called!");
if (!bm_inited)
bm_init();
// if no file was passed then get out now
if ((filename == NULL) || (strlen(filename) <= 0))
@@ -3048,8 +2994,6 @@ void bm_set_low_mem(int mode) {
}
bool bm_set_render_target(int handle, int face) {
GR_DEBUG_SCOPE("Set render target");
int n = handle % MAX_BITMAPS;
if (n >= 0) {
@@ -3118,7 +3062,10 @@ bool bm_set_render_target(int handle, int face) {
gr_reset_clip();
gr_setup_viewport();
if (gr_screen.mode == GR_OPENGL) {
extern void opengl_setup_viewport();
opengl_setup_viewport();
}
return true;
}
@@ -3130,10 +3077,6 @@ int bm_unload(int handle, int clear_render_targets, bool nodebug) {
bitmap_entry *be;
bitmap *bmp;
if (handle == -1) {
return -1;
}
int n = handle % MAX_BITMAPS;
Assert((n >= 0) && (n < MAX_BITMAPS));
@@ -3248,7 +3191,7 @@ int bm_unload_fast(int handle, int clear_render_targets) {
void bm_unlock(int handle) {
bitmap_entry *be;
Assertion(bm_inited, "bmpman must be initialized before this function can be called!");
if (!bm_inited) bm_init();
int bitmapnum = handle % MAX_BITMAPS;
@@ -3304,53 +3247,3 @@ int find_block_of(int n)
return -1;
}
bool bm_is_texture_array(const int handle) {
int bitmapnum = handle % MAX_BITMAPS;
if (!bm_is_anim(bitmapnum)) {
return true;
}
// This will return the index of the first animation frame
int n = bm_get_cache_slot(handle, 0);
bitmap_entry *be = &bm_bitmaps[n];
return be->info.ani.is_array;
}
int bm_get_base_frame(const int handle, int* num_frames) {
// If the bitmap is no animation then num_frames will still be at least 1
auto animation_begin = bm_get_info(handle, nullptr, nullptr, nullptr, num_frames);
if (animation_begin < 0) {
// Some kind of error
return -1;
}
if (!bm_is_texture_array(animation_begin)) {
// If this is not a texture array then we just treat it like a single frame animation
animation_begin = handle;
if (num_frames != nullptr) {
*num_frames = 1;
}
}
return animation_begin;
}
int bm_get_array_index(const int handle) {
return handle - bm_get_base_frame(handle, nullptr);
}
int bmpman_count_bitmaps() {
if (!bm_inited)
return -1;
int total_bitmaps = 0;
for (int i = 0; i < MAX_BITMAPS; i++) {
if (bm_bitmaps[i].type != BM_TYPE_NONE) {
total_bitmaps++;
}
}
return total_bitmaps;
}
+2 -45
View File
@@ -33,7 +33,7 @@
*/
/**
* @brief How many bitmaps the game can handle by default
* @brief How many bitmaps the game can handle
*
* @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
@@ -45,9 +45,7 @@
* 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;
#define MAX_BITMAPS 4750
// 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!! ******
@@ -58,7 +56,6 @@ extern int MAX_BITMAPS;
#define BMP_TEX_DXT3 (1<<4) //!< dxt3 compressed 8r8g8b4a (32bit)
#define BMP_TEX_DXT5 (1<<5) //!< dxt5 compressed 8r8g8b8a (32bit)
#define BMP_TEX_CUBEMAP (1<<6) //!< a texture made for cubic environment map
#define BMP_MASK_BITMAP (1<<7) //!< a bitmap that will be used for masking mouse interaction. Typically not used in render operations
// Combined flags
#define BMP_TEX_COMP ( BMP_TEX_DXT1 | BMP_TEX_DXT3 | BMP_TEX_DXT5 ) //!< Compressed textures
@@ -701,44 +698,4 @@ bool bm_load_and_parse_eff(const char *filename, int dir_type, int *nframes, int
*/
int bm_get_anim_frame(const int frame1_handle, float elapsed_time, const float divisor = 0.0f, const bool loop = false);
/**
* @brief Determines if the given handle could be used in a texture array
*
* @param handle The handle to query the value for
* @return @c true if all frames have the same size, @c false otherwise. Always returns @c true for single images
*/
bool bm_is_texture_array(const int handle);
/**
* @brief Gets the base frame of the specified animation
*
* @details The base frame is the frame of the animation that should be used to determine if two animation frames can be
* used in the same draw call. Use this if you want to optimize your draw calls to make use of texture arrays.
*
* @param handle The handle of the animation to check. This may also be a single frame bitmap
* @param num_frames Optionally return the number of frames in the animation
* @return The bitmap handle of the base frame or -1 on error
*/
int bm_get_base_frame(const int handle, int* num_frames = nullptr);
/**
* @brief Get the array index of the specified bitmap
*
* This should be used when passing the array index to the GPU (e.g. when building uniform structs or streaming particle
* data)
*
* @param handle The handle of the bitmap
* @return The index into the array
*/
int bm_get_array_index(const int handle);
/**
* @brief Counts how many slots are used in bm_bitmaps
*
* This needs to iterate through all the slots in order to determine whether or not they're used, so shouldn't be used frivolously.
*
* @return The number of used slots
*/
int bmpman_count_bitmaps();
#endif
+5 -5
View File
@@ -2,7 +2,7 @@
#include "globalincs/alphacolors.h"
#include "globalincs/linklist.h"
#include "globalincs/systemvars.h" //VM_FREECAMERA etc
#include "graphics/matrix.h"
#include "graphics/font.h"
#include "hud/hud.h" //hud_get_draw
#include "math/vecmat.h"
#include "mod_table/mod_table.h"
@@ -26,7 +26,7 @@ camid Main_camera;
//*************************CLASS: camera*************************
//This is where the camera class beings! :D
camera::camera(const char *in_name, int in_signature)
camera::camera(char *in_name, int in_signature)
{
set_name(in_name);
sig = in_signature;
@@ -78,7 +78,7 @@ void camera::reset()
}
}
void camera::set_name(const char *in_name)
void camera::set_name(char *in_name)
{
if(in_name != NULL)
strncpy(name, in_name, NAME_LENGTH-1);
@@ -885,14 +885,14 @@ int cam_get_next_sig()
return next_sig++;
}
camid cam_create(const char *n_name, vec3d *n_pos, vec3d *n_norm, object *n_object, int n_object_host_submodel)
camid cam_create(char *n_name, vec3d *n_pos, vec3d *n_norm, object *n_object, int n_object_host_submodel)
{
matrix ori;
vm_vector_2_matrix_norm(&ori, n_norm);
return cam_create(n_name, n_pos, &ori, n_object, n_object_host_submodel);
}
camid cam_create(const char *n_name, vec3d *n_pos, matrix *n_ori, object *n_object, int n_object_host_submodel)
camid cam_create(char *n_name, vec3d *n_pos, matrix *n_ori, object *n_object, int n_object_host_submodel)
{
camera *cam = NULL;
camid cid;
+4 -4
View File
@@ -43,13 +43,13 @@ protected:
vec3d c_pos;
matrix c_ori;
public:
camera(const char *in_name=NULL, int in_signature=-1);
camera(char *in_name=NULL, int in_signature=-1);
~camera();
void clear();
void reset();
//Set
void set_name(const char *in_name);
void set_name(char *in_name);
void set_object_host(object *objp, int n_object_host_submodel = -1);
void set_object_target(object *objp, int n_object_target_submodel = -1);
@@ -158,8 +158,8 @@ extern float Sexp_fov;
void cam_init();
void cam_close();
void cam_do_frame(float frametime);
camid cam_create(const char *n_name=NULL, vec3d *n_pos=NULL, matrix *n_ori=NULL, object *n_object=NULL, int n_submodel_parent=-1);
camid cam_create(const char *n_name, vec3d *n_pos, vec3d *n_norm, object *n_object=NULL, int n_submodel_parent=-1);
camid cam_create(char *n_name=NULL, vec3d *n_pos=NULL, matrix *n_ori=NULL, object *n_object=NULL, int n_submodel_parent=-1);
camid cam_create(char *n_name, vec3d *n_pos, vec3d *n_norm, object *n_object=NULL, int n_submodel_parent=-1);
void cam_delete(camid cid);
bool cam_set_camera(camid cid);
void cam_reset_camera();
+10 -13
View File
@@ -14,7 +14,6 @@
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <sys/stat.h>
#ifdef _WIN32
#include <io.h>
@@ -24,6 +23,7 @@
#endif
#ifdef SCP_UNIX
#include <sys/stat.h>
#include <glob.h>
#include <sys/mman.h>
#endif
@@ -69,7 +69,7 @@ cf_pathtype Pathtypes[CF_MAX_PATH_TYPES] = {
{ CF_TYPE_VOICE_SPECIAL, "data" DIR_SEPARATOR_STR "voice" DIR_SEPARATOR_STR "special", ".wav .ogg", CF_TYPE_VOICE },
{ CF_TYPE_VOICE_TRAINING, "data" DIR_SEPARATOR_STR "voice" DIR_SEPARATOR_STR "training", ".wav .ogg", CF_TYPE_VOICE },
{ CF_TYPE_MUSIC, "data" DIR_SEPARATOR_STR "music", ".wav .ogg", CF_TYPE_DATA },
{ CF_TYPE_MOVIES, "data" DIR_SEPARATOR_STR "movies", ".mve .msb .ogg .mp4", CF_TYPE_DATA },
{ CF_TYPE_MOVIES, "data" DIR_SEPARATOR_STR "movies", ".mve .msb .ogg", CF_TYPE_DATA },
{ CF_TYPE_INTERFACE, "data" DIR_SEPARATOR_STR "interface", ".pcx .ani .dds .tga .eff .png .jpg", CF_TYPE_DATA },
{ CF_TYPE_FONT, "data" DIR_SEPARATOR_STR "fonts", ".vf .ttf", CF_TYPE_DATA },
{ CF_TYPE_EFFECTS, "data" DIR_SEPARATOR_STR "effects", ".ani .eff .pcx .neb .tga .jpg .png .dds .sdr", CF_TYPE_DATA },
@@ -82,13 +82,12 @@ cf_pathtype Pathtypes[CF_MAX_PATH_TYPES] = {
{ CF_TYPE_CACHE, "data" DIR_SEPARATOR_STR "cache", ".clr .tmp .bx", CF_TYPE_DATA }, //clr=cached color
{ CF_TYPE_MULTI_CACHE, "data" DIR_SEPARATOR_STR "multidata", ".pcx .png .dds .fs2 .txt", CF_TYPE_DATA },
{ CF_TYPE_MISSIONS, "data" DIR_SEPARATOR_STR "missions", ".fs2 .fc2 .ntl .ssv", CF_TYPE_DATA },
{ CF_TYPE_CONFIG, "data" DIR_SEPARATOR_STR "config", ".cfg .tbl .tbm .xml .csv", CF_TYPE_DATA },
{ CF_TYPE_CONFIG, "data" DIR_SEPARATOR_STR "config", ".cfg", CF_TYPE_DATA },
{ CF_TYPE_DEMOS, "data" DIR_SEPARATOR_STR "demos", ".fsd", CF_TYPE_DATA },
{ CF_TYPE_CBANIMS, "data" DIR_SEPARATOR_STR "cbanims", ".pcx .ani .eff .tga .jpg .png .dds", CF_TYPE_DATA },
{ CF_TYPE_INTEL_ANIMS, "data" DIR_SEPARATOR_STR "intelanims", ".pcx .ani .eff .tga .jpg .png .dds", CF_TYPE_DATA },
{ CF_TYPE_SCRIPTS, "data" DIR_SEPARATOR_STR "scripts", ".lua .lc", CF_TYPE_DATA },
{ CF_TYPE_FICTION, "data" DIR_SEPARATOR_STR "fiction", ".txt", CF_TYPE_DATA },
{ CF_TYPE_FREDDOCS, "data" DIR_SEPARATOR_STR "freddocs", ".html", CF_TYPE_DATA },
};
@@ -129,14 +128,12 @@ static void dump_opened_files()
}
}
void cfile_close()
static void cfile_close()
{
mprintf(("Still opened files:\n"));
dump_opened_files();
cf_free_secondary_filelist();
cfile_inited = 0;
}
#ifdef SCP_UNIX
@@ -242,6 +239,8 @@ int cfile_init(const char *exe_dir, const char *cdrom_dir)
Cfile_cdrom_dir = cdrom_dir;
cf_build_secondary_filelist(Cfile_cdrom_dir);
atexit(cfile_close);
return 0;
}
@@ -609,7 +608,7 @@ static void mkdir_recursive(const char *path) {
while ((pos = tmp.find_first_of(DIR_SEPARATOR_CHAR, pre)) != std::string::npos) {
dir = tmp.substr(0, pos++);
pre = pos;
if (dir.empty()) continue; // if leading / first time is 0 length
if (dir.size() == 0) continue; // if leading / first time is 0 length
_mkdir(dir.c_str());
}
@@ -622,7 +621,6 @@ void cf_create_directory( int dir_type )
int num_dirs = 0;
int dir_tree[CF_MAX_PATH_TYPES];
char longname[MAX_PATH_LEN];
struct stat statbuf;
Assertion( CF_TYPE_SPECIFIED(dir_type), "Invalid dir_type passed to cf_create_directory." );
@@ -636,14 +634,13 @@ void cf_create_directory( int dir_type )
} while( current_dir != CF_TYPE_ROOT );
int i;
for (i=num_dirs-1; i>=0; i-- ) {
cf_create_default_path_string( longname, sizeof(longname)-1, dir_tree[i], NULL );
if (stat(longname, &statbuf) != 0) {
mprintf(( "CFILE: Creating new directory '%s'\n", longname ));
mkdir_recursive(longname);
}
mprintf(( "CFILE: Creating new directory '%s'\n", longname ));
mkdir_recursive(longname);
}
}
+1 -3
View File
@@ -78,9 +78,8 @@ typedef struct {
#define CF_TYPE_INTEL_ANIMS 34
#define CF_TYPE_SCRIPTS 35
#define CF_TYPE_FICTION 36
#define CF_TYPE_FREDDOCS 37
#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
#define CF_MAX_PATH_TYPES 37 // 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
@@ -117,7 +116,6 @@ extern char Cfile_user_dir_legacy[CFILE_ROOT_DIRECTORY_LEN];
//================= LOW-LEVEL FUNCTIONS ==================
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
+2 -10
View File
@@ -161,15 +161,10 @@ int cfseek( CFILE *cfile, int offset, int where )
default:
Int3();
return 1;
}
// Make sure we don't seek beyond the end of the file
CAP(goal_position, cb->lib_offset, cb->lib_offset + cb->size);
}
int result = fseek(cb->fp, (long)goal_position, SEEK_SET );
Assertion(goal_position >= cb->lib_offset, "Invalid offset values detected while seeking! Goal was " SIZE_T_ARG ", lib_offset is " SIZE_T_ARG ".", goal_position, cb->lib_offset);
cb->raw_position = goal_position - cb->lib_offset;
Assertion(cb->raw_position <= cb->size, "Invalid raw_position value detected!");
#if defined(CHECK_POSITION) && !defined(NDEBUG)
auto tmp_offset = ftell(cb->fp) - cb->lib_offset;
@@ -205,7 +200,6 @@ int cfread(void *buf, int elsize, int nelem, CFILE *cfile)
}
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;
@@ -225,7 +219,6 @@ int cfread(void *buf, int elsize, int nelem, CFILE *cfile)
size_t bytes_read = fread( buf, 1, size, cb->fp );
if ( bytes_read > 0 ) {
cb->raw_position += bytes_read;
Assertion(cb->raw_position <= cb->size, "Invalid raw_position value detected!");
}
#if defined(CHECK_POSITION) && !defined(NDEBUG)
@@ -256,8 +249,7 @@ int cfread_lua_number(double *buf, CFILE *cfile)
long orig_pos = ftell(cb->fp);
int items_read = fscanf(cb->fp, LUA_NUMBER_SCAN, buf);
cb->raw_position += ftell(cb->fp)-orig_pos;
Assertion(cb->raw_position <= cb->size, "Invalid raw_position value detected!");
cb->raw_position += ftell(cb->fp)-orig_pos;
#if defined(CHECK_POSITION) && !defined(NDEBUG)
auto tmp_offset = ftell(cb->fp) - cb->lib_offset;
+73 -175
View File
@@ -30,7 +30,6 @@
#include <fnmatch.h>
#include <sys/stat.h>
#include <unistd.h>
#include <libgen.h>
#endif
#include "cfile/cfile.h"
@@ -39,13 +38,12 @@
#include "globalincs/pstypes.h"
#include "localization/localize.h"
#include "osapi/osapi.h"
#include "parse/parselo.h"
#define CF_ROOTTYPE_PATH 0
#define CF_ROOTTYPE_PACK 1
// for a defined and specifically set location to get/send pilot/campaign files
SCP_string Pilot_file_path;
char *Pilot_file_path = NULL;
// Created by:
// specifying hard drive tree
@@ -79,13 +77,12 @@ static int Num_path_roots = 0;
// Created by searching all roots in order. This means Files is then sorted by precedence.
typedef struct cf_file {
char name_ext[CF_MAX_FILENAME_LENGTH]; // Filename and extension
int root_index; // Where in Roots this is located
int pathtype_index; // Where in Paths this is located
time_t write_time; // When it was last written
int size; // How big it is in bytes
int pack_offset; // For pack files, where it is at. 0 if not in a pack file. This can be used to tell if in a pack file.
char* real_name; // For real files, the full path
char name_ext[CF_MAX_FILENAME_LENGTH]; // Filename and extension
int root_index; // Where in Roots this is located
int pathtype_index; // Where in Paths this is located
time_t write_time; // When it was last written
int size; // How big it is in bytes
int pack_offset; // For pack files, where it is at. 0 if not in a pack file. This can be used to tell if in a pack file.
} cf_file;
#define CF_NUM_FILES_PER_BLOCK 512
@@ -118,7 +115,6 @@ cf_file *cf_create_file()
if ( File_blocks[block] == NULL ) {
File_blocks[block] = (cf_file_block *)vm_malloc( sizeof(cf_file_block) );
Assert( File_blocks[block] != NULL);
memset(File_blocks[block], 0, sizeof(cf_file_block));
}
Num_files++;
@@ -432,7 +428,7 @@ void cf_build_root_list(const char *cdrom_dir)
root->roottype = CF_ROOTTYPE_PATH;
// If it wasn't set before, set the pilot path
if (Pilot_file_path.empty())
if (Pilot_file_path == NULL)
Pilot_file_path = root->path;
// Next, check any VP files under the current directory.
@@ -459,7 +455,7 @@ void cf_build_root_list(const char *cdrom_dir)
root->roottype = CF_ROOTTYPE_PATH;
// set the default player location to here
if (Pilot_file_path.empty())
if (Pilot_file_path == NULL)
Pilot_file_path = root->path;
// Next, check any VP files under the current directory.
@@ -489,7 +485,7 @@ void cf_build_root_list(const char *cdrom_dir)
root->roottype = CF_ROOTTYPE_PATH;
// If the path wasn't set before use the working directory
if ( Pilot_file_path.empty() )
if ( Pilot_file_path == NULL )
Pilot_file_path = root->path;
//======================================================
@@ -538,10 +534,6 @@ void cf_search_root_path(int root_index)
mprintf(( "Searching root '%s' ... ", root->path ));
char search_path[CF_MAX_PATHNAME_LENGTH];
#ifdef SCP_UNIX
// This map stores the mapping between a specific path type and the actual path that we use for it
SCP_unordered_map<int, SCP_string> pathTypeToRealPath;
#endif
for (i=CF_TYPE_ROOT; i<CF_MAX_PATH_TYPES; i++ ) {
@@ -560,7 +552,6 @@ void cf_search_root_path(int root_index)
}
#if defined _WIN32
SCP_string search_directory = search_path;
strcat_s( search_path, "*.*" );
intptr_t find_handle;
@@ -585,11 +576,6 @@ void cf_search_root_path(int root_index)
file->size = find.size;
file->pack_offset = 0; // Mark as a non-packed file
SCP_string file_name;
sprintf(file_name, "%s%s%s", search_directory.c_str(), DIR_SEPARATOR_STR, find.name);
file->real_name = vm_strdup(file_name.c_str());
num_files++;
//mprintf(( "Found file '%s'\n", file->name_ext ));
}
@@ -602,80 +588,21 @@ void cf_search_root_path(int root_index)
_findclose( find_handle );
}
#elif defined SCP_UNIX
DIR *dirp = nullptr;
SCP_string search_dir;
{
if (i == CF_TYPE_ROOT) {
// Don't search for the same name for the root case since we would be searching in other mod directories in that case
dirp = opendir (search_path);
search_dir.assign(search_path);
} else {
// On Unix we can have a different case for the search paths so we also need to account for that
// We do that by looking at the parent of search_path and enumerating all directories and the check if any of
// them are a case-insensitive match
SCP_string directory_name;
auto parentPathIter = pathTypeToRealPath.find(Pathtypes[i].parent_index);
if (parentPathIter == pathTypeToRealPath.end()) {
// No parent known yet, use the standard dirname
char dirname_copy[CF_MAX_PATHNAME_LENGTH];
memcpy(dirname_copy, search_path, sizeof(search_path));
// According to the documentation of directory_name and basename, the return value does not need to be freed
directory_name.assign(dirname(dirname_copy));
} else {
// we have a valid parent path -> use that
directory_name = parentPathIter->second;
}
char basename_copy[CF_MAX_PATHNAME_LENGTH];
memcpy(basename_copy, search_path, sizeof(search_path));
// According to the documentation of dirname and basename, the return value does not need to be freed
auto search_name = basename(basename_copy);
auto parentDirP = opendir(directory_name.c_str());
if (parentDirP) {
struct dirent *dir = nullptr;
while ((dir = readdir (parentDirP)) != nullptr) {
if (stricmp(search_name, dir->d_name)) {
continue;
}
SCP_string fn;
sprintf(fn, "%s/%s", directory_name.c_str(), dir->d_name);
struct stat buf;
if (stat(fn.c_str(), &buf) == -1) {
continue;
}
if (S_ISDIR(buf.st_mode)) {
// Found a case insensitive match
dirp = opendir(fn.c_str());
search_dir = fn;
// We also need to store this in our mapping since we may need it in the future
pathTypeToRealPath.insert(std::make_pair(i, fn));
break;
}
}
closedir(parentDirP);
}
}
}
DIR *dirp;
struct dirent *dir;
dirp = opendir (search_path);
if ( dirp ) {
struct dirent *dir = nullptr;
while ((dir = readdir (dirp)) != NULL)
{
if (!fnmatch ("*.*", dir->d_name, 0))
{
SCP_string fn;
sprintf(fn, "%s/%s", search_dir.c_str(), dir->d_name);
char fn[MAX_PATH];
snprintf(fn, MAX_PATH-1, "%s%s", search_path, dir->d_name);
fn[MAX_PATH-1] = 0;
struct stat buf;
if (stat(fn.c_str(), &buf) == -1) {
if (stat(fn, &buf) == -1) {
continue;
}
@@ -699,8 +626,6 @@ void cf_search_root_path(int root_index)
file->pack_offset = 0; // Mark as a non-packed file
file->real_name = vm_strdup(fn.c_str());
num_files++;
//mprintf(( "Found file '%s'\n", file->name_ext ));
}
@@ -902,14 +827,6 @@ void cf_free_secondary_filelist()
// Init the file blocks
for (i=0; i<CF_MAX_FILE_BLOCKS; i++ ) {
if ( File_blocks[i] ) {
// Free file paths
for (auto& f : File_blocks[i]->files) {
if (f.real_name) {
vm_free(f.real_name);
f.real_name = nullptr;
}
}
vm_free( File_blocks[i] );
File_blocks[i] = NULL;
}
@@ -1068,14 +985,17 @@ int cf_find_file_location( const char *filespec, int pathtype, int max_out, char
*offset = (size_t)f->pack_offset;
if (pack_filename) {
if (f->pack_offset < 1) {
// This is a real file, return the actual file path
strncpy( pack_filename, f->real_name, max_out );
} else {
// File is in a pack file
cf_root *r = cf_get_root(f->root_index);
cf_root *r = cf_get_root(f->root_index);
strncpy( pack_filename, r->path, max_out );
strncpy( pack_filename, r->path, max_out );
if (f->pack_offset < 1) {
strcat_s( pack_filename, max_out, Pathtypes[f->pathtype_index].path );
if ( pack_filename[strlen(pack_filename)-1] != DIR_SEPARATOR_CHAR )
strcat_s( pack_filename, max_out, DIR_SEPARATOR_STR );
strcat_s( pack_filename, max_out, f->name_ext );
}
}
@@ -1093,14 +1013,19 @@ int cf_find_file_location( const char *filespec, int pathtype, int max_out, char
*offset = (size_t)f->pack_offset;
if (pack_filename) {
if (f->pack_offset < 1) {
// This is a real file, return the actual file path
strncpy( pack_filename, f->real_name, max_out );
} else {
// File is in a pack file
cf_root *r = cf_get_root(f->root_index);
cf_root *r = cf_get_root(f->root_index);
strncpy( pack_filename, r->path, max_out );
strcpy( pack_filename, r->path );
if (f->pack_offset < 1) {
if ( strlen(Pathtypes[f->pathtype_index].path) ) {
strcat_s( pack_filename, max_out, Pathtypes[f->pathtype_index].path );
if ( pack_filename[strlen(pack_filename)-1] != DIR_SEPARATOR_CHAR )
strcat_s( pack_filename, max_out, DIR_SEPARATOR_STR );
}
strcat_s( pack_filename, max_out, f->name_ext );
}
}
@@ -1335,14 +1260,17 @@ int cf_find_file_location_ext( const char *filename, const int ext_num, const ch
*offset = f->pack_offset;
if (pack_filename) {
if (f->pack_offset < 1) {
// This is a real file, return the actual file path
strncpy( pack_filename, f->real_name, max_out );
} else {
// File is in a pack file
cf_root *r = cf_get_root(f->root_index);
cf_root *r = cf_get_root(f->root_index);
strncpy( pack_filename, r->path, max_out );
strncpy( pack_filename, r->path, max_out );
if (f->pack_offset < 1) {
strcat_s( pack_filename, max_out, Pathtypes[f->pathtype_index].path );
if ( pack_filename[strlen(pack_filename)-1] != DIR_SEPARATOR_CHAR )
strcat_s( pack_filename, max_out, DIR_SEPARATOR_STR );
strcat_s( pack_filename, max_out, f->name_ext );
}
}
@@ -1363,14 +1291,20 @@ int cf_find_file_location_ext( const char *filename, const int ext_num, const ch
*offset = f->pack_offset;
if (pack_filename) {
if (f->pack_offset < 1) {
// This is a real file, return the actual file path
strncpy( pack_filename, f->real_name, max_out );
} else {
// File is in a pack file
cf_root *r = cf_get_root(f->root_index);
cf_root *r = cf_get_root(f->root_index);
strncpy( pack_filename, r->path, max_out );
strcpy( pack_filename, r->path );
if (f->pack_offset < 1) {
if ( strlen(Pathtypes[f->pathtype_index].path) ) {
strcat_s( pack_filename, max_out, Pathtypes[f->pathtype_index].path );
if ( pack_filename[strlen(pack_filename)-1] != DIR_SEPARATOR_CHAR )
strcat_s( pack_filename, max_out, DIR_SEPARATOR_STR );
}
strcat_s( pack_filename, max_out, f->name_ext );
}
}
@@ -1567,10 +1501,8 @@ int cf_get_file_list( SCP_vector<SCP_string> &list, int pathtype, const char *fi
continue;
char fn[MAX_PATH];
if (snprintf(fn, MAX_PATH, "%s/%s", filespec, dir->d_name) >= MAX_PATH) {
// Make sure the string is null terminated
fn[MAX_PATH-1] = 0;
}
snprintf(fn, MAX_PATH-1, "%s/%s", filespec, dir->d_name);
fn[MAX_PATH-1] = 0;
struct stat buf;
if (stat(fn, &buf) == -1) {
@@ -1605,7 +1537,8 @@ int cf_get_file_list( SCP_vector<SCP_string> &list, int pathtype, const char *fi
}
#endif
bool skip_packfiles = false;
bool skip_packfiles = (Skip_packfile_search != 0);
if ( (pathtype == CF_TYPE_PLAYERS) || (pathtype == CF_TYPE_SINGLE_PLAYERS) || (pathtype == CF_TYPE_MULTI_PLAYERS) ) {
skip_packfiles = true;
} else if (Get_file_list_child != NULL) {
@@ -1630,11 +1563,6 @@ int cf_get_file_list( SCP_vector<SCP_string> &list, int pathtype, const char *fi
continue;
}
if (Skip_packfile_search && f->pack_offset != 0) {
// If the packfile skip flag is set we skip files in VPs but still search in directories
continue;
}
if ( !Get_file_list_filter || (*Get_file_list_filter)(f->name_ext) ) {
//mprintf(( "Found '%s' in root %d path %d\n", f->name_ext, f->root_index, f->pathtype_index ));
@@ -1778,10 +1706,8 @@ int cf_get_file_list( int max, char **list, int pathtype, const char *filter, in
continue;
char fn[MAX_PATH];
if (snprintf(fn, MAX_PATH, "%s/%s", filespec, dir->d_name) >= MAX_PATH) {
// Make sure the string is null terminated
fn[MAX_PATH-1] = 0;
}
snprintf(fn, MAX_PATH-1, "%s/%s", filespec, dir->d_name);
fn[MAX_PATH-1] = 0;
struct stat buf;
if (stat(fn, &buf) == -1) {
@@ -1813,16 +1739,8 @@ int cf_get_file_list( int max, char **list, int pathtype, const char *filter, in
}
#endif
bool skip_packfiles = false;
if ((pathtype == CF_TYPE_PLAYERS) || (pathtype == CF_TYPE_SINGLE_PLAYERS) || (pathtype == CF_TYPE_MULTI_PLAYERS)) {
skip_packfiles = true;
}
else if (Get_file_list_child != NULL) {
skip_packfiles = true;
}
// Search all the packfiles and CD.
if ( !skip_packfiles) {
if ( !Skip_packfile_search ) {
for (i=0; i<Num_files; i++ ) {
cf_file * f = cf_get_file(i);
@@ -1842,11 +1760,6 @@ int cf_get_file_list( int max, char **list, int pathtype, const char *filter, in
continue;
}
if (Skip_packfile_search && f->pack_offset != 0) {
// If the packfile skip flag is set we skip files in VPs but still search in directories
continue;
}
if ( !Get_file_list_filter || (*Get_file_list_filter)(f->name_ext) ) {
//mprintf(( "Found '%s' in root %d path %d\n", f->name_ext, f->root_index, f->pathtype_index ));
@@ -1995,10 +1908,8 @@ int cf_get_file_list_preallocated( int max, char arr[][MAX_FILENAME_LEN], char *
continue;
char fn[MAX_PATH];
if (snprintf(fn, MAX_PATH, "%s/%s", filespec, dir->d_name) >= MAX_PATH) {
// Make sure the string is null terminated
fn[MAX_PATH-1] = 0;
}
snprintf(fn, MAX_PATH-1, "%s/%s", filespec, dir->d_name);
fn[MAX_PATH-1] = 0;
struct stat buf;
if (stat(fn, &buf) == -1) {
@@ -2032,16 +1943,8 @@ int cf_get_file_list_preallocated( int max, char arr[][MAX_FILENAME_LEN], char *
}
#endif
bool skip_packfiles = false;
if ((pathtype == CF_TYPE_PLAYERS) || (pathtype == CF_TYPE_SINGLE_PLAYERS) || (pathtype == CF_TYPE_MULTI_PLAYERS)) {
skip_packfiles = true;
}
else if (Get_file_list_child != NULL) {
skip_packfiles = true;
}
// Search all the packfiles and CD.
if (!skip_packfiles) {
if ( !Skip_packfile_search ) {
for (uint i=0; i<Num_files; i++ ) {
cf_file * f = cf_get_file(i);
@@ -2062,11 +1965,6 @@ int cf_get_file_list_preallocated( int max, char arr[][MAX_FILENAME_LEN], char *
continue;
}
if (Skip_packfile_search && f->pack_offset != 0) {
// If the packfile skip flag is set we skip files in VPs but still search in directories
continue;
}
if ( !Get_file_list_filter || (*Get_file_list_filter)(f->name_ext) ) {
//mprintf(( "Found '%s' in root %d path %d\n", f->name_ext, f->root_index, f->pathtype_index ));
@@ -2134,7 +2032,7 @@ int cf_create_default_path_string(char *path, uint path_max, int pathtype, const
// force a specific directory to search for player files
if ( (pathtype == CF_TYPE_PLAYERS) || (pathtype == CF_TYPE_SINGLE_PLAYERS) || (pathtype == CF_TYPE_MULTI_PLAYERS) ) {
strncpy(path, Pilot_file_path.c_str(), path_max);
strncpy(path, Pilot_file_path, path_max);
} else {
strncpy(path, root->path, path_max);
}
+4 -4
View File
@@ -20,10 +20,10 @@ void cf_free_secondary_filelist();
// Internal stuff
typedef struct cf_pathtype {
int index; // To verify that the CF_TYPE define is correctly indexed into this array
const char* path; // Path relative to FreeSpace root, has ending backslash.
const char* extensions; // Extensions used in this pathtype, separated by spaces
int parent_index; // Index of this directory's parent. Used for creating directories when writing.
int index; // To verify that the CF_TYPE define is correctly indexed into this array
char *path; // Path relative to FreeSpace root, has ending backslash.
char *extensions; // Extensions used in this pathtype, separated by spaces
int parent_index; // Index of this directory's parent. Used for creating directories when writing.
} cf_pathtype;
// During cfile_init, verify that Pathtypes[n].index == n for each item
+1 -1
View File
@@ -8,7 +8,7 @@ set_target_properties(cfilearchiver
PROPERTIES
FOLDER "FSOTools"
)
TARGET_LINK_LIBRARIES(cfilearchiver PUBLIC sdl2)
TARGET_LINK_LIBRARIES(cfilearchiver PUBLIC ${SDL_LIBS})
TARGET_INCLUDE_DIRECTORIES(cfilearchiver PUBLIC ${GENERATED_SOURCE_DIR})
TARGET_INCLUDE_DIRECTORIES(cfilearchiver PUBLIC ${GENERATED_SOURCE_DIR}/code)
+31 -10
View File
@@ -315,16 +315,28 @@ int verify_directory( char *filespec )
void print_instructions()
{
printf("Creates a vp archive out of a FreeSpace data tree.\n\n");
printf("Usage: cfilearchiver archive_name src_dir\n");
#ifdef _WIN32
printf("Example: cfilearchiver freespace c:\\freespace\\data\n");
#else
printf("Example: cfilearchiver freespace /tmp/freespace/data\n\n");
#endif
printf("Creates an archive named freespace out of the freespace data tree\n");
printf("For information about the FS2 directory structure, please consult\n");
printf("http://www.hard-light.net/wiki/index.php/FS2_Data_Structure\n");
printf( "Creates a vp archive out of a FreeSpace data tree.\n\n" );
printf( "Usage: cfilearchiver archive_name src_dir\n");
printf( "Example: cfilearchiver freespace /tmp/freespace/data\n\n");
printf( "Directory structure options:\n" );
printf( " Effects (.ani .pcx .neb .tga)\n" );
printf( " Fonts (.vf)\n" );
printf( " Hud (.ani .pcx .tga\n" );
printf( " Interface (.pcx .ani .tga)\n" );
printf( " Maps (.pcx .ani .tga)\n" );
printf( " Missions (.ntl .ssv), FS1(.fsm .fsc), FS2(.fs2 .fc2)\n" );
printf( " Models (.pof)\n" );
printf( " Music (.wav)\n" );
printf( " Sounds/8b22k (.wav)\n" );
printf( " Sounds/16b11k (.wav)\n" );
printf( " Tables (.tbl)\n" );
printf( " Voice/Briefing (.wav)\n" );
printf( " Voice/Command briefings (.wav)\n" );
printf( " Voice/Debriefing (.wav)\n" );
printf( " Voice/Personas (.wav)\n" );
printf( " Voice/Special (.wav)\n" );
printf( " Voice/Training (.wav)\n" );
exit(0);
}
@@ -340,7 +352,16 @@ int main(int argc, char *argv[] )
char *p;
if ( argc < 3 ) {
#ifdef _WIN32
printf( "Usage: %s archive_name src_dir\n", argv[0] );
printf( "Example: %s freespace c:\\freespace\\data\n", argv[0] );
printf( "Creates an archive named freespace out of the\nfreespace data tree\n" );
printf( "Press any key to exit...\n" );
getch();
return 1;
#else
print_instructions();
#endif
}
strcpy_s( archive, argv[1] );
+1 -1
View File
@@ -8,7 +8,7 @@ set_target_properties(cfileextractor
PROPERTIES
FOLDER "FSOTools"
)
TARGET_LINK_LIBRARIES(cfileextractor PUBLIC sdl2)
TARGET_LINK_LIBRARIES(cfileextractor PUBLIC ${SDL_LIBS})
TARGET_INCLUDE_DIRECTORIES(cfileextractor PUBLIC ${GENERATED_SOURCE_DIR})
TARGET_INCLUDE_DIRECTORIES(cfileextractor PUBLIC ${GENERATED_SOURCE_DIR}/code)
+118 -369
View File
@@ -17,15 +17,12 @@
#include "globalincs/version.h"
#include "hud/hudconfig.h"
#include "network/multi.h"
#include "scripting/scripting.h"
#include "parse/scripting.h"
#include "parse/sexp.h"
#include "globalincs/version.h"
#include "globalincs/pstypes.h"
#include "osapi/osapi.h"
#include "cfile/cfilesystem.h"
#include "sound/speech.h"
#include "sound/openal.h"
#include "io/joy.h"
#ifdef _WIN32
#include <io.h>
@@ -41,9 +38,6 @@
#include <string.h>
#include <stdlib.h>
#include <cstdio>
#include <jansson.h>
// Stupid windows workaround...
#ifdef MessageBox
@@ -66,11 +60,6 @@ const char *cmdline_arg_types[] =
"STRING",
};
enum class flag_output_type {
Binary,
Json_V1,
};
// variables
class cmdline_parm {
public:
@@ -89,7 +78,6 @@ public:
float get_float();
char *str();
bool check_if_args_is_valid();
bool has_param();
};
static cmdline_parm Parm_list(NULL, NULL, AT_NONE);
@@ -162,7 +150,6 @@ Flag exe_params[] =
{ "-noscalevid", "Disable scale-to-window for movies", true, 0, EASY_DEFAULT, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-noscalevid", },
{ "-missile_lighting", "Apply lighting to missiles" , true, EASY_ALL_ON, EASY_DEFAULT, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-missile_lighting", },
{ "-nonormal", "Disable normal maps", true, EASY_DEFAULT_MEM, EASY_MEM_ALL_ON, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-normal" },
{ "-no_emissive_light", "Disable emissive light from ships", true, 0, EASY_DEFAULT, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_emissive_light" },
{ "-noheight", "Disable height/parallax maps", true, EASY_DEFAULT_MEM, EASY_MEM_ALL_ON, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-height" },
{ "-3dshockwave", "Enable 3D shockwaves", true, EASY_MEM_ALL_ON, EASY_DEFAULT_MEM, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-3dshockwave" },
{ "-post_process", "Enable post processing", true, EASY_ALL_ON, EASY_DEFAULT, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-post_process" },
@@ -189,6 +176,7 @@ Flag exe_params[] =
{ "-no_ap_interrupt", "Disable interrupting autopilot", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_ap_interrupt", },
{ "-stretch_menu", "Stretch interface to fill screen", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-stretch_menu", },
{ "-snd_preload", "Preload mission game sounds", true, EASY_MEM_ALL_ON, EASY_DEFAULT_MEM, "Audio", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-snd_preload", },
{ "-nosound", "Disable all sound", false, 0, EASY_DEFAULT, "Audio", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-nosound", },
{ "-nomusic", "Disable music", false, 0, EASY_DEFAULT, "Audio", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-nomusic", },
{ "-no_enhanced_sound", "Disable enhanced sound", false, 0, EASY_DEFAULT, "Audio", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_enhanced_sound", },
@@ -207,9 +195,11 @@ Flag exe_params[] =
{ "-nomovies", "Disable video playback", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-nomovies", },
{ "-noparseerrors", "Disable parsing errors", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-noparseerrors", },
{ "-query_speech", "Check if this build has speech", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-query_speech", },
{ "-novbo", "Disable OpenGL VBO", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-novbo", },
{ "-loadallweps", "Load all weapons, even those not used", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-loadallweps", },
{ "-disable_fbo", "Disable OpenGL RenderTargets", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-disable_fbo", },
{ "-disable_pbo", "Disable OpenGL Pixel Buffer Objects", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-disable_pbo", },
{ "-no_glsl", "Disable GLSL (shader) support", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_glsl", },
{ "-ati_swap", "Fix colour issues on some ATI cards", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-ati_swap", },
{ "-no_3d_sound", "Use only 2D/stereo for sound effects", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_3d_sound", },
{ "-mipmap", "Enable mipmapping", true, 0, EASY_DEFAULT_MEM, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-mipmap", },
@@ -219,8 +209,6 @@ Flag exe_params[] =
{ "-no_batching", "Disable batched model rendering", true, 0, EASY_DEFAULT, "Troubleshoot", "", },
{ "-no_geo_effects", "Disable geometry shader for effects", true, 0, EASY_DEFAULT, "Troubleshoot", "", },
{ "-set_cpu_affinity", "Sets processor affinity to config value", true, 0, EASY_DEFAULT, "Troubleshoot", "", },
{ "-nograb", "Disables mouse grabbing", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-nograb", },
{ "-noshadercache", "Disables the shader cache", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-noshadercache", },
#ifdef WIN32
{ "-fix_registry", "Use a different registry path", true, 0, EASY_DEFAULT, "Troubleshoot", "", },
#endif
@@ -229,7 +217,6 @@ Flag exe_params[] =
{ "-voicer", "Enable voice recognition", true, 0, EASY_DEFAULT, "Experimental", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-voicer", },
{ "-fps", "Show frames per second on HUD", false, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-fps", },
{ "-bmpmanusage", "Show how many BMPMAN slots are in use", false, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-bmpmanusage", },
{ "-pos", "Show position of camera", false, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-pos", },
{ "-window", "Run in window", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-window", },
{ "-fullscreen_window", "Run in fullscreen window", false, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-fullscreen_window", },
@@ -244,16 +231,14 @@ Flag exe_params[] =
{ "-output_sexps", "Output SEXPs to sexps.html", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-output_sexps", },
{ "-output_scripting", "Output scripting to scripting.html", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-output_scripting", },
{ "-save_render_target", "Save render targets to file", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-save_render_target", },
{ "-debug_window", "Display debug window", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-debug_window", },
{ "-verify_vps", "Spew VP CRCs to vp_crcs.txt", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-verify_vps", },
{ "-reparse_mainhall", "Reparse mainhall.tbl when loading halls", false, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-reparse_mainhall", },
{ "-profile_frame_time","Profile engine subsystems", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-profile_frame_timings", },
{ "-profile_write_file", "Write profiling information to file", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-profile_write_file", },
{ "-no_unfocused_pause","Don't pause if the window isn't focused", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_unfocused_pause", },
{ "-benchmark_mode", "Puts the game into benchmark mode", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-benchmark_mode", },
{ "-noninteractive", "Disables interactive dialogs", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-noninteractive", },
{ "-json_pilot", "Dump pilot files in JSON format", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-json_pilot", },
{ "-json_profiling", "Generate JSON profiling output", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-json_profiling", },
{ "-profile_frame_time","Profile engine subsystems", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-profile_frame_timings", },
{ "-debug_window", "Enable the debug window", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-debug_window", },
};
// forward declaration
@@ -405,9 +390,11 @@ int Cmdline_stretch_menu = 0;
// Audio related
cmdline_parm query_speech_arg("-query_speech", NULL, AT_NONE); // Cmdline_query_speech
cmdline_parm snd_preload_arg("-snd_preload", NULL, AT_NONE); // Cmdline_snd_preload
cmdline_parm voice_recognition_arg("-voicer", NULL, AT_NONE); // Cmdline_voice_recognition
int Cmdline_query_speech = 0;
int Cmdline_snd_preload = 0; // preload game sounds during mission load
int Cmdline_voice_recognition = 0;
int Cmdline_no_enhanced_sound = 0;
@@ -440,8 +427,10 @@ bool Cmdline_portable_mode = false;
cmdline_parm loadallweapons_arg("-loadallweps", NULL, AT_NONE); // Cmdline_load_all_weapons
cmdline_parm nomovies_arg("-nomovies", NULL, AT_NONE); // Cmdline_nomovies -- Allows video streaming
cmdline_parm no_set_gamma_arg("-no_set_gamma", NULL, AT_NONE); // Cmdline_no_set_gamma
cmdline_parm no_vbo_arg("-novbo", NULL, AT_NONE); // Cmdline_novbo
cmdline_parm no_fbo_arg("-disable_fbo", NULL, AT_NONE); // Cmdline_no_fbo
cmdline_parm no_pbo_arg("-disable_pbo", NULL, AT_NONE); // Cmdline_no_pbo
cmdline_parm noglsl_arg("-no_glsl", NULL, AT_NONE); // Cmdline_noglsl -- disable GLSL support in OpenGL
cmdline_parm mipmap_arg("-mipmap", NULL, AT_NONE); // Cmdline_mipmap
cmdline_parm atiswap_arg("-ati_swap", NULL, AT_NONE); // Cmdline_atiswap - Fix ATI color swap issue for screenshots.
cmdline_parm no3dsound_arg("-no_3d_sound", NULL, AT_NONE); // Cmdline_no_3d_sound - Disable use of full 3D sounds
@@ -451,8 +440,6 @@ cmdline_parm old_collision_system("-old_collision", NULL, AT_NONE); // Cmdline_o
cmdline_parm gl_finish ("-gl_finish", NULL, AT_NONE);
cmdline_parm no_geo_sdr_effects("-no_geo_effects", NULL, AT_NONE);
cmdline_parm set_cpu_affinity("-set_cpu_affinity", NULL, AT_NONE);
cmdline_parm nograb_arg("-nograb", NULL, AT_NONE);
cmdline_parm noshadercache_arg("-noshadercache", NULL, AT_NONE);
#ifdef WIN32
cmdline_parm fix_registry("-fix_registry", NULL, AT_NONE);
#endif
@@ -460,8 +447,10 @@ cmdline_parm fix_registry("-fix_registry", NULL, AT_NONE);
int Cmdline_load_all_weapons = 0;
int Cmdline_nomovies = 0;
int Cmdline_no_set_gamma = 0;
int Cmdline_novbo = 0; // turn off OGL VBO support, troubleshooting
int Cmdline_no_fbo = 0;
int Cmdline_no_pbo = 0;
int Cmdline_noglsl = 0;
int Cmdline_ati_color_swap = 0;
int Cmdline_no_3d_sound = 0;
int Cmdline_drawelements = 0;
@@ -469,8 +458,6 @@ char* Cmdline_keyboard_layout = NULL;
bool Cmdline_gl_finish = false;
bool Cmdline_no_geo_sdr_effects = false;
bool Cmdline_set_cpu_affinity = false;
bool Cmdline_nograb = false;
bool Cmdline_noshadercache = false;
#ifdef WIN32
bool Cmdline_alternate_registry_path = false;
#endif
@@ -482,7 +469,7 @@ cmdline_parm dis_weapons("-dis_weapons", NULL, AT_NONE); // Cmdline_dis_weapons
cmdline_parm noparseerrors_arg("-noparseerrors", NULL, AT_NONE); // Cmdline_noparseerrors -- turns off parsing errors -C
cmdline_parm extra_warn_arg("-extra_warn", "Enable 'extra' warnings", AT_NONE); // Cmdline_extra_warn
cmdline_parm fps_arg("-fps", NULL, AT_NONE); // Cmdline_show_fps
cmdline_parm bmpmanusage_arg("-bmpmanusage", NULL, AT_NONE); // Cmdline_bmpman_usage
cmdline_parm show_mem_usage_arg("-show_mem_usage", NULL, AT_NONE); // Cmdline_show_mem_usage
cmdline_parm pos_arg("-pos", NULL, AT_NONE); // Cmdline_show_pos
cmdline_parm stats_arg("-stats", NULL, AT_NONE); // Cmdline_show_stats
cmdline_parm save_render_targets_arg("-save_render_target", NULL, AT_NONE); // Cmdline_save_render_targets
@@ -493,15 +480,11 @@ cmdline_parm center_res_arg("-center_res", "Resolution of center monitor, format
cmdline_parm verify_vps_arg("-verify_vps", NULL, AT_NONE); // Cmdline_verify_vps -- spew VP crcs to vp_crcs.txt
cmdline_parm parse_cmdline_only(PARSE_COMMAND_LINE_STRING, "Ignore any cmdline_fso.cfg files", AT_NONE);
cmdline_parm reparse_mainhall_arg("-reparse_mainhall", NULL, AT_NONE); //Cmdline_reparse_mainhall
cmdline_parm frame_profile_arg("-profile_frame_time", NULL, AT_NONE); //Cmdline_frame_profile
cmdline_parm frame_profile_write_file("-profile_write_file", NULL, AT_NONE); // Cmdline_profile_write_file
cmdline_parm no_unfocused_pause_arg("-no_unfocused_pause", NULL, AT_NONE); //Cmdline_no_unfocus_pause
cmdline_parm benchmark_mode_arg("-benchmark_mode", NULL, AT_NONE); //Cmdline_benchmark_mode
cmdline_parm noninteractive_arg("-noninteractive", NULL, AT_NONE); //Cmdline_noninteractive
cmdline_parm json_pilot("-json_pilot", NULL, AT_NONE); //Cmdline_json_pilot
cmdline_parm json_profiling("-json_profiling", NULL, AT_NONE); //Cmdline_json_profiling
cmdline_parm show_video_info("-show_video_info", NULL, AT_NONE); //Cmdline_show_video_info
cmdline_parm frame_profile_arg("-profile_frame_time", NULL, AT_NONE); //Cmdline_frame_profile
cmdline_parm debug_window_arg("-debug_window", NULL, AT_NONE); // Cmdline_debug_window
char *Cmdline_start_mission = NULL;
@@ -513,7 +496,7 @@ int Cmdline_noparseerrors = 0;
int Cmdline_nowarn = 0; // turn warnings off in FRED
#endif
int Cmdline_extra_warn = 0;
int Cmdline_bmpman_usage = 0;
int Cmdline_show_mem_usage = 0;
int Cmdline_show_pos = 0;
int Cmdline_show_stats = 0;
int Cmdline_save_render_targets = 0;
@@ -523,18 +506,14 @@ char *Cmdline_res = 0;
char *Cmdline_center_res = 0;
int Cmdline_verify_vps = 0;
int Cmdline_reparse_mainhall = 0;
bool Cmdline_frame_profile = false;
bool Cmdline_profile_write_file = false;
bool Cmdline_no_unfocus_pause = false;
bool Cmdline_benchmark_mode = false;
bool Cmdline_noninteractive = false;
bool Cmdline_json_pilot = false;
bool Cmdline_json_profiling = false;
bool Cmdline_frame_profile = false;
bool Cmdline_show_video_info = false;
bool Cmdline_debug_window = false;
// Other
cmdline_parm get_flags_arg("-get_flags", "Output the launcher flags file", AT_STRING);
cmdline_parm get_flags_arg("-get_flags", "Output the launcher flags file", AT_NONE);
cmdline_parm output_sexp_arg("-output_sexps", NULL, AT_NONE); //WMC - outputs all SEXPs to sexps.html
cmdline_parm output_scripting_arg("-output_scripting", NULL, AT_NONE); //WMC
@@ -547,7 +526,6 @@ cmdline_parm deprecated_tbp_arg("-tbp", "Deprecated", AT_NONE);
cmdline_parm deprecated_jpgtga_arg("-jpgtga", "Deprecated", AT_NONE);
cmdline_parm deprecated_htl_arg("-nohtl", "Deprecated", AT_NONE);
cmdline_parm deprecated_brieflighting_arg("-brief_lighting", "Deprecated", AT_NONE);
cmdline_parm deprecated_sndpreload_arg("-snd_preload", "Deprecated", AT_NONE);
int Cmdline_deprecated_spec = 0;
int Cmdline_deprecated_glow = 0;
@@ -802,7 +780,12 @@ void os_validate_parms(int argc, char *argv[])
if (parm_found == 0) {
// if we got a -help, --help, -h, or -? then show the help text, otherwise show unknown option
if (!stricmp(token, "-help") || !stricmp(token, "--help") || !stricmp(token, "-h") || !stricmp(token, "-?")) {
printf("FreeSpace 2 Open, version %s\n", FS_VERSION_FULL);
if (FS_VERSION_HAS_REVIS == 0) {
printf("FreeSpace 2 Open, version %i.%i.%i\n", FS_VERSION_MAJOR, FS_VERSION_MINOR, FS_VERSION_BUILD);
}
else {
printf("FreeSpace 2 Open, version %i.%i.%i.%i\n", FS_VERSION_MAJOR, FS_VERSION_MINOR, FS_VERSION_BUILD, FS_VERSION_REVIS);
}
printf("Website: http://scp.indiegames.us\n");
printf("Mantis (bug reporting): http://scp.indiegames.us/mantis/\n\n");
printf("Usage: fs2_open [options]\n");
@@ -939,45 +922,32 @@ bool has_cmdline_only_flag(int argc, char *argv[])
return false;
}
// remove old parms - needed for tests
static void reset_cmdline_parms()
{
for (cmdline_parm *parmp = GET_FIRST(&Parm_list); parmp != END_OF_LIST(&Parm_list); parmp = GET_NEXT(parmp)) {
if (parmp->args != NULL) {
delete[] parmp->args;
parmp->args = NULL;
}
parmp->name_found = 0;
}
}
// Call once to initialize the command line system
//
// cmdline - command line string passed to the application
void os_init_cmdline(int argc, char *argv[])
{
// Tests call this multiple times, so reset the params here.
// Otherwise e.g. the modlist just grows and grows...
reset_cmdline_parms();
FILE *fp;
if (!has_cmdline_only_flag(argc, argv)) {
// Only parse the config file in the current directory if we are in legacy config mode
if (os_is_legacy_mode()) {
// read the cmdline_fso.cfg file from the data folder, and pass the command line arguments to
// the the parse_parms and validate_parms line. Read these first so anything actually on
// the command line will take precedence
#ifdef APPLE_APP
#ifdef _WIN32
fp = fopen("data\\cmdline_fso.cfg", "rt");
#elif defined(APPLE_APP)
char resolved_path[MAX_PATH], data_path[MAX_PATH_LEN];
getcwd(data_path, sizeof(data_path));
GetCurrentDirectory(MAX_PATH_LEN - 1, data_path);
snprintf(resolved_path, MAX_PATH, "%s/data/cmdline_fso.cfg", data_path);
fp = fopen(resolved_path, "rt");
#else
fp = fopen("data" DIR_SEPARATOR_STR "cmdline_fso.cfg", "rt");
fp = fopen("data/cmdline_fso.cfg", "rt");
#endif
// if the file exists, get a single line, and deal with it
if (fp) {
char *buf, *p;
@@ -991,6 +961,7 @@ void os_init_cmdline(int argc, char *argv[])
if ((p = strrchr(buf, '\n')) != NULL) {
*p = '\0';
}
#ifdef SCP_UNIX
// append a space for the os_parse_parms() check
strcat_s(buf, len, " ");
@@ -1000,35 +971,35 @@ void os_init_cmdline(int argc, char *argv[])
delete[] buf;
fclose(fp);
}
} else {
// parse user specific cmdline_fso config file (will supersede options in global file)
fp = fopen(os_get_config_path("data/cmdline_fso.cfg").c_str(), "rt");
}
// if the file exists, get a single line, and deal with it
if ( fp ) {
char *buf, *p;
// parse user specific cmdline_fso config file (will supersede options in global file)
fp = fopen(os_get_config_path("data/cmdline_fso.cfg").c_str(), "rt");
auto len = static_cast<int>(filelength( fileno(fp) )) + 2;
buf = new char [len];
// if the file exists, get a single line, and deal with it
if ( fp ) {
char *buf, *p;
if (fgets(buf, len-1, fp) != nullptr)
{
// replace the newline character with a NULL
if ( (p = strrchr(buf, '\n')) != NULL ) {
*p = '\0';
}
auto len = static_cast<int>(filelength( fileno(fp) )) + 2;
buf = new char [len];
// append a space for the os_parse_parms() check
strcat_s(buf, len, " ");
os_process_cmdline(buf);
if (fgets(buf, len-1, fp) != nullptr)
{
// replace the newline character with a NULL
if ( (p = strrchr(buf, '\n')) != NULL ) {
*p = '\0';
}
delete [] buf;
fclose(fp);
// append a space for the os_parse_parms() check
strcat_s(buf, len, " ");
os_process_cmdline(buf);
}
delete [] buf;
fclose(fp);
}
} // If cmdline included PARSE_COMMAND_LINE_STRING
// By parsing cmdline last, anything actually on the command line will take precedence.
os_parse_parms(argc, argv);
os_validate_parms(argc, argv);
@@ -1156,9 +1127,6 @@ char *cmdline_parm::str()
return args;
}
bool cmdline_parm::has_param() {
return args != nullptr;
}
#ifdef SCP_UNIX
// Return a vector with all filesystem names of "parent/dir" relative to parent.
@@ -1226,8 +1194,7 @@ static void handle_unix_modlist(char **modlist, size_t *len)
for (char *cur_mod = strtok(*modlist, ","); cur_mod != NULL; cur_mod = strtok(NULL, ","))
{
SCP_vector<SCP_string> this_mod_paths = unix_get_dir_names(".", cur_mod);
// Ignore non-existing mods for unit tests
if (!running_unittests && this_mod_paths.empty()) {
if (this_mod_paths.empty()) {
ReleaseWarning(LOCATION, "Can't find mod '%s'. Ignoring.", cur_mod);
}
mod_paths.insert(mod_paths.end(), this_mod_paths.begin(), this_mod_paths.end());
@@ -1257,248 +1224,6 @@ static void handle_unix_modlist(char **modlist, size_t *len)
// external entry point into this modules
static json_t* json_get_v1() {
auto root = json_object();
{
auto version_obj = json_object();
json_object_set_new(version_obj, "full", json_string(FS_VERSION_FULL));
json_object_set_new(version_obj, "major", json_integer(FS_VERSION_MAJOR));
json_object_set_new(version_obj, "minor", json_integer(FS_VERSION_MINOR));
json_object_set_new(version_obj, "build", json_integer(FS_VERSION_BUILD));
json_object_set_new(version_obj, "has_revision", json_boolean(FS_VERSION_HAS_REVIS));
json_object_set_new(version_obj, "revision", json_integer(FS_VERSION_REVIS));
json_object_set_new(version_obj, "revision_str", json_string(FS_VERSION_REVIS_STR));
json_object_set_new(root, "version", version_obj);
}
{
auto easy_array = json_array();
for (auto& easy_flag : easy_flags) {
json_array_append_new(easy_array, json_string(easy_flag.name));
}
json_object_set_new(root, "easy_flags", easy_array);
}
{
auto flags_array = json_array();
for (auto& flag : exe_params) {
auto flag_obj = json_object();
json_object_set_new(flag_obj, "name", json_string(flag.name));
json_object_set_new(flag_obj, "description", json_string(flag.desc));
json_object_set_new(flag_obj, "fso_only", json_boolean(flag.fso_only));
json_object_set_new(flag_obj, "on_flags", json_integer(flag.on_flags));
json_object_set_new(flag_obj, "off_flags", json_integer(flag.off_flags));
json_object_set_new(flag_obj, "type", json_string(flag.type));
json_object_set_new(flag_obj, "web_url", json_string(flag.web_url));
json_array_append_new(flags_array, flag_obj);
}
json_object_set_new(root, "flags", flags_array);
}
{
auto caps_array = json_array();
json_array_append_new(caps_array, json_string("OpenAL"));
json_array_append_new(caps_array, json_string("No D3D"));
json_array_append_new(caps_array, json_string("New Sound"));
json_array_append_new(caps_array, json_string("SDL"));
json_object_set_new(root, "caps", caps_array);
}
{
auto voices_array = json_array();
auto voices = speech_enumerate_voices();
for (auto& voice : voices) {
json_array_append_new(voices_array, json_string(voice.c_str()));
}
json_object_set_new(root, "voices", voices_array);
}
{
auto resolution_array = json_array();
auto displays = gr_enumerate_displays();
for (auto& display : displays) {
auto display_obj = json_object();
json_object_set_new(display_obj, "index", json_integer(display.index));
json_object_set_new(display_obj, "name", json_string(display.name.c_str()));
json_object_set_new(display_obj, "x", json_integer(display.x));
json_object_set_new(display_obj, "y", json_integer(display.y));
json_object_set_new(display_obj, "width", json_integer(display.width));
json_object_set_new(display_obj, "height", json_integer(display.height));
auto modes_array = json_array();
for (auto& mode : display.video_modes) {
auto mode_obj = json_object();
json_object_set_new(mode_obj, "x", json_integer(mode.width));
json_object_set_new(mode_obj, "y", json_integer(mode.height));
json_object_set_new(mode_obj, "bits", json_integer(mode.bit_depth));
json_array_append_new(modes_array, mode_obj);
}
json_object_set_new(display_obj, "modes", modes_array);
json_array_append_new(resolution_array, display_obj);
}
json_object_set_new(root, "displays", resolution_array);
}
{
auto openal_obj = json_object();
auto openal_info = openal_get_platform_information();
json_object_set_new(openal_obj, "version_major", json_integer(openal_info.version_major));
json_object_set_new(openal_obj, "version_minor", json_integer(openal_info.version_minor));
json_object_set(openal_obj, "default_playback", json_string(openal_info.default_playback_device.c_str()));
json_object_set(openal_obj, "default_capture", json_string(openal_info.default_capture_device.c_str()));
{
auto playback_array = json_array();
for (auto& device : openal_info.playback_devices) {
json_array_append_new(playback_array, json_string(device.c_str()));
}
json_object_set_new(openal_obj, "playback_devices", playback_array);
}
{
auto capture_array = json_array();
for (auto& device : openal_info.capture_devices) {
json_array_append_new(capture_array, json_string(device.c_str()));
}
json_object_set_new(openal_obj, "capture_devices", capture_array);
}
json_object_set_new(root, "openal", openal_obj);
}
{
auto joystick_array = json_array();
auto joysticks = io::joystick::getJoystickInformations();
for (auto& info : joysticks) {
auto joystick_obj = json_object();
json_object_set_new(joystick_obj, "name", json_string(info.name.c_str()));
json_object_set_new(joystick_obj, "guid", json_string(info.guid.c_str()));
json_object_set_new(joystick_obj, "num_axes", json_integer(info.num_axes));
json_object_set_new(joystick_obj, "num_balls", json_integer(info.num_balls));
json_object_set_new(joystick_obj, "num_buttons", json_integer(info.num_buttons));
json_object_set_new(joystick_obj, "num_hats", json_integer(info.num_hats));
json_object_set_new(joystick_obj, "is_haptic", json_boolean(info.is_haptic));
json_array_append_new(joystick_array, joystick_obj);
}
json_object_set_new(root, "joysticks", joystick_array);
}
{
json_object_set_new(root, "pref_path", json_string(os_get_config_path().c_str()));
}
return root;
}
static void write_flags_file() {
FILE *fp = fopen("flags.lch","w");
if (fp == NULL) {
os::dialogs::Message(os::dialogs::MESSAGEBOX_ERROR, "Error creating flag list for launcher");
return;
}
int easy_flag_size = sizeof(EasyFlag);
int flag_size = sizeof(Flag);
int num_easy_flags = sizeof(easy_flags) / easy_flag_size;
int num_flags = sizeof(exe_params) / flag_size;
// Launcher will check its using structures of the same size
fwrite(&easy_flag_size, sizeof(int), 1, fp);
fwrite(&flag_size, sizeof(int), 1, fp);
fwrite(&num_easy_flags, sizeof(int), 1, fp);
fwrite(&easy_flags, sizeof(easy_flags), 1, fp);
fwrite(&num_flags, sizeof(int), 1, fp);
fwrite(&exe_params, sizeof(exe_params), 1, fp);
{
// cheap and bastardly cap check for builds
// (needs to be compatible with older Launchers, which means having
// this implies an OpenAL build for old Launchers)
ubyte build_caps = 0;
/* portej05 defined this always */
build_caps |= BUILD_CAPS_OPENAL;
build_caps |= BUILD_CAPS_NO_D3D;
build_caps |= BUILD_CAPS_NEW_SND;
build_caps |= BUILD_CAPS_SDL;
fwrite(&build_caps, 1, 1, fp);
}
fflush(fp);
fclose(fp);
}
static flag_output_type get_flags_output_type() {
Assertion(get_flags_arg.found(), "This function is only valid if -get_flags is present!");
if (!get_flags_arg.has_param()) {
// Default to binary mode
return flag_output_type::Binary;
}
SCP_string type(get_flags_arg.str());
if (type == "binary") {
return flag_output_type::Binary;
} else if (type == "json_v1") {
return flag_output_type::Json_V1;
} else {
// This is supposed to make it easy for the launcher to recognize an unsupported type
printf("OUTPUT TYPE NOT SUPPORTED!\n");
// Default to json in this case so that no flags.lch file is created
return flag_output_type::Json_V1;
}
}
static void write_flags() {
auto type = get_flags_output_type();
switch(type) {
case flag_output_type::Binary:
write_flags_file();
break;
case flag_output_type::Json_V1:
json_t* root = json_get_v1();
json_dumpf(root, stdout, JSON_INDENT(4));
json_decref(root);
break;
}
}
bool SetCmdlineParams()
// Sets externed variables used for communication cmdline information
{
@@ -1506,7 +1231,47 @@ bool SetCmdlineParams()
// DO THIS FIRST to avoid unrecognized flag warnings when just getting flag file
if ( get_flags_arg.found() ) {
write_flags();
FILE *fp = fopen("flags.lch","w");
if (fp == NULL) {
os::dialogs::Message(os::dialogs::MESSAGEBOX_ERROR, "Error creating flag list for launcher");
return false;
}
int easy_flag_size = sizeof(EasyFlag);
int flag_size = sizeof(Flag);
int num_easy_flags = sizeof(easy_flags) / easy_flag_size;
int num_flags = sizeof(exe_params) / flag_size;
// Launcher will check its using structures of the same size
fwrite(&easy_flag_size, sizeof(int), 1, fp);
fwrite(&flag_size, sizeof(int), 1, fp);
fwrite(&num_easy_flags, sizeof(int), 1, fp);
fwrite(&easy_flags, sizeof(easy_flags), 1, fp);
fwrite(&num_flags, sizeof(int), 1, fp);
fwrite(&exe_params, sizeof(exe_params), 1, fp);
{
// cheap and bastardly cap check for builds
// (needs to be compatible with older Launchers, which means having
// this implies an OpenAL build for old Launchers)
ubyte build_caps = 0;
/* portej05 defined this always */
build_caps |= BUILD_CAPS_OPENAL;
build_caps |= BUILD_CAPS_NO_D3D;
build_caps |= BUILD_CAPS_NEW_SND;
build_caps |= BUILD_CAPS_SDL;
fwrite(&build_caps, 1, 1, fp);
}
fflush(fp);
fclose(fp);
return false;
}
@@ -1759,11 +1524,6 @@ bool SetCmdlineParams()
Show_framerate = 1;
}
if (bmpmanusage_arg.found())
{
Cmdline_bmpman_usage = 1;
}
if(pos_arg.found())
{
Cmdline_show_pos = 1;
@@ -1853,7 +1613,11 @@ bool SetCmdlineParams()
if ( height_arg.found() ) {
Cmdline_height = 0;
}
if ( noglsl_arg.found() ) {
Cmdline_noglsl = 1;
}
if (fxaa_arg.found() ) {
Cmdline_fxaa = true;
@@ -1876,6 +1640,9 @@ bool SetCmdlineParams()
if ( weapon_choice_3d_arg.found() )
Cmdline_weapon_choice_3d = 1;
if ( show_mem_usage_arg.found() )
Cmdline_show_mem_usage = 1;
if (ingamejoin_arg.found() )
Cmdline_ingamejoin = 1;
@@ -1893,6 +1660,11 @@ bool SetCmdlineParams()
output_sexps("sexps.html");
}
if ( no_vbo_arg.found() )
{
Cmdline_novbo = 1;
}
if ( no_pbo_arg.found() )
{
Cmdline_no_pbo = 1;
@@ -1923,16 +1695,6 @@ bool SetCmdlineParams()
Cmdline_set_cpu_affinity = true;
}
if (nograb_arg.found())
{
Cmdline_nograb = true;
}
if (noshadercache_arg.found())
{
Cmdline_noshadercache = true;
}
if (portable_mode.found())
{
Cmdline_portable_mode = true;
@@ -1944,6 +1706,11 @@ bool SetCmdlineParams()
}
#endif
if ( snd_preload_arg.found() )
{
Cmdline_snd_preload = 1;
}
if ( env.found() ) {
Cmdline_env = 0;
}
@@ -2059,8 +1826,14 @@ bool SetCmdlineParams()
Cmdline_no_deferred_lighting = 1;
}
if (frame_profile_arg.found() )
{
Cmdline_frame_profile = true;
}
if (frame_profile_write_file.found())
{
Cmdline_frame_profile = true;
Cmdline_profile_write_file = true;
}
@@ -2079,30 +1852,6 @@ bool SetCmdlineParams()
Cmdline_noninteractive = true;
}
if (json_pilot.found())
{
Cmdline_json_pilot = true;
}
if (json_profiling.found())
{
Cmdline_json_profiling = true;
}
if (frame_profile_arg.found() )
{
Cmdline_frame_profile = true;
}
if (debug_window_arg.found()) {
Cmdline_debug_window = true;
}
if (show_video_info.found())
{
Cmdline_show_video_info = true;
}
//Deprecated flags - CommanderDJ
if( deprecated_spec_arg.found() )
{
+5 -9
View File
@@ -80,7 +80,6 @@ extern bool Cmdline_fb_thrusters;
extern bool Cmdline_no_batching;
extern int Cmdline_shadow_quality;
extern int Cmdline_no_deferred_lighting;
extern int Cmdline_no_emissive;
// Game Speed related
extern int Cmdline_cache_bitmaps;
@@ -104,6 +103,7 @@ extern int Cmdline_stretch_menu;
// Audio related
extern int Cmdline_query_speech;
extern int Cmdline_snd_preload;
extern int Cmdline_voice_recognition;
extern int Cmdline_no_enhanced_sound;
@@ -124,8 +124,10 @@ extern bool Cmdline_portable_mode;
extern int Cmdline_load_all_weapons;
extern int Cmdline_nomovies; // WMC Toggles movie playing support
extern int Cmdline_no_set_gamma;
extern int Cmdline_novbo;
extern int Cmdline_no_fbo;
extern int Cmdline_no_pbo;
extern int Cmdline_noglsl;
extern int Cmdline_mipmap;
extern int Cmdline_ati_color_swap;
extern int Cmdline_no_3d_sound;
@@ -134,8 +136,6 @@ 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;
#ifdef WIN32
extern bool Cmdline_alternate_registry_path;
#endif
@@ -147,20 +147,16 @@ extern int Cmdline_dis_collisions;
extern int Cmdline_dis_weapons;
extern int Cmdline_noparseerrors;
extern int Cmdline_extra_warn;
extern int Cmdline_bmpman_usage;
extern int Cmdline_show_mem_usage;
extern int Cmdline_show_pos;
extern int Cmdline_show_stats;
extern int Cmdline_save_render_targets;
extern int Cmdline_verify_vps;
extern int Cmdline_reparse_mainhall;
extern bool Cmdline_frame_profile;
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;
extern bool Cmdline_debug_window;
#endif
+3 -3
View File
@@ -62,7 +62,7 @@ void cmeasure_select_next(ship *shipp)
{
new_index = (shipp->current_cmeasure + i) % Num_weapon_types;
if(Weapon_info[new_index].wi_flags[Weapon::Info_Flags::Cmeasure])
if(Weapon_info[new_index].wi_flags & WIF_CMEASURE)
{
shipp->current_cmeasure = new_index;
return;
@@ -88,11 +88,11 @@ void cmeasure_maybe_alert_success(object *objp)
return;
}
Assert(Weapon_info[Weapons[objp->instance].weapon_info_index].wi_flags[Weapon::Info_Flags::Cmeasure]);
Assert(Weapon_info[Weapons[objp->instance].weapon_info_index].wi_flags & WIF_CMEASURE);
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, SND_MISSILE_EVADED_POPUP)));
snd_play(&Snds[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 );
}
+16 -16
View File
@@ -25,7 +25,7 @@
#include "missionui/missionscreencommon.h"
#include "network/multi_pmsg.h"
#include "network/multiutil.h"
#include "scripting/scripting.h"
#include "parse/scripting.h"
#include "pilotfile/pilotfile.h"
#include "popup/popup.h"
#include "ui/ui.h"
@@ -48,12 +48,12 @@
#define CONTROL_W_COORD 2
#define CONTROL_H_COORD 3
const char* Conflict_background_bitmap_fname[GR_NUM_RESOLUTIONS] = {
char* Conflict_background_bitmap_fname[GR_NUM_RESOLUTIONS] = {
"ControlConfig", // GR_640
"2_ControlConfig" // GR_1024
};
const char* Conflict_background_bitmap_mask_fname[GR_NUM_RESOLUTIONS] = {
char* Conflict_background_bitmap_mask_fname[GR_NUM_RESOLUTIONS] = {
"ControlConfig-m", // GR_640
"2_ControlConfig-m" // GR_1024
};
@@ -369,7 +369,7 @@ static int joy_get_unscaled_reading(int raw, int axn)
if (raw > rng)
raw = rng;
return (int) ((std::uint64_t) raw * (std::uint64_t) F1_0 / (std::uint64_t) rng); // convert to 0 - F1_0 range, 64bit ints used to avoid uint overflow
return (int) ((uint) raw * (uint) F1_0 / (uint) rng); // convert to 0 - F1_0 range.
}
int joy_get_scaled_reading(int raw)
@@ -919,7 +919,7 @@ int control_config_do_reset()
bool cycling_presets = false;
// If there are presets, then we'll cycle to the next preset and reset to that
if (!Control_config_presets.empty()) {
if (Control_config_presets.size() >= 1) {
cycling_presets = true;
if (++Defaults_cycle_pos >= Control_config_presets.size())
@@ -1974,7 +1974,7 @@ void control_config_do_frame(float frametime)
if (t % 2) {
gr_set_color_fast(&Color_text_normal);
gr_get_string_size(&w, NULL, XSTR( "?", 208));
gr_printf_menu(x - w / 2, y - font_height / 2, "%s", XSTR( "?", 208));
gr_printf_menu(x - w / 2, y - font_height / 2, XSTR( "?", 208));
}
} else if (!(z & JOY_AXIS) && ((Conflicts[z].key >= 0) || (Conflicts[z].joy >= 0))) {
@@ -1986,7 +1986,7 @@ void control_config_do_frame(float frametime)
gr_set_color_fast(&Color_text_normal);
str = XSTR( "Control conflicts with:", 209);
gr_get_string_size(&w, NULL, str);
gr_printf_menu(x - w / 2, y - font_height, "%s", str);
gr_printf_menu(x - w / 2, y - font_height, str);
if (Control_config[i].hasXSTR) {
strcpy_s(buf, XSTR(Control_config[i].text, CONTROL_CONFIG_XSTR + i));
@@ -1996,12 +1996,12 @@ void control_config_do_frame(float frametime)
font::force_fit_string(buf, 255, Conflict_wnd_coords[gr_screen.res][CONTROL_W_COORD]);
gr_get_string_size(&w, NULL, buf);
gr_printf_menu(x - w / 2, y, "%s", buf);
gr_printf_menu(x - w / 2, y, buf);
} else if (*bound_string) {
gr_set_color_fast(&Color_text_normal);
gr_get_string_size(&w, NULL, bound_string);
gr_printf_menu(x - w / 2, y - font_height / 2, "%s", bound_string);
gr_printf_menu(x - w / 2, y - font_height / 2, bound_string);
if (timestamp_elapsed(bound_timestamp)) {
*bound_string = 0;
}
@@ -2009,7 +2009,7 @@ void control_config_do_frame(float frametime)
if (Cc_lines[Num_cc_lines - 1].y + font_height > Cc_lines[Scroll_offset].y + Control_list_coords[gr_screen.res][CONTROL_H_COORD]) {
gr_set_color_fast(&Color_white);
gr_printf_menu(Control_more_coords[gr_screen.res][CONTROL_X_COORD], Control_more_coords[gr_screen.res][CONTROL_Y_COORD], "%s", XSTR( "More...", 210));
gr_printf_menu(Control_more_coords[gr_screen.res][CONTROL_X_COORD], Control_more_coords[gr_screen.res][CONTROL_Y_COORD], XSTR( "More...", 210));
}
conflict = 0;
@@ -2035,7 +2035,7 @@ void control_config_do_frame(float frametime)
if (Cc_lines[line].label) {
strcpy_s(buf, Cc_lines[line].label);
font::force_fit_string(buf, 255, Control_list_ctrl_w[gr_screen.res]);
gr_printf_menu(Control_list_coords[gr_screen.res][CONTROL_X_COORD], y, "%s", buf);
gr_printf_menu(Control_list_coords[gr_screen.res][CONTROL_X_COORD], y, buf);
}
if (!(z & JOY_AXIS)) {
@@ -2046,7 +2046,7 @@ void control_config_do_frame(float frametime)
if ((k < 0) && (j < 0)) {
gr_set_color_fast(&Color_grey);
gr_printf_menu(x, y, "%s", XSTR( "None", 211));
gr_printf_menu(x, y, XSTR( "None", 211));
} else {
if (k >= 0) {
@@ -2066,7 +2066,7 @@ void control_config_do_frame(float frametime)
gr_set_color_fast(c);
}
gr_printf_menu(x, y, "%s", buf);
gr_printf_menu(x, y, buf);
Cc_lines[line].kx = x - Control_list_coords[gr_screen.res][CONTROL_X_COORD];
gr_get_string_size(&w, NULL, buf);
@@ -2075,7 +2075,7 @@ void control_config_do_frame(float frametime)
if (j >= 0) {
gr_set_color_fast(&Color_text_normal);
gr_printf_menu(x, y, "%s", XSTR( ", ", 212));
gr_printf_menu(x, y, XSTR( ", ", 212));
gr_get_string_size(&w, NULL, XSTR( ", ", 212));
x += w;
}
@@ -2099,7 +2099,7 @@ void control_config_do_frame(float frametime)
}
font::force_fit_string(buf, 255, Control_list_key_w[gr_screen.res] + Control_list_key_x[gr_screen.res] - x);
gr_printf_menu(x, y, "%s", buf);
gr_printf_menu(x, y, buf);
Cc_lines[line].jx = x - Control_list_coords[gr_screen.res][CONTROL_X_COORD];
gr_get_string_size(&Cc_lines[line].jw, NULL, buf);
@@ -2115,7 +2115,7 @@ void control_config_do_frame(float frametime)
if (j < 0) {
gr_set_color_fast(&Color_grey);
gr_printf_menu(x, y, "%s", XSTR( "None", 211));
gr_printf_menu(x, y, XSTR( "None", 211));
} else {
if (Conflicts_axes[z & ~JOY_AXIS] >= 0) {
+4 -23
View File
@@ -63,7 +63,7 @@ typedef struct config_item {
short joy_default; //!< default joystick button bound to action
char tab; //!< what tab (category) it belongs in
bool hasXSTR; //!< whether we should translate this with an XSTR
const char *text; //!< describes the action in the config screen
char *text; //!< describes the action in the config screen
char type; //!< manner control should be checked in
short key_id; //!< actual key bound to action
short joy_id; //!< joystick button bound to action
@@ -296,8 +296,8 @@ extern int Control_config_overlay_id;
extern config_item Control_config[]; //!< Stores the keyboard configuration
extern SCP_vector<config_item*> Control_config_presets; // tabled control presets; pointers to config_item arrays
extern SCP_vector<SCP_string> Control_config_preset_names; // names for Control_config_presets (identical order of items)
extern const char **Scan_code_text;
extern const char **Joy_button_text;
extern char **Scan_code_text;
extern char **Joy_button_text;
void control_config_common_init(); //!< initialize common control config stuff - call at game startup after localization has been initialized
void control_config_common_close(); //!< close common control config stuff - call at game shutdown
@@ -311,26 +311,7 @@ void control_config_cancel_exit();
void control_config_reset_defaults(int presetnum=-1);
int translate_key_to_index(const char *key, bool find_override=true);
char *translate_key(char *key);
/**
* @brief Converts the specified key code to a human readable string
*
* @note The returned value is localized to the current language
*
* @param code The key code to convert
* @return The text representation of the code. The returned value is stored in a temporary location, copy it to your
* own buffer if you want to continue using it.
*/
const char *textify_scancode(int code);
/**
* @note Same as textify_scancode but always returns the same value regardless of current language
* @param code The key code to convert
* @return The name of the key
* @see textify_scancode
*/
const char *textify_scancode_universal(int code);
char *textify_scancode(int code);
float check_control_timef(int id);
int check_control(int id, int key = -1);
void control_get_axes_readings(int *h, int *p, int *b, int *ta, int *tr);
+109 -138
View File
@@ -199,7 +199,7 @@ config_item Control_config[CCFG_MAX + 1] = {
{ -1, -1, -1, false, "", CC_TYPE_TRIGGER, -1, -1, 0, false, false }
};
const char *Scan_code_text_german[] = {
char *Scan_code_text_german[] = {
"", "Esc", "1", "2", "3", "4", "5", "6",
"7", "8", "9", "0", "Akzent '", "Eszett", "R\x81""cktaste", "Tab",
"Q", "W", "E", "R", "T", "Z", "U", "I",
@@ -241,7 +241,7 @@ const char *Scan_code_text_german[] = {
"", "", "", "", "", "", "", "",
};
const char *Joy_button_text_german[] = {
char *Joy_button_text_german[] = {
"Knopf 1", "Knopf 2", "Knopf 3", "Knopf 4", "Knopf 5", "Knopf 6",
"Knopf 7", "Knopf 8", "Knopf 9", "Knopf 10", "Knopf 11", "Knopf 12",
"Knopf 13", "Knopf 14", "Knopf 15", "Knopf 16", "Knopf 17", "Knopf 18",
@@ -250,7 +250,7 @@ const char *Joy_button_text_german[] = {
"Knopf 31", "Knopf 32", "Hut Hinten", "Hut Vorne", "Hut Links", "Hut Rechts"
};
const char *Scan_code_text_french[] = {
char *Scan_code_text_french[] = {
"", "\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",
@@ -292,7 +292,7 @@ const char *Scan_code_text_french[] = {
"", "", "", "", "", "", "", "",
};
const char *Joy_button_text_french[] = {
char *Joy_button_text_french[] = {
"Bouton 1", "Bouton 2", "Bouton 3", "Bouton 4", "Bouton 5", "Bouton 6",
"Bouton 7", "Bouton 8", "Bouton 9", "Bouton 10", "Bouton 11", "Bouton 12",
"Bouton 13", "Bouton 14", "Bouton 15", "Bouton 16", "Bouton 17", "Bouton 18",
@@ -301,7 +301,7 @@ const char *Joy_button_text_french[] = {
"Bouton 31", "Bouton 32", "Chapeau Arri\x8Are", "Chapeau Avant", "Chapeau Gauche", "Chapeau Droite"
};
const char *Scan_code_text_polish[] = {
char *Scan_code_text_polish[] = {
"", "Esc", "1", "2", "3", "4", "5", "6",
"7", "8", "9", "0", "-", "=", "Backspace", "Tab",
"Q", "W", "E", "R", "T", "Y", "U", "I",
@@ -343,7 +343,7 @@ const char *Scan_code_text_polish[] = {
"", "", "", "", "", "", "", "",
};
const char *Joy_button_text_polish[] = {
char *Joy_button_text_polish[] = {
"Przyc.1", "Przyc.2", "Przyc.3", "Przyc.4", "Przyc.5", "Przyc.6",
"Przyc.7", "Przyc.8", "Przyc.9", "Przyc.10", "Przyc.11", "Przyc.12",
"Przyc.13", "Przyc.14", "Przyc.15", "Przyc.16", "Przyc.17", "Przyc.18",
@@ -353,7 +353,7 @@ const char *Joy_button_text_polish[] = {
};
//! This is the text that is displayed on the screen for the keys a player selects
const char *Scan_code_text_english[] = {
char *Scan_code_text_english[] = {
"", "Esc", "1", "2", "3", "4", "5", "6",
"7", "8", "9", "0", "-", "=", "Backspace", "Tab",
"Q", "W", "E", "R", "T", "Y", "U", "I",
@@ -395,7 +395,7 @@ const char *Scan_code_text_english[] = {
"", "", "", "", "", "", "", "",
};
const char *Joy_button_text_english[] = {
char *Joy_button_text_english[] = {
"Button 1", "Button 2", "Button 3", "Button 4", "Button 5", "Button 6",
"Button 7", "Button 8", "Button 9", "Button 10", "Button 11", "Button 12",
"Button 13", "Button 14", "Button 15", "Button 16", "Button 17", "Button 18",
@@ -404,8 +404,8 @@ const char *Joy_button_text_english[] = {
"Button 31", "Button 32", "Hat Back", "Hat Forward", "Hat Left", "Hat Right"
};
const char **Scan_code_text = Scan_code_text_english;
const char **Joy_button_text = Joy_button_text_english;
char **Scan_code_text = Scan_code_text_english;
char **Joy_button_text = Joy_button_text_english;
SCP_vector<config_item*> Control_config_presets;
SCP_vector<SCP_string> Control_config_preset_names;
@@ -510,8 +510,8 @@ int translate_key_to_index(const char *key, bool find_override)
char *translate_key(char *key)
{
int index = -1, key_code = -1, joy_code = -1;
const char *key_text = NULL;
const char *joy_text = NULL;
char *key_text = NULL;
char *joy_text = NULL;
static char text[40] = {"None"};
@@ -553,7 +553,7 @@ char *translate_key(char *key)
return text;
}
const char *textify_scancode(int code)
char *textify_scancode(int code)
{
static char text[40];
@@ -586,28 +586,6 @@ const char *textify_scancode(int code)
strcat_s(text, Scan_code_text[keycode]);
return text;
}
const char *textify_scancode_universal(int code)
{
if (code < 0)
return "None";
int keycode = code & KEY_MASK;
static char text[40];
*text = 0;
if (code & KEY_ALTED && !(keycode == KEY_LALT || keycode == KEY_RALT)) {
strcat_s(text, "Alt-");
}
if (code & KEY_SHIFTED && !(keycode == KEY_LSHIFT || keycode == KEY_RSHIFT)) {
strcat_s(text, "Shift-");
}
// Always use the english version here
strcat_s(text, Scan_code_text_english[keycode]);
return text;
}
//XSTR:ON
void control_config_common_load_overrides();
@@ -833,125 +811,118 @@ void control_config_common_load_overrides()
{
LoadEnumsIntoMaps();
try {
if (cf_exists_full("controlconfigdefaults.tbl", CF_TYPE_TABLES)) {
read_file_text("controlconfigdefaults.tbl", CF_TYPE_TABLES);
if (cf_exists_full("controlconfigdefaults.tbl", CF_TYPE_TABLES)) {
read_file_text("controlconfigdefaults.tbl", CF_TYPE_TABLES);
} else {
read_file_text_from_default(defaults_get_file("controlconfigdefaults.tbl"));
}
reset_parse();
// start parsing
// TODO: Split this out into more helps. Too many tabs!
while(optional_string("#ControlConfigOverride")) {
config_item *cfg_preset = new config_item[CCFG_MAX + 1];
std::copy(Control_config, Control_config + CCFG_MAX + 1, cfg_preset);
Control_config_presets.push_back(cfg_preset);
SCP_string preset_name;
if (optional_string("$Name:")) {
stuff_string_line(preset_name);
} else {
read_file_text_from_default(defaults_get_file("controlconfigdefaults.tbl"));
preset_name = "<unnamed preset>";
}
Control_config_preset_names.push_back(preset_name);
reset_parse();
while (required_string_either("#End","$Bind Name:")) {
const int iBufferLength = 64;
char szTempBuffer[iBufferLength];
// start parsing
// TODO: Split this out into more helps. Too many tabs!
while(optional_string("#ControlConfigOverride")) {
config_item *cfg_preset = new config_item[CCFG_MAX + 1];
std::copy(Control_config, Control_config + CCFG_MAX + 1, cfg_preset);
Control_config_presets.push_back(cfg_preset);
required_string("$Bind Name:");
stuff_string(szTempBuffer, F_NAME, iBufferLength);
SCP_string preset_name;
if (optional_string("$Name:")) {
stuff_string_line(preset_name);
} else {
preset_name = "<unnamed preset>";
}
Control_config_preset_names.push_back(preset_name);
const size_t cCntrlAryLength = sizeof(Control_config) / sizeof(Control_config[0]);
for (size_t i = 0; i < cCntrlAryLength; ++i) {
config_item& r_ccConfig = cfg_preset[i];
while (required_string_either("#End","$Bind Name:")) {
const int iBufferLength = 64;
char szTempBuffer[iBufferLength];
if (!strcmp(szTempBuffer, r_ccConfig.text)) {
/**
* short key_default;
* short joy_default;
* char tab;
* bool hasXSTR;
* char type;
*/
required_string("$Bind Name:");
stuff_string(szTempBuffer, F_NAME, iBufferLength);
int iTemp;
const size_t cCntrlAryLength = sizeof(Control_config) / sizeof(Control_config[0]);
for (size_t i = 0; i < cCntrlAryLength; ++i) {
config_item& r_ccConfig = cfg_preset[i];
if (!strcmp(szTempBuffer, r_ccConfig.text)) {
/**
* short key_default;
* short joy_default;
* char tab;
* bool hasXSTR;
* char type;
*/
int iTemp;
if (optional_string("$Key Default:")) {
if (optional_string("NONE")) {
r_ccConfig.key_default = (short)-1;
} else {
stuff_string(szTempBuffer, F_NAME, iBufferLength);
r_ccConfig.key_default = (short)mKeyNameToVal[szTempBuffer];
}
}
if (optional_string("$Joy Default:")) {
stuff_int(&iTemp);
r_ccConfig.joy_default = (short)iTemp;
}
if (optional_string("$Key Mod Shift:")) {
stuff_int(&iTemp);
r_ccConfig.key_default |= (iTemp == 1) ? KEY_SHIFTED : 0;
}
if (optional_string("$Key Mod Alt:")) {
stuff_int(&iTemp);
r_ccConfig.key_default |= (iTemp == 1) ? KEY_ALTED : 0;
}
if (optional_string("$Key Mod Ctrl:")) {
stuff_int(&iTemp);
r_ccConfig.key_default |= (iTemp == 1) ? KEY_CTRLED : 0;
}
if (optional_string("$Category:")) {
if (optional_string("$Key Default:")) {
if (optional_string("NONE")) {
r_ccConfig.key_default = (short)-1;
} else {
stuff_string(szTempBuffer, F_NAME, iBufferLength);
r_ccConfig.tab = (char)mCCTabNameToVal[szTempBuffer];
r_ccConfig.key_default = (short)mKeyNameToVal[szTempBuffer];
}
if (optional_string("$Has XStr:")) {
stuff_int(&iTemp);
r_ccConfig.hasXSTR = (iTemp == 1);
}
if (optional_string("$Type:")) {
stuff_string(szTempBuffer, F_NAME, iBufferLength);
r_ccConfig.type = (char)mCCTypeNameToVal[szTempBuffer];
}
if (optional_string("+Disable")) {
r_ccConfig.disabled = true;
}
if (optional_string("$Disable:")) {
stuff_boolean(&r_ccConfig.disabled);
}
// Nerf the buffer now.
szTempBuffer[0] = '\0';
} else if ((i + 1) == cCntrlAryLength) {
error_display(1, "Bind Name not found: %s\n", szTempBuffer);
advance_to_eoln(NULL);
ignore_white_space();
return;
}
if (optional_string("$Joy Default:")) {
stuff_int(&iTemp);
r_ccConfig.joy_default = (short)iTemp;
}
if (optional_string("$Key Mod Shift:")) {
stuff_int(&iTemp);
r_ccConfig.key_default |= (iTemp == 1) ? KEY_SHIFTED : 0;
}
if (optional_string("$Key Mod Alt:")) {
stuff_int(&iTemp);
r_ccConfig.key_default |= (iTemp == 1) ? KEY_ALTED : 0;
}
if (optional_string("$Key Mod Ctrl:")) {
stuff_int(&iTemp);
r_ccConfig.key_default |= (iTemp == 1) ? KEY_CTRLED : 0;
}
if (optional_string("$Category:")) {
stuff_string(szTempBuffer, F_NAME, iBufferLength);
r_ccConfig.tab = (char)mCCTabNameToVal[szTempBuffer];
}
if (optional_string("$Has XStr:")) {
stuff_int(&iTemp);
r_ccConfig.hasXSTR = (iTemp == 1);
}
if (optional_string("$Type:")) {
stuff_string(szTempBuffer, F_NAME, iBufferLength);
r_ccConfig.type = (char)mCCTypeNameToVal[szTempBuffer];
}
if (optional_string("+Disable")) {
r_ccConfig.disabled = true;
}
if (optional_string("$Disable:")) {
stuff_boolean(&r_ccConfig.disabled);
}
// Nerf the buffer now.
szTempBuffer[0] = '\0';
} else if ((i + 1) == cCntrlAryLength) {
error_display(1, "Bind Name not found: %s\n", szTempBuffer);
advance_to_eoln(NULL);
ignore_white_space();
return;
}
}
required_string("#End");
}
}
catch (const parse::ParseException& e)
{
mprintf(("TABLES: Unable to parse 'controlconfigdefaults.tbl'! Error message = %s.\n", e.what()));
return;
}
required_string("#End");
}
// Overwrite the control config with the first preset that was found
if (!Control_config_presets.empty()) {
if (Control_config_presets.size() > 0) {
std::copy(Control_config_presets[0], Control_config_presets[0] + CCFG_MAX + 1, Control_config);
}
}
-86
View File
@@ -1,86 +0,0 @@
#include "cutscene/Decoder.h"
#include <memory>
namespace cutscene {
Decoder::Decoder() : m_decoding(true) {
}
Decoder::~Decoder() {
}
bool Decoder::tryPopAudioData(AudioFramePtr& out) {
auto res = m_audioQueue->try_pull_front(out);
return res == queue_op_status::success;
}
bool Decoder::tryPopSubtitleData(SubtitleFramePtr& out) {
auto res = m_subtitleQueue->try_pull_front(out);
return res == queue_op_status::success;
}
bool Decoder::tryPopVideoFrame(VideoFramePtr& out) {
auto res = m_videoQueue->try_pull_front(out);
return res == queue_op_status::success;
}
void Decoder::initializeQueues(size_t queueSize) {
m_queueSize = queueSize;
m_videoQueue.reset(new sync_bounded_queue<VideoFramePtr>(m_queueSize));
m_audioQueue.reset(new sync_bounded_queue<AudioFramePtr>(m_queueSize));
m_subtitleQueue.reset(new sync_bounded_queue<SubtitleFramePtr>(m_queueSize));
}
void Decoder::stopDecoder() {
m_decoding = false;
m_videoQueue->close();
m_audioQueue->close();
m_subtitleQueue->close();
}
bool Decoder::canPushAudioData() {
return !isAudioQueueFull();
}
void Decoder::pushAudioData(AudioFramePtr&& data) {
Assertion(data, "Invalid audio data passed!");
try {
m_audioQueue->push_back(std::move(data));
}
catch (sync_queue_is_closed&) {
// Ignore
}
}
bool Decoder::canPushSubtitleData() {
return !isSubtitleQueueFull();
}
void Decoder::pushSubtitleData(SubtitleFramePtr&& data) {
Assertion(data, "Invalid audio data passed!");
try {
m_subtitleQueue->push_back(std::move(data));
}
catch (sync_queue_is_closed&) {
// Ignore
}
}
bool Decoder::canPushVideoData() {
return !isVideoQueueFull();
}
void Decoder::pushFrameData(VideoFramePtr&& frame) {
Assertion(frame, "Invalid video data passed!");
try {
m_videoQueue->push_back(std::move(frame));
}
catch (sync_queue_is_closed&) {
// Ignore
}
}
}
-171
View File
@@ -1,171 +0,0 @@
#pragma once
#include <memory>
#include "globalincs/pstypes.h"
#include "utils/boost/syncboundedqueue.h"
namespace cutscene {
struct FrameSize {
size_t width = 0;
size_t height = 0;
size_t stride = 0;
};
class VideoFrame {
protected:
VideoFrame() {}
public:
virtual ~VideoFrame() {}
double frameTime = -1.0;
int id = -1;
FrameSize ySize;
FrameSize uvSize;
struct DataPointers {
ubyte* y;
ubyte* u;
ubyte* v;
};
virtual DataPointers getDataPointers() = 0;
};
/**
* @brief Pointer type for passing frame data between threads
*
*/
template<typename T>
using FramePtr = std::unique_ptr<T>;
typedef std::unique_ptr<VideoFrame> VideoFramePtr;
struct MovieProperties {
FrameSize size;
float fps = -1.0f;
};
struct AudioFrame {
SCP_vector<short> audioData;
int channels = -1;
int rate = -1;
};
typedef std::unique_ptr<AudioFrame> AudioFramePtr;
struct SubtitleFrame {
double displayStartTime = -1.0;
double displayEndTime = -1.0;
SCP_string text;
};
typedef std::unique_ptr<SubtitleFrame> SubtitleFramePtr;
/**
* @brief Abstract class for decoding a video or audio stream
*
* A decoder maintaines two queues of decoded audio and video frames which are filled from a background thread and
* retrieved by the main thread.
*/
class Decoder {
private:
std::unique_ptr<sync_bounded_queue<VideoFramePtr>> m_videoQueue;
std::unique_ptr<sync_bounded_queue<AudioFramePtr>> m_audioQueue;
std::unique_ptr<sync_bounded_queue<SubtitleFramePtr>> m_subtitleQueue;
bool m_decoding;
size_t m_queueSize = 0;
Decoder(const Decoder&) SCP_DELETED_FUNCTION;
Decoder& operator=(const Decoder&) SCP_DELETED_FUNCTION;
protected:
Decoder();
public:
virtual ~Decoder();
/**
* @brief Initializes the decoder
*
* @note A implementation should initialize the datastructures required for decoding here.
*
* @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) = 0;
/**
* @brief Returns the properties of the video
* @return The properties
*/
virtual MovieProperties getProperties() = 0;
/**
* @brief Starts decoding the video
*/
virtual void startDecoding() = 0;
/**
* @brief Determines if the video has audio
* @return @c true if audio is included in the video
*/
virtual bool hasAudio() = 0;
virtual bool hasSubtitles() = 0;
/**
* @brief Ends decoding of the video file
*/
virtual void close() = 0;
bool isAudioQueueFull() { return m_audioQueue->size() == m_queueSize; }
bool isAudioFrameAvailable() { return !m_audioQueue->empty(); }
size_t getAudioQueueSize() { return m_audioQueue->size(); }
bool tryPopAudioData(AudioFramePtr&);
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; }
bool isVideoFrameAvailable() { return !m_videoQueue->empty(); }
size_t getVideoQueueSize() { return m_videoQueue->size(); }
bool tryPopVideoFrame(VideoFramePtr&);
void stopDecoder();
bool isDecoding() { return m_decoding; }
protected:
void initializeQueues(size_t queueSize);
bool canPushAudioData();
void pushAudioData(AudioFramePtr&& data);
bool canPushSubtitleData();
void pushSubtitleData(SubtitleFramePtr&& data);
bool canPushVideoData();
void pushFrameData(VideoFramePtr&& frame);
};
}
-95
View File
@@ -1,95 +0,0 @@
#include "VideoPresenter.h"
#include "graphics/matrix.h"
using namespace cutscene;
using namespace cutscene::player;
namespace {
struct movie_vertex {
vec2d pos;
vec2d uv;
};
}
namespace cutscene {
namespace player {
VideoPresenter::VideoPresenter(const MovieProperties& props) {
GR_DEBUG_SCOPE("Init video");
auto w = static_cast<int>(props.size.width);
auto h = static_cast<int>(props.size.height);
// Create buffer textures
_yTexBuffer.reset(new uint8_t[w * h]);
_ytex = bm_create(8, w, h, _yTexBuffer.get(), BMP_AABITMAP);
_uTexBuffer.reset(new uint8_t[w / 2 * h / 2]);
_utex = bm_create(8, w / 2, h / 2, _uTexBuffer.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(&_render_material, _ytex, _utex, _vtex);
}
VideoPresenter::~VideoPresenter() {
GR_DEBUG_SCOPE("Deinit video");
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();
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);
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) {
GR_DEBUG_SCOPE("Draw video frame");
movie_vertex vertex_data[4];
vertex_data[0].pos.x = x1;
vertex_data[0].pos.y = y1;
vertex_data[0].uv.x = 0.0f;
vertex_data[0].uv.y = 0.0f;
vertex_data[1].pos.x = x1;
vertex_data[1].pos.y = y2;
vertex_data[1].uv.x = 0.0f;
vertex_data[1].uv.y = 1.0f;
vertex_data[2].pos.x = x2;
vertex_data[2].pos.y = y1;
vertex_data[2].uv.x = 1.0f;
vertex_data[2].uv.y = 0.0f;
vertex_data[3].pos.x = x2;
vertex_data[3].pos.y = y2;
vertex_data[3].uv.x = 1.0f;
vertex_data[3].uv.y = 1.0f;
// Use the immediate buffer for storing our data since that is exactly what we need
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]), offset + offsetof(movie_vertex, pos));
layout.add_vertex_component(vertex_format_data::TEX_COORD2, sizeof(vertex_data[0]), offset + offsetof(movie_vertex, uv));
gr_render_movie(&_render_material, PRIM_TYPE_TRISTRIP, &layout, 4, gr_immediate_buffer_handle);
}
}
}
-42
View File
@@ -1,42 +0,0 @@
#ifndef FS2_OPEN_OPENGLVIDEOPRESENTER_H
#define FS2_OPEN_OPENGLVIDEOPRESENTER_H
#include "globalincs/pstypes.h"
#include "graphics/2d.h"
#include "graphics/material.h"
#include "cutscene/Decoder.h"
#include <memory>
namespace cutscene {
namespace player {
class VideoPresenter {
int _ytex = -1;
std::unique_ptr<uint8_t[]> _yTexBuffer;
int _utex = -1;
std::unique_ptr<uint8_t[]> _uTexBuffer;
int _vtex = -1;
std::unique_ptr<uint8_t[]> _vTexBuffer;
movie_material _render_material;
public:
explicit VideoPresenter(const MovieProperties& props);
// Disallow copying
VideoPresenter(const VideoPresenter&) = delete;
VideoPresenter& operator=(const VideoPresenter&) = delete;
virtual ~VideoPresenter();
void uploadVideoFrame(const VideoFramePtr& frame);
void displayFrame(float x1, float y1, float x2, float y2);
};
}
}
#endif //FS2_OPEN_OPENGLVIDEOPRESENTER_H
+215 -197
View File
@@ -5,7 +5,7 @@
* or otherwise commercially exploit the source or things you created based on the
* source.
*
*/
*/
@@ -26,13 +26,13 @@
extern int Cmdline_nomovies;
const char* Cutscene_bitmap_name[GR_NUM_RESOLUTIONS] = {
"ViewFootage",
"2_ViewFootage"
char *Cutscene_bitmap_name[GR_NUM_RESOLUTIONS] = {
"ViewFootage",
"2_ViewFootage"
};
const char* Cutscene_mask_name[GR_NUM_RESOLUTIONS] = {
"ViewFootage-m",
"2_ViewFootage-m"
char *Cutscene_mask_name[GR_NUM_RESOLUTIONS] = {
"ViewFootage-m",
"2_ViewFootage-m"
};
int Description_index;
@@ -40,9 +40,8 @@ SCP_vector<cutscene_info> Cutscenes;
void cutscene_close()
{
for (SCP_vector<cutscene_info>::iterator cut = Cutscenes.begin(); cut != Cutscenes.end(); ++cut)
if (cut->description != NULL)
{
for(SCP_vector<cutscene_info>::iterator cut = Cutscenes.begin(); cut != Cutscenes.end(); ++cut)
if(cut->description != NULL) {
vm_free(cut->description);
cut->description = NULL;
}
@@ -82,24 +81,19 @@ void cutscene_init()
cutinfo.description = vm_strdup(buf);
if (optional_string("$cd:"))
{
// Option isn't needed anymore. Consume the token and ignore it
int junk;
stuff_int(&junk);
}
stuff_int(&cutinfo.cd);
else
cutinfo.cd = 0;
cutinfo.viewable = false;
if (isFirstCutscene)
{
if (isFirstCutscene) {
isFirstCutscene = false;
// The original code assumes the first movie is the intro, so always viewable
cutinfo.viewable = true;
}
if (optional_string("$Always Viewable:"))
{
if (optional_string("$Always Viewable:")) {
stuff_boolean(&cutinfo.viewable);
}
@@ -115,34 +109,44 @@ void cutscene_init()
}
}
// function to return 0 based index of which CD a particular movie is on
// returns -1 on failure.
int cutscenes_get_cd_num( char *filename )
{
for (SCP_vector<cutscene_info>::iterator cut = Cutscenes.begin(); cut != Cutscenes.end(); ++cut) {
if ( !stricmp(cut->filename, filename) ) {
return (cut->cd - 1);
}
}
return -1;
}
// marks a cutscene as viewable
void cutscene_mark_viewable(const char* filename)
void cutscene_mark_viewable(char *filename)
{
char cut_file[MAX_FILENAME_LEN];
char file[MAX_FILENAME_LEN];
Assert(filename != NULL);
Assert(filename!=NULL);
// strip off extension
strcpy_s(file, filename);
char* p = strchr(file, '.');
if (p)
{
strcpy_s( file, filename );
char *p = strchr( file, '.' );
if ( p ) {
*p = 0;
}
// change to lower case
strlwr(file);
int i = 0;
for (SCP_vector<cutscene_info>::iterator cut = Cutscenes.begin(); cut != Cutscenes.end(); ++cut)
{
for (SCP_vector<cutscene_info>::iterator cut = Cutscenes.begin(); cut != Cutscenes.end(); ++cut) {
// change the cutscene file name to lower case
strcpy_s(cut_file, cut->filename);
strlwr(cut_file);
// see if the stripped filename matches the cutscene filename
if (strstr(cut_file, file) != NULL)
{
if ( strstr(cut_file, file) != NULL ) {
cut->viewable = true;
return;
}
@@ -152,17 +156,17 @@ void cutscene_mark_viewable(const char* filename)
Warning(LOCATION, "Could not find cutscene '%s' in listing; cannot mark it viewable...", filename);
}
#define NUM_BUTTONS 8
#define NUM_BUTTONS 8
#define TECH_DATABASE_BUTTON 0
#define SIMULATOR_BUTTON 1
#define CUTSCENES_BUTTON 2
#define CREDITS_BUTTON 3
#define TECH_DATABASE_BUTTON 0
#define SIMULATOR_BUTTON 1
#define CUTSCENES_BUTTON 2
#define CREDITS_BUTTON 3
#define SCROLL_UP_BUTTON 4
#define SCROLL_DOWN_BUTTON 5
#define PLAY_BUTTON 6
#define EXIT_BUTTON 7
#define SCROLL_UP_BUTTON 4
#define SCROLL_DOWN_BUTTON 5
#define PLAY_BUTTON 6
#define EXIT_BUTTON 7
static SCP_vector<int> Cutscene_list;
//static int Stats_scroll_offset; // not used - taylor
@@ -173,102 +177,155 @@ static UI_BUTTON List_region;
static UI_WINDOW Ui_window;
static ui_button_info Buttons[GR_NUM_RESOLUTIONS][NUM_BUTTONS] = {
{ // GR_640
ui_button_info("TDB_00", 7, 3, 37, 7, 0), // tech database 1
ui_button_info("TDB_01", 7, 18, 37, 23, 1), // tech database 2
ui_button_info("TDB_02", 7, 34, 37, 38, 2), // tech database 3
ui_button_info("TDB_03", 7, 49, 37, 54, 3), // tech database 4
{ // GR_640
ui_button_info("TDB_00", 7, 3, 37, 7, 0), // tech database 1
ui_button_info("TDB_01", 7, 18, 37, 23, 1), // tech database 2
ui_button_info("TDB_02", 7, 34, 37, 38, 2), // tech database 3
ui_button_info("TDB_03", 7, 49, 37, 54, 3), // tech database 4
ui_button_info("VFB_04", 6, 318, -1, -1, 4), // scroll up
ui_button_info("VFB_05", 36, 318, -1, -1, 5), // scroll down
ui_button_info("VFB_06", 578, 319, 587, 366, 6), // play
ui_button_info("VFB_07", 574, 431, 587, 413, 7), // exit
},
{ // GR_1024
ui_button_info("2_TDB_00", 12, 5, 59, 12, 0), // tech database 1
ui_button_info("2_TDB_01", 12, 31, 59, 37, 1), // tech database 2
ui_button_info("2_TDB_02", 12, 56, 59, 62, 2), // tech database 3
ui_button_info("2_TDB_03", 12, 81, 59, 88, 3), // tech database 4
ui_button_info("VFB_04", 6, 318, -1, -1, 4), // scroll up
ui_button_info("VFB_05", 36, 318, -1, -1, 5), // scroll down
ui_button_info("VFB_06", 578, 319, 587, 366, 6), // play
ui_button_info("VFB_07", 574, 431, 587, 413, 7), // exit
},
{ // GR_1024
ui_button_info("2_TDB_00", 12, 5, 59, 12, 0), // tech database 1
ui_button_info("2_TDB_01", 12, 31, 59, 37, 1), // tech database 2
ui_button_info("2_TDB_02", 12, 56, 59, 62, 2), // tech database 3
ui_button_info("2_TDB_03", 12, 81, 59, 88, 3), // tech database 4
ui_button_info("2_VFB_04", 9, 509, -1, -1, 4), // scroll up
ui_button_info("2_VFB_05", 58, 509, -1, -1, 5), // scroll down
ui_button_info("2_VFB_06", 925, 511, 940, 586, 6), // play
ui_button_info("2_VFB_07", 918, 689, 940, 661, 7), // exit
}
ui_button_info("2_VFB_04", 9, 509, -1, -1, 4), // scroll up
ui_button_info("2_VFB_05", 58, 509, -1, -1, 5), // scroll down
ui_button_info("2_VFB_06", 925, 511, 940, 586, 6), // play
ui_button_info("2_VFB_07", 918, 689, 940, 661, 7), // exit
}
};
// text
#define NUM_CUTSCENE_TEXT 6
#define NUM_CUTSCENE_TEXT 6
UI_XSTR Cutscene_text[GR_NUM_RESOLUTIONS][NUM_CUTSCENE_TEXT] = {
{ // GR_640
{"Technical Database", 1055, 37, 7, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][TECH_DATABASE_BUTTON].button},
{"Mission Simulator", 1056, 37, 23, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][SIMULATOR_BUTTON].button},
{"Cutscenes", 1057, 37, 38, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][CUTSCENES_BUTTON].button},
{"Credits", 1058, 37, 54, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][CREDITS_BUTTON].button},
{"Play", 1335, 587, 366, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][PLAY_BUTTON].button},
{"Exit", 1419, 587, 413, UI_XSTR_COLOR_PINK, -1, &Buttons[0][EXIT_BUTTON].button},
},
{ // GR_1024
{"Technical Database", 1055, 59, 12, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][TECH_DATABASE_BUTTON].button},
{"Mission Simulator", 1056, 59, 37, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][SIMULATOR_BUTTON].button},
{"Cutscenes", 1057, 59, 62, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][CUTSCENES_BUTTON].button},
{"Credits", 1058, 59, 88, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][CREDITS_BUTTON].button},
{"Play", 1335, 940, 586, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][PLAY_BUTTON].button},
{"Exit", 1419, 940, 661, UI_XSTR_COLOR_PINK, -1, &Buttons[1][EXIT_BUTTON].button},
}
{ // GR_640
{"Technical Database", 1055, 37, 7, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][TECH_DATABASE_BUTTON].button },
{"Mission Simulator", 1056, 37, 23, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][SIMULATOR_BUTTON].button },
{"Cutscenes", 1057, 37, 38, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][CUTSCENES_BUTTON].button },
{"Credits", 1058, 37, 54, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][CREDITS_BUTTON].button },
{"Play", 1335, 587, 366, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][PLAY_BUTTON].button },
{"Exit", 1419, 587, 413, UI_XSTR_COLOR_PINK, -1, &Buttons[0][EXIT_BUTTON].button },
},
{ // GR_1024
{"Technical Database", 1055, 59, 12, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][TECH_DATABASE_BUTTON].button },
{"Mission Simulator", 1056, 59, 37, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][SIMULATOR_BUTTON].button },
{"Cutscenes", 1057, 59, 62, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][CUTSCENES_BUTTON].button },
{"Credits", 1058, 59, 88, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][CREDITS_BUTTON].button },
{"Play", 1335, 940, 586, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][PLAY_BUTTON].button },
{"Exit", 1419, 940, 661, UI_XSTR_COLOR_PINK, -1, &Buttons[1][EXIT_BUTTON].button },
}
};
int Cutscene_list_coords[GR_NUM_RESOLUTIONS][4] = {
{ // GR_640
9, 117, 621, 198
},
{ // GR_1024
14, 188, 994, 316
}
{ // GR_640
9, 117, 621, 198
},
{ // GR_1024
14, 188, 994, 316
}
};
int Cutscene_desc_coords[GR_NUM_RESOLUTIONS][4] = {
{ // GR_640
9, 378, 484, 73
},
{ // GR_1024
14, 605, 775, 117
}
{ // GR_640
9, 378, 484, 73
},
{ // GR_1024
14, 605, 775, 117
}
};
#define MAX_TEXT_LINES 20
#define MAX_TEXT_LINES 20
int Cutscene_max_text_lines[GR_NUM_RESOLUTIONS] = {
10,
MAX_TEXT_LINES
10,
MAX_TEXT_LINES
};
#define MAX_TEXT_LINE_LEN 256
#define MAX_TEXT_LINE_LEN 256
static int Text_size;
static int Text_offset = 0;
static int Text_line_size[MAX_TEXT_LINES];
static const char* Text_lines[MAX_TEXT_LINES];
static const char *Text_lines[MAX_TEXT_LINES];
int cutscenes_validate_cd(char *mve_name, int prompt_for_cd)
{
int cd_present = 0;
int cd_drive_num;
int cd_mve_is_on;
char volume_name[MAX_PATH_LEN];
int num_attempts = 0;
while(1) {
int path_set_ok;
cd_mve_is_on = cutscenes_get_cd_num(mve_name);
if ((cd_mve_is_on != 0) && (cd_mve_is_on != 1) && (cd_mve_is_on != 2)) {
cd_present = 0;
break;
}
sprintf(volume_name, NOX("FREESPACE2_%c"), '1' + cd_mve_is_on);
cd_drive_num = find_freespace_cd(volume_name);
path_set_ok = set_cdrom_path(cd_drive_num);
if ( path_set_ok ) {
cd_present = 1;
break;
}
if ( !prompt_for_cd ) {
cd_present = 0;
break;
}
// no CD found, so prompt user
char popup_msg[256];
int popup_rval;
sprintf(popup_msg, XSTR( "Movie not found\n\nInsert FreeSpace CD #%d to continue", 203), cd_mve_is_on+1);
popup_rval = popup(PF_BODY_BIG, 2, POPUP_CANCEL, POPUP_OK, popup_msg);
if ( popup_rval != 1 ) {
cd_present = 0;
break;
}
if ( num_attempts++ > 5 ) {
cd_present = 0;
break;
}
}
return cd_present;
}
void cutscenes_screen_play()
{
char name[MAX_FILENAME_LEN]; // *full_name
int which_cutscene;
Assert((Selected_line >= 0) && (Selected_line < (int) Cutscene_list.size()));
Assert( (Selected_line >= 0) && (Selected_line < (int)Cutscene_list.size()) );
which_cutscene = Cutscene_list[Selected_line];
strcpy_s(name, Cutscenes[which_cutscene].filename);
strcpy_s(name, Cutscenes[which_cutscene].filename );
// full_name = cf_add_ext(name, NOX(".mve"));
main_hall_stop_music(true);
main_hall_stop_ambient();
auto rval = movie::play(name);
int rval = movie_play(name);
main_hall_start_music();
if (!rval)
{
if ( !rval ) {
char str[256];
if (Cmdline_nomovies)
@@ -276,21 +333,20 @@ void cutscenes_screen_play()
else
sprintf(str, XSTR("Unable to play movie %s.", 204), Cutscenes[which_cutscene].name);
popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, str);
popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, str );
}
}
void cutscenes_screen_scroll_line_up()
{
if (Selected_line)
{
if (Selected_line) {
Selected_line--;
gamesnd_play_iface(SND_SCROLL);
} else
gamesnd_play_iface(SND_GENERAL_FAIL);
if (Selected_line < Scroll_offset)
Scroll_offset = Selected_line;
}
@@ -299,17 +355,15 @@ void cutscenes_screen_scroll_line_down()
{
int h;
if (Selected_line < (int) Cutscene_list.size() - 1)
{
if (Selected_line < (int)Cutscene_list.size() - 1) {
Selected_line++;
gamesnd_play_iface(SND_SCROLL);
} else
gamesnd_play_iface(SND_GENERAL_FAIL);
h = Cutscene_list_coords[gr_screen.res][3] / gr_get_font_height();
if (Selected_line >= Scroll_offset + h)
{
if (Selected_line >= Scroll_offset + h){
Scroll_offset++;
}
}
@@ -318,20 +372,17 @@ void cutscenes_screen_scroll_screen_up()
{
int h;
if (Scroll_offset)
{
if (Scroll_offset) {
Scroll_offset--;
Assert(Selected_line > Scroll_offset);
h = Cutscene_list_coords[gr_screen.res][3] / gr_get_font_height();
while (Selected_line >= Scroll_offset + h)
{
while (Selected_line >= Scroll_offset + h){
Selected_line--;
}
gamesnd_play_iface(SND_SCROLL);
} else
{
} else {
gamesnd_play_iface(SND_GENERAL_FAIL);
}
}
@@ -341,25 +392,21 @@ void cutscenes_screen_scroll_screen_down()
int h;
h = Cutscene_list_coords[gr_screen.res][3] / gr_get_font_height();
if (Scroll_offset + h < (int) Cutscene_list.size())
{
if (Scroll_offset + h < (int)Cutscene_list.size()) {
Scroll_offset++;
if (Selected_line < Scroll_offset)
{
if (Selected_line < Scroll_offset){
Selected_line = Scroll_offset;
}
gamesnd_play_iface(SND_SCROLL);
} else
{
} else {
gamesnd_play_iface(SND_GENERAL_FAIL);
}
}
int cutscenes_screen_button_pressed(int n)
{
switch (n)
{
switch (n) {
case TECH_DATABASE_BUTTON:
gamesnd_play_iface(SND_SWITCH_SCREENS);
gameseq_post_event(GS_EVENT_TECH_MENU);
@@ -400,13 +447,12 @@ int cutscenes_screen_button_pressed(int n)
void cutscenes_screen_init()
{
int i;
ui_button_info* b;
ui_button_info *b;
Ui_window.create(0, 0, gr_screen.max_w_unscaled, gr_screen.max_h_unscaled, 0);
Ui_window.set_mask_bmap(Cutscene_mask_name[gr_screen.res]);
for (i = 0; i < NUM_BUTTONS; i++)
{
for (i=0; i<NUM_BUTTONS; i++) {
b = &Buttons[gr_screen.res][i];
b->button.create(&Ui_window, "", b->x, b->y, 60, 30, (i < 2), 1);
@@ -417,17 +463,15 @@ void cutscenes_screen_init()
}
// add xstrs
for (i = 0; i < NUM_CUTSCENE_TEXT; i++)
{
for(i=0; i<NUM_CUTSCENE_TEXT; i++){
Ui_window.add_XSTR(&Cutscene_text[gr_screen.res][i]);
}
Buttons[gr_screen.res][EXIT_BUTTON].button.set_hotkey(KEY_CTRLED | KEY_ENTER);
Buttons[gr_screen.res][SCROLL_UP_BUTTON].button.set_hotkey(KEY_PAGEUP);
Buttons[gr_screen.res][SCROLL_DOWN_BUTTON].button.set_hotkey(KEY_PAGEDOWN);
Buttons[gr_screen.res][SCROLL_DOWN_BUTTON].button.set_hotkey(KEY_PAGEDOWN);
List_region.create(&Ui_window, "", Cutscene_list_coords[gr_screen.res][0], Cutscene_list_coords[gr_screen.res][1],
Cutscene_list_coords[gr_screen.res][2], Cutscene_list_coords[gr_screen.res][3], 0, 1);
List_region.create(&Ui_window, "", Cutscene_list_coords[gr_screen.res][0], Cutscene_list_coords[gr_screen.res][1], Cutscene_list_coords[gr_screen.res][2], Cutscene_list_coords[gr_screen.res][3], 0, 1);
List_region.hide();
// set up hotkeys for buttons so we draw the correct animation frame when a key is pressed
@@ -438,13 +482,11 @@ void cutscenes_screen_init()
Scroll_offset = Selected_line = 0;
Description_index = -1;
Cutscene_list.clear();
Cutscene_list.clear();
int u = 0;
for (SCP_vector<cutscene_info>::iterator cut = Cutscenes.begin(); cut != Cutscenes.end(); ++cut, u++)
{
if ((*cut).viewable)
{
for (SCP_vector<cutscene_info>::iterator cut = Cutscenes.begin(); cut != Cutscenes.end(); ++cut, u++) {
if ( (*cut).viewable ) {
Cutscene_list.push_back(u);
}
}
@@ -465,8 +507,7 @@ void cutscenes_screen_do_frame()
int select_tease_line = -1;
k = Ui_window.process();
switch (k)
{
switch (k) {
case KEY_DOWN: // select next line
cutscenes_screen_scroll_line_down();
break;
@@ -501,117 +542,96 @@ void cutscenes_screen_do_frame()
gameseq_post_event(GS_EVENT_OPTIONS_MENU);
break;
// the "show-all" hotkey
// the "show-all" hotkey
case KEY_CTRLED | KEY_SHIFTED | KEY_S:
{
Cutscene_list.clear();
Cutscene_list.clear();
size_t size = Cutscenes.size();
for (size_t t = 0; t < size; t++)
{
Cutscene_list.push_back((int) t);
for (size_t t = 0; t < size; t++) {
Cutscene_list.push_back((int)t);
}
break;
}
} // end switch
} // end switch
for (i = 0; i < NUM_BUTTONS; i++)
{
if (Buttons[gr_screen.res][i].button.pressed())
{
if (cutscenes_screen_button_pressed(i))
{
for (i=0; i<NUM_BUTTONS; i++){
if (Buttons[gr_screen.res][i].button.pressed()){
if (cutscenes_screen_button_pressed(i)){
return;
}
}
}
if (List_region.button_down())
{
if (List_region.button_down()) {
List_region.get_mouse_pos(NULL, &y);
z = Scroll_offset + y / font_height;
if ((z >= 0) && (z < (int) Cutscene_list.size()))
if ((z >= 0) && (z < (int)Cutscene_list.size()))
select_tease_line = z;
}
if (List_region.pressed())
{
if (List_region.pressed()) {
List_region.get_mouse_pos(NULL, &y);
z = Scroll_offset + y / font_height;
if ((z >= 0) && (z < (int) Cutscene_list.size()))
if ((z >= 0) && (z < (int)Cutscene_list.size()))
Selected_line = z;
}
GR_MAYBE_CLEAR_RES(Background_bitmap);
if (Background_bitmap >= 0)
{
if (Background_bitmap >= 0) {
gr_set_bitmap(Background_bitmap);
gr_bitmap(0, 0, GR_RESIZE_MENU);
}
}
Ui_window.draw();
for (i = TECH_DATABASE_BUTTON; i <= CREDITS_BUTTON; i++)
{
if (Buttons[gr_screen.res][i].button.button_down())
{
for (i=TECH_DATABASE_BUTTON; i<=CREDITS_BUTTON; i++){
if (Buttons[gr_screen.res][i].button.button_down()){
break;
}
}
if (i > CREDITS_BUTTON)
{
if (i > CREDITS_BUTTON){
Buttons[gr_screen.res][CUTSCENES_BUTTON].button.draw_forced(2);
}
y = 0;
z = Scroll_offset;
while (y + font_height <= Cutscene_list_coords[gr_screen.res][3])
{
if (z >= (int) Cutscene_list.size())
{
while (y + font_height <= Cutscene_list_coords[gr_screen.res][3]) {
if (z >= (int)Cutscene_list.size()){
break;
}
if (z == Selected_line)
{
if (z == Selected_line){
gr_set_color_fast(&Color_text_selected);
} else if (z == select_tease_line)
{
} else if (z == select_tease_line) {
gr_set_color_fast(&Color_text_subselected);
} else
{
} else {
gr_set_color_fast(&Color_text_normal);
}
gr_printf_menu(Cutscene_list_coords[gr_screen.res][0], Cutscene_list_coords[gr_screen.res][1] + y,
"%s", Cutscenes[Cutscene_list[z]].name);
gr_printf_menu(Cutscene_list_coords[gr_screen.res][0], Cutscene_list_coords[gr_screen.res][1] + y, Cutscenes[Cutscene_list[z]].name);
y += font_height;
z++;
}
if (Description_index != Selected_line)
{
char* src = NULL;
if (Description_index != Selected_line) {
char *src = NULL;
Description_index = Selected_line;
Text_size = 0;
if (Description_index < (int) Cutscene_list.size() &&
(int) Cutscene_list[Description_index] < (int) Cutscenes.size())
{
if ( Description_index < (int)Cutscene_list.size( ) &&
(int)Cutscene_list[ Description_index ] < (int)Cutscenes.size( ) ) {
src = Cutscenes[Cutscene_list[Description_index]].description;
if (src)
{
Text_size = split_str(src, Cutscene_desc_coords[gr_screen.res][2], Text_line_size, Text_lines,
Cutscene_max_text_lines[gr_screen.res]);
if (src) {
Text_size = split_str(src, Cutscene_desc_coords[gr_screen.res][2], Text_line_size, Text_lines, Cutscene_max_text_lines[gr_screen.res]);
Assert(Text_size >= 0 && Text_size < Cutscene_max_text_lines[gr_screen.res]);
}
}
}
if (Description_index >= 0)
{
if (Description_index >= 0) {
int len;
char line[MAX_TEXT_LINE_LEN + 1];
@@ -619,9 +639,8 @@ void cutscenes_screen_do_frame()
y = 0;
z = Text_offset;
while (y + font_height <= Cutscene_desc_coords[gr_screen.res][3])
{
if (z >= Text_size || z >= MAX_TEXT_LINES - 1)
while (y + font_height <= Cutscene_desc_coords[gr_screen.res][3]) {
if (z >= Text_size || z >= MAX_TEXT_LINES-1)
break;
len = Text_line_size[z];
@@ -630,8 +649,7 @@ void cutscenes_screen_do_frame()
strncpy(line, Text_lines[z], len);
line[len] = 0;
gr_string(Cutscene_desc_coords[gr_screen.res][0], Cutscene_desc_coords[gr_screen.res][1] + y, line,
GR_RESIZE_MENU);
gr_string(Cutscene_desc_coords[gr_screen.res][0], Cutscene_desc_coords[gr_screen.res][1] + y, line, GR_RESIZE_MENU);
y += font_height;
z++;
+9 -17
View File
@@ -13,33 +13,25 @@
#include "globalincs/globals.h"
#include "globalincs/pstypes.h"
typedef struct cutscene_info
{
char filename[MAX_FILENAME_LEN];
char name[NAME_LENGTH];
char* description;
bool viewable;
typedef struct cutscene_info {
char filename[MAX_FILENAME_LEN];
char name[NAME_LENGTH];
char *description;
int cd;
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();
int cutscene_get_cd_num(char *filename);
void cutscenes_screen_init();
void cutscenes_screen_close();
void cutscenes_screen_do_frame();
void cutscene_mark_viewable(const char* filename);
int cutscenes_validate_cd(char *mve_name, int prompt_for_cd = 1);
void cutscene_mark_viewable(char *filename);
#endif
+570
View File
@@ -0,0 +1,570 @@
#include "globalincs/pstypes.h"
extern int g_width, g_height;
extern void *g_vBackBuf1, *g_vBackBuf2;
/* 16 bit decoding routines */
static ushort *backBuf1, *backBuf2;
static int lookup_initialized;
static void dispatchDecoder16(ushort **pFrame, ubyte codeType, ubyte **pData, ubyte **pOffData, int *pDataRemain, int *curXb, int *curYb);
static void genLoopkupTable();
void decodeFrame16(ubyte *pFrame, ubyte *pMap, int mapRemain, unsigned char *pData, int dataRemain)
{
ubyte *pOrig, *pOffData, op;
ushort offset;
int length = 0, i, j, xb, yb;
if (!lookup_initialized) {
genLoopkupTable();
}
backBuf1 = (ushort *)g_vBackBuf1;
backBuf2 = (ushort *)g_vBackBuf2;
xb = g_width >> 3;
yb = g_height >> 3;
offset = pData[0]|(pData[1]<<8);
pOffData = pData + offset;
pData += 2;
pOrig = pData;
length = offset - 2; /*dataRemain-2;*/
for (j=0; j<yb; j++) {
for (i=0; i<xb/2; i++) {
op = (*pMap) & 0xf;
dispatchDecoder16((ushort **)&pFrame, op, &pData, &pOffData, &dataRemain, &i, &j);
op = ((*pMap) >> 4) & 0xf;
dispatchDecoder16((ushort **)&pFrame, op, &pData, &pOffData, &dataRemain, &i, &j);
pMap++;
mapRemain--;
}
pFrame += 7*g_width*2;
}
if ((length-(pData-pOrig)) != 0) {
nprintf(("MVE", "DEBUG: junk left over: " PTRDIFF_T_ARG ",%d," PTRDIFF_T_ARG "\n",
(pData-pOrig), length, (length-(pData-pOrig))));
}
}
static ushort GETPIXEL(unsigned char **buf, int off)
{
ushort val = (*buf)[0+off] | ((*buf)[1+off] << 8);
return val;
}
static ushort GETPIXELI(unsigned char **buf, int off)
{
ushort val = (*buf)[0+off] | ((*buf)[1+off] << 8);
(*buf) += 2;
return val;
}
static void relClose(int i, int *x, int *y)
{
int ma, mi;
ma = i >> 4;
mi = i & 0xf;
*x = mi - 8;
*y = ma - 8;
}
static void relFar(int i, int sign, int *x, int *y)
{
if (i < 56) {
*x = sign * (8 + (i % 7));
*y = sign * (i / 7);
} else {
*x = sign * (-14 + (i - 56) % 29);
*y = sign * (8 + (i - 56) / 29);
}
}
static int close_table[512];
static int far_p_table[512];
static int far_n_table[512];
static void genLoopkupTable()
{
int i;
int x, y;
for (i = 0; i < 256; i++) {
relClose(i, &x, &y);
close_table[i*2+0] = x;
close_table[i*2+1] = y;
relFar(i, 1, &x, &y);
far_p_table[i*2+0] = x;
far_p_table[i*2+1] = y;
relFar(i, -1, &x, &y);
far_n_table[i*2+0] = x;
far_n_table[i*2+1] = y;
}
lookup_initialized = 1;
}
static void copyFrame(ushort *pDest, ushort *pSrc)
{
int i;
for (i=0; i<8; i++) {
memcpy(pDest, pSrc, 16);
pDest += g_width;
pSrc += g_width;
}
}
static void patternRow4Pixels(ushort *pFrame, unsigned char pat0, unsigned char pat1, ushort *p)
{
ushort mask=0x0003;
ushort shift=0;
ushort pattern = (pat1 << 8) | pat0;
while (mask != 0) {
*pFrame++ = p[(mask & pattern) >> shift];
mask <<= 2;
shift += 2;
}
}
static void patternRow4Pixels2(ushort *pFrame, unsigned char pat0, ushort *p)
{
unsigned char mask=0x03;
unsigned char shift=0;
ushort pel;
while (mask != 0) {
pel = p[(mask & pat0) >> shift];
pFrame[0] = pel;
pFrame[1] = pel;
pFrame[g_width + 0] = pel;
pFrame[g_width + 1] = pel;
pFrame += 2;
mask <<= 2;
shift += 2;
}
}
static void patternRow4Pixels2x1(ushort *pFrame, unsigned char pat, ushort *p)
{
unsigned char mask=0x03;
unsigned char shift=0;
ushort pel;
while (mask != 0) {
pel = p[(mask & pat) >> shift];
pFrame[0] = pel;
pFrame[1] = pel;
pFrame += 2;
mask <<= 2;
shift += 2;
}
}
static void patternQuadrant4Pixels(ushort *pFrame, unsigned char pat0, unsigned char pat1, unsigned char pat2, unsigned char pat3, ushort *p)
{
unsigned long mask = 0x00000003UL;
int shift=0;
int i;
unsigned long pat = (pat3 << 24) | (pat2 << 16) | (pat1 << 8) | pat0;
for (i=0; i<16; i++) {
pFrame[i&3] = p[(pat & mask) >> shift];
if ((i&3) == 3) {
pFrame += g_width;
}
mask <<= 2;
shift += 2;
}
}
static void patternRow2Pixels(ushort *pFrame, unsigned char pat, ushort *p)
{
unsigned char mask=0x01;
while (mask != 0) {
*pFrame++ = p[(mask & pat) ? 1 : 0];
mask <<= 1;
}
}
static void patternRow2Pixels2(ushort *pFrame, unsigned char pat, ushort *p)
{
ushort pel;
unsigned char mask=0x1;
while (mask != 0x10) {
pel = p[(mask & pat) ? 1 : 0];
pFrame[0] = pel;
pFrame[1] = pel;
pFrame[g_width + 0] = pel;
pFrame[g_width + 1] = pel;
pFrame += 2;
mask <<= 1;
}
}
static void patternQuadrant2Pixels(ushort *pFrame, unsigned char pat0, unsigned char pat1, ushort *p)
{
ushort mask = 0x0001;
int i;
ushort pat = (pat1 << 8) | pat0;
for (i=0; i<16; i++) {
pFrame[i&3] = p[(pat & mask) ? 1 : 0];
if ((i&3) == 3) {
pFrame += g_width;
}
mask <<= 1;
}
}
static void dispatchDecoder16(ushort **pFrame, unsigned char codeType, unsigned char **pData, unsigned char **pOffData, int *pDataRemain, int *curXb, int *curYb)
{
ushort p[4];
unsigned char pat[16];
int i, j, k;
int x, y;
ushort *pDstBak;
pDstBak = *pFrame;
switch(codeType) {
case 0x0:
copyFrame(*pFrame, *pFrame + (backBuf2 - backBuf1));
break; // ADDED
case 0x1:
break;
case 0x2:
k = *(*pOffData)++;
x = far_p_table[k*2+0];
y = far_p_table[k*2+1];
copyFrame(*pFrame, *pFrame + x + y*g_width);
(*pDataRemain)--;
break;
case 0x3:
k = *(*pOffData)++;
x = far_n_table[k*2+0];
y = far_n_table[k*2+1];
copyFrame(*pFrame, *pFrame + x + y*g_width);
(*pDataRemain)--;
break;
case 0x4:
k = *(*pOffData)++;
x = close_table[k*2+0];
y = close_table[k*2+1];
copyFrame(*pFrame, *pFrame + (backBuf2 - backBuf1) + x + y*g_width);
(*pDataRemain)--;
break;
case 0x5:
x = (char)*(*pData)++;
y = (char)*(*pData)++;
copyFrame(*pFrame, *pFrame + (backBuf2 - backBuf1) + x + y*g_width);
*pDataRemain -= 2;
break;
case 0x6:
nprintf(("MVE", "STUB: encoding 6 not tested\n"));
for (i=0; i<2; i++) {
*pFrame += 16;
if (++*curXb == (g_width >> 3)) {
*pFrame += 7*g_width;
*curXb = 0;
if (++*curYb == (g_height >> 3)) {
return;
}
}
}
break;
case 0x7:
p[0] = GETPIXELI(pData, 0);
p[1] = GETPIXELI(pData, 0);
if (!((p[0]/*|p[1]*/)&0x8000)) {
for (i=0; i<8; i++) {
patternRow2Pixels(*pFrame, *(*pData), p);
(*pData)++;
*pFrame += g_width;
}
} else {
for (i=0; i<2; i++) {
patternRow2Pixels2(*pFrame, *(*pData) & 0xf, p);
*pFrame += 2*g_width;
patternRow2Pixels2(*pFrame, *(*pData) >> 4, p);
(*pData)++;
*pFrame += 2*g_width;
}
}
break;
case 0x8:
p[0] = GETPIXEL(pData, 0);
if (!(p[0] & 0x8000)) {
for (i=0; i<4; i++) {
p[0] = GETPIXELI(pData, 0);
p[1] = GETPIXELI(pData, 0);
pat[0] = (*pData)[0];
pat[1] = (*pData)[1];
(*pData) += 2;
patternQuadrant2Pixels(*pFrame, pat[0], pat[1], p);
if (i & 1) {
*pFrame -= (4*g_width - 4);
} else {
*pFrame += 4*g_width;
}
}
} else {
p[2] = GETPIXEL(pData, 8);
if (!(p[2]&0x8000)) {
for (i=0; i<4; i++) {
if ((i & 1) == 0) {
p[0] = GETPIXELI(pData, 0);
p[1] = GETPIXELI(pData, 0);
}
pat[0] = *(*pData)++;
pat[1] = *(*pData)++;
patternQuadrant2Pixels(*pFrame, pat[0], pat[1], p);
if (i & 1) {
*pFrame -= (4*g_width - 4);
} else {
*pFrame += 4*g_width;
}
}
} else {
for (i=0; i<8; i++) {
if ((i & 3) == 0) {
p[0] = GETPIXELI(pData, 0);
p[1] = GETPIXELI(pData, 0);
}
patternRow2Pixels(*pFrame, *(*pData), p);
(*pData)++;
*pFrame += g_width;
}
}
}
break;
case 0x9:
p[0] = GETPIXELI(pData, 0);
p[1] = GETPIXELI(pData, 0);
p[2] = GETPIXELI(pData, 0);
p[3] = GETPIXELI(pData, 0);
*pDataRemain -= 8;
if (!(p[0] & 0x8000)) {
if (!(p[2] & 0x8000)) {
for (i=0; i<8; i++) {
pat[0] = (*pData)[0];
pat[1] = (*pData)[1];
(*pData) += 2;
patternRow4Pixels(*pFrame, pat[0], pat[1], p);
*pFrame += g_width;
}
*pDataRemain -= 16;
} else {
patternRow4Pixels2(*pFrame, (*pData)[0], p);
*pFrame += 2*g_width;
patternRow4Pixels2(*pFrame, (*pData)[1], p);
*pFrame += 2*g_width;
patternRow4Pixels2(*pFrame, (*pData)[2], p);
*pFrame += 2*g_width;
patternRow4Pixels2(*pFrame, (*pData)[3], p);
(*pData) += 4;
*pDataRemain -= 4;
}
} else {
if (!(p[2] & 0x8000)) {
for (i=0; i<8; i++) {
pat[0] = (*pData)[0];
(*pData) += 1;
patternRow4Pixels2x1(*pFrame, pat[0], p);
*pFrame += g_width;
}
*pDataRemain -= 8;
} else {
for (i=0; i<4; i++) {
pat[0] = (*pData)[0];
pat[1] = (*pData)[1];
(*pData) += 2;
patternRow4Pixels(*pFrame, pat[0], pat[1], p);
*pFrame += g_width;
patternRow4Pixels(*pFrame, pat[0], pat[1], p);
*pFrame += g_width;
}
*pDataRemain -= 8;
}
}
break;
case 0xa:
p[0] = GETPIXEL(pData, 0);
if (!(p[0] & 0x8000)) {
for (i=0; i<4; i++) {
p[0] = GETPIXELI(pData, 0);
p[1] = GETPIXELI(pData, 0);
p[2] = GETPIXELI(pData, 0);
p[3] = GETPIXELI(pData, 0);
pat[0] = (*pData)[0];
pat[1] = (*pData)[1];
pat[2] = (*pData)[2];
pat[3] = (*pData)[3];
(*pData) += 4;
patternQuadrant4Pixels(*pFrame, pat[0], pat[1], pat[2], pat[3], p);
if (i & 1) {
*pFrame -= (4*g_width - 4);
} else {
*pFrame += 4*g_width;
}
}
} else {
p[0] = GETPIXEL(pData, 16);
if (!(p[0] & 0x8000)) {
for (i=0; i<4; i++) {
if ((i&1) == 0) {
p[0] = GETPIXELI(pData, 0);
p[1] = GETPIXELI(pData, 0);
p[2] = GETPIXELI(pData, 0);
p[3] = GETPIXELI(pData, 0);
}
pat[0] = (*pData)[0];
pat[1] = (*pData)[1];
pat[2] = (*pData)[2];
pat[3] = (*pData)[3];
(*pData) += 4;
patternQuadrant4Pixels(*pFrame, pat[0], pat[1], pat[2], pat[3], p);
if (i & 1) {
*pFrame -= (4*g_width - 4);
} else {
*pFrame += 4*g_width;
}
}
} else {
for (i=0; i<8; i++) {
if ((i&3) == 0) {
p[0] = GETPIXELI(pData, 0);
p[1] = GETPIXELI(pData, 0);
p[2] = GETPIXELI(pData, 0);
p[3] = GETPIXELI(pData, 0);
}
pat[0] = (*pData)[0];
pat[1] = (*pData)[1];
patternRow4Pixels(*pFrame, pat[0], pat[1], p);
*pFrame += g_width;
(*pData) += 2;
}
}
}
break;
case 0xb:
for (i=0; i<8; i++) {
#if BYTE_ORDER == BIG_ENDIAN
ubyte frame_tmp[16];
memcpy(&frame_tmp, *pData, 16);
ushort *swap_tmp;
for (j = 0; j < 16; j += 2) {
swap_tmp = (ushort*)(frame_tmp + j);
*swap_tmp = INTEL_SHORT(*swap_tmp);
}
memcpy(*pFrame, &frame_tmp, 16);
#else
memcpy(*pFrame, *pData, 16);
#endif
*pFrame += g_width;
*pData += 16;
*pDataRemain -= 16;
}
break;
case 0xc:
for (i=0; i<4; i++) {
p[0] = GETPIXEL(pData, 0);
p[1] = GETPIXEL(pData, 2);
p[2] = GETPIXEL(pData, 4);
p[3] = GETPIXEL(pData, 6);
for (j=0; j<2; j++) {
for (k=0; k<4; k++) {
(*pFrame)[2*k] = p[k];
(*pFrame)[2*k+1] = p[k];
}
*pFrame += g_width;
}
*pData += 8;
*pDataRemain -= 8;
}
break;
case 0xd:
for (i=0; i<2; i++) {
p[0] = GETPIXEL(pData, 0);
p[1] = GETPIXEL(pData, 2);
for (j=0; j<4; j++) {
for (k=0; k<4; k++) {
(*pFrame)[k*g_width+j] = p[0];
(*pFrame)[k*g_width+j+4] = p[1];
}
}
*pFrame += 4*g_width;
*pData += 4;
*pDataRemain -= 4;
}
break;
case 0xe:
p[0] = GETPIXEL(pData, 0);
for (i = 0; i < 8; i++) {
for (j = 0; j < 8; j++) {
(*pFrame)[j] = p[0];
}
*pFrame += g_width;
}
*pData += 2;
*pDataRemain -= 2;
break;
case 0xf:
p[0] = GETPIXEL(pData, 0);
p[1] = GETPIXEL(pData, 1);
for (i=0; i<8; i++) {
for (j=0; j<8; j++) {
(*pFrame)[j] = p[(i+j)&1];
}
*pFrame += g_width;
}
*pData += 4;
*pDataRemain -= 4;
break;
default:
break;
}
*pFrame = pDstBak+8;
}
+533
View File
@@ -0,0 +1,533 @@
#include "globalincs/pstypes.h"
extern int g_width, g_height;
extern void *g_vBackBuf1, *g_vBackBuf2;
static void dispatchDecoder8(ubyte **pFrame, ubyte codeType, ubyte **pData, int *pDataRemain, int *curXb, int *curYb);
void decodeFrame8(ubyte *pFrame, ubyte *pMap, int mapRemain, ubyte *pData, int dataRemain)
{
int i, j;
int xb, yb;
xb = g_width >> 3;
yb = g_height >> 3;
for (j = 0; j < yb; j++) {
for (i = 0; i < (xb / 2); i++) {
dispatchDecoder8(&pFrame, (*pMap) & 0xf, &pData, &dataRemain, &i, &j);
dispatchDecoder8(&pFrame, (*pMap) >> 4, &pData, &dataRemain, &i, &j);
pMap++;
mapRemain--;
}
pFrame += 7*g_width;
}
}
static void relClose(int i, int *x, int *y)
{
int ma, mi;
ma = i >> 4;
mi = i & 0xf;
*x = mi - 8;
*y = ma - 8;
}
static void relFar(int i, int sign, int *x, int *y)
{
if (i < 56) {
*x = sign * (8 + (i % 7));
*y = sign * (i / 7);
} else {
*x = sign * (-14 + (i - 56) % 29);
*y = sign * (8 + (i - 56) / 29);
}
}
/* copies an 8x8 block from pSrc to pDest.
pDest and pSrc are both g_width bytes wide */
static void copyFrame(ubyte *pDest, ubyte *pSrc)
{
int i;
for (i = 0; i < 8; i++) {
memcpy(pDest, pSrc, 8);
pDest += g_width;
pSrc += g_width;
}
}
// Fill in the next eight bytes with p[0], p[1], p[2], or p[3],
// depending on the corresponding two-bit value in pat0 and pat1
static void patternRow4Pixels(ubyte *pFrame, ubyte pat0, ubyte pat1, ubyte *p)
{
ushort mask = 0x0003;
ushort shift = 0;
ushort pattern = (pat1 << 8) | pat0;
while (mask != 0) {
*pFrame++ = p[(mask & pattern) >> shift];
mask <<= 2;
shift += 2;
}
}
// Fill in the next four 2x2 pixel blocks with p[0], p[1], p[2], or p[3],
// depending on the corresponding two-bit value in pat0.
static void patternRow4Pixels2(ubyte *pFrame, ubyte pat0, ubyte *p)
{
ubyte mask = 0x03;
ubyte shift = 0;
ubyte pel;
while (mask != 0) {
pel = p[(mask & pat0) >> shift];
pFrame[0] = pel;
pFrame[1] = pel;
pFrame[g_width + 0] = pel;
pFrame[g_width + 1] = pel;
pFrame += 2;
mask <<= 2;
shift += 2;
}
}
// Fill in the next four 2x1 pixel blocks with p[0], p[1], p[2], or p[3],
// depending on the corresponding two-bit value in pat.
static void patternRow4Pixels2x1(ubyte *pFrame, ubyte pat, ubyte *p)
{
ubyte mask = 0x03;
ubyte shift = 0;
ubyte pel;
while (mask != 0) {
pel = p[(mask & pat) >> shift];
pFrame[0] = pel;
pFrame[1] = pel;
pFrame += 2;
mask <<= 2;
shift += 2;
}
}
// Fill in the next 4x4 pixel block with p[0], p[1], p[2], or p[3],
// depending on the corresponding two-bit value in pat0, pat1, pat2, and pat3.
static void patternQuadrant4Pixels(ubyte *pFrame, ubyte pat0, ubyte pat1, ubyte pat2, ubyte pat3, ubyte *p)
{
unsigned long mask = 0x00000003UL;
int shift=0;
int i;
unsigned long pat = (pat3 << 24) | (pat2 << 16) | (pat1 << 8) | pat0;
for (i = 0; i < 16; i++) {
pFrame[i&3] = p[(pat & mask) >> shift];
if ( (i & 3) == 3 )
pFrame += g_width;
mask <<= 2;
shift += 2;
}
}
// fills the next 8 pixels with either p[0] or p[1], depending on pattern
static void patternRow2Pixels(ubyte *pFrame, ubyte pat, ubyte *p)
{
ubyte mask=0x01;
while (mask != 0) {
*pFrame++ = p[(mask & pat) ? 1 : 0];
mask <<= 1;
}
}
// fills the next four 2 x 2 pixel boxes with either p[0] or p[1], depending on pattern
static void patternRow2Pixels2(ubyte *pFrame, ubyte pat, ubyte *p)
{
ubyte pel;
ubyte mask=0x1;
while (mask != 0x10) {
pel = p[(mask & pat) ? 1 : 0];
pFrame[0] = pel; // upper-left
pFrame[1] = pel; // upper-right
pFrame[g_width + 0] = pel; // lower-left
pFrame[g_width + 1] = pel; // lower-right
pFrame += 2;
mask <<= 1;
}
}
// fills pixels in the next 4 x 4 pixel boxes with either p[0] or p[1], depending on pat0 and pat1.
static void patternQuadrant2Pixels(ubyte *pFrame, ubyte pat0, ubyte pat1, ubyte *p)
{
ubyte pel;
ushort mask = 0x0001;
int i, j;
ushort pat = (pat1 << 8) | pat0;
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
pel = p[(pat & mask) ? 1 : 0];
pFrame[j + i * g_width] = pel;
mask <<= 1;
}
}
}
static void dispatchDecoder8(ubyte **pFrame, ubyte codeType, ubyte **pData, int *pDataRemain, int *curXb, int *curYb)
{
ubyte p[4];
ubyte pat[16];
int i, j, k;
int x, y;
switch(codeType) {
case 0x0:
copyFrame(*pFrame, *pFrame + ((ubyte *)g_vBackBuf2 - (ubyte *)g_vBackBuf1));
*pFrame += 8;
break;
case 0x1:
*pFrame += 8;
break;
case 0x2:
relFar(*(*pData)++, 1, &x, &y);
copyFrame(*pFrame, *pFrame + x + y*g_width);
*pFrame += 8;
(*pDataRemain)--;
break;
case 0x3:
relFar(*(*pData)++, -1, &x, &y);
copyFrame(*pFrame, *pFrame + x + y*g_width);
*pFrame += 8;
(*pDataRemain)--;
break;
case 0x4:
relClose(*(*pData)++, &x, &y);
copyFrame(*pFrame, *pFrame + ((ubyte *)g_vBackBuf2 - (ubyte *)g_vBackBuf1) + x + y*g_width);
*pFrame += 8;
(*pDataRemain)--;
break;
case 0x5:
x = (signed char)*(*pData)++;
y = (signed char)*(*pData)++;
copyFrame(*pFrame, *pFrame + ((ubyte *)g_vBackBuf2 - (ubyte *)g_vBackBuf1) + x + y*g_width);
*pFrame += 8;
*pDataRemain -= 2;
break;
case 0x6:
for (i = 0; i < 2; i++) {
*pFrame += 16;
if (++*curXb == (g_width >> 3)) {
*pFrame += 7*g_width;
*curXb = 0;
if (++*curYb == (g_height >> 3))
return;
}
}
break;
case 0x7:
p[0] = *(*pData)++;
p[1] = *(*pData)++;
if (p[0] <= p[1]) {
for (i = 0; i < 8; i++) {
patternRow2Pixels(*pFrame, *(*pData)++, p);
*pFrame += g_width;
}
} else {
for (i = 0; i < 2; i++) {
patternRow2Pixels2(*pFrame, *(*pData) & 0xf, p);
*pFrame += 2*g_width;
patternRow2Pixels2(*pFrame, *(*pData)++ >> 4, p);
*pFrame += 2*g_width;
}
}
*pFrame -= (8*g_width - 8);
break;
case 0x8:
if ( (*pData)[0] <= (*pData)[1] ) {
// four quadrant case
for (i = 0; i < 4; i++) {
p[0] = *(*pData)++;
p[1] = *(*pData)++;
pat[0] = *(*pData)++;
pat[1] = *(*pData)++;
patternQuadrant2Pixels(*pFrame, pat[0], pat[1], p);
// alternate between moving down and moving up and right
if (i & 1)
*pFrame += 4 - 4*g_width; // up and right
else
*pFrame += 4*g_width; // down
}
} else if ( (*pData)[6] <= (*pData)[7] ) {
// split horizontal
for (i = 0; i < 4; i++) {
if ((i & 1) == 0) {
p[0] = *(*pData)++;
p[1] = *(*pData)++;
}
pat[0] = *(*pData)++;
pat[1] = *(*pData)++;
patternQuadrant2Pixels(*pFrame, pat[0], pat[1], p);
if (i & 1)
*pFrame -= (4*g_width - 4);
else
*pFrame += 4*g_width;
}
} else {
// split vertical
for (i = 0; i < 8; i++) {
if ((i & 3) == 0) {
p[0] = *(*pData)++;
p[1] = *(*pData)++;
}
patternRow2Pixels(*pFrame, *(*pData)++, p);
*pFrame += g_width;
}
*pFrame -= (8*g_width - 8);
}
break;
case 0x9:
if ( (*pData)[0] <= (*pData)[1] ) {
if ( (*pData)[2] <= (*pData)[3] ) {
p[0] = *(*pData)++;
p[1] = *(*pData)++;
p[2] = *(*pData)++;
p[3] = *(*pData)++;
for (i = 0; i < 8; i++) {
pat[0] = *(*pData)++;
pat[1] = *(*pData)++;
patternRow4Pixels(*pFrame, pat[0], pat[1], p);
*pFrame += g_width;
}
*pFrame -= (8*g_width - 8);
} else {
p[0] = *(*pData)++;
p[1] = *(*pData)++;
p[2] = *(*pData)++;
p[3] = *(*pData)++;
patternRow4Pixels2(*pFrame, *(*pData)++, p);
*pFrame += 2*g_width;
patternRow4Pixels2(*pFrame, *(*pData)++, p);
*pFrame += 2*g_width;
patternRow4Pixels2(*pFrame, *(*pData)++, p);
*pFrame += 2*g_width;
patternRow4Pixels2(*pFrame, *(*pData)++, p);
*pFrame -= (6*g_width - 8);
}
} else {
if ( (*pData)[2] <= (*pData)[3] ) {
// draw 2x1 strips
p[0] = *(*pData)++;
p[1] = *(*pData)++;
p[2] = *(*pData)++;
p[3] = *(*pData)++;
for (i = 0; i < 8; i++) {
pat[0] = *(*pData)++;
patternRow4Pixels2x1(*pFrame, pat[0], p);
*pFrame += g_width;
}
*pFrame -= (8*g_width - 8);
} else {
// draw 1x2 strips
p[0] = *(*pData)++;
p[1] = *(*pData)++;
p[2] = *(*pData)++;
p[3] = *(*pData)++;
for (i = 0; i < 4; i++) {
pat[0] = *(*pData)++;
pat[1] = *(*pData)++;
patternRow4Pixels(*pFrame, pat[0], pat[1], p);
*pFrame += g_width;
patternRow4Pixels(*pFrame, pat[0], pat[1], p);
*pFrame += g_width;
}
*pFrame -= (8*g_width - 8);
}
}
break;
case 0xa:
if ( (*pData)[0] <= (*pData)[1] ) {
for (i = 0; i < 4; i++) {
p[0] = *(*pData)++;
p[1] = *(*pData)++;
p[2] = *(*pData)++;
p[3] = *(*pData)++;
pat[0] = *(*pData)++;
pat[1] = *(*pData)++;
pat[2] = *(*pData)++;
pat[3] = *(*pData)++;
patternQuadrant4Pixels(*pFrame, pat[0], pat[1], pat[2], pat[3], p);
if (i & 1)
*pFrame -= (4*g_width - 4);
else
*pFrame += 4*g_width;
}
} else {
if ( (*pData)[12] <= (*pData)[13] ) {
// split vertical
for (i = 0; i < 4; i++) {
if ((i&1) == 0) {
p[0] = *(*pData)++;
p[1] = *(*pData)++;
p[2] = *(*pData)++;
p[3] = *(*pData)++;
}
pat[0] = *(*pData)++;
pat[1] = *(*pData)++;
pat[2] = *(*pData)++;
pat[3] = *(*pData)++;
patternQuadrant4Pixels(*pFrame, pat[0], pat[1], pat[2], pat[3], p);
if (i & 1)
*pFrame -= (4*g_width - 4);
else
*pFrame += 4*g_width;
}
} else {
// split horizontal
for (i = 0; i < 8; i++) {
if ((i&3) == 0) {
p[0] = *(*pData)++;
p[1] = *(*pData)++;
p[2] = *(*pData)++;
p[3] = *(*pData)++;
}
pat[0] = *(*pData)++;
pat[1] = *(*pData)++;
patternRow4Pixels(*pFrame, pat[0], pat[1], p);
*pFrame += g_width;
}
*pFrame -= (8*g_width - 8);
}
}
break;
case 0xb:
for (i = 0; i < 8; i++) {
memcpy(*pFrame, *pData, 8);
*pFrame += g_width;
*pData += 8;
*pDataRemain -= 8;
}
*pFrame -= (8*g_width - 8);
break;
case 0xc:
for (i = 0; i < 4; i++) {
for (j = 0; j < 2; j++) {
for (k = 0; k < 4; k++) {
(*pFrame)[2*k] = (*pData)[k];
(*pFrame)[2*k+1] = (*pData)[k];
}
*pFrame += g_width;
}
*pData += 4;
*pDataRemain -= 4;
}
*pFrame -= (8*g_width - 8);
break;
case 0xd:
for (i = 0; i < 2; i++) {
for (j = 0; j < 4; j++) {
for (k = 0; k < 4; k++) {
(*pFrame)[k*g_width+j] = (*pData)[0];
(*pFrame)[k*g_width+j+4] = (*pData)[1];
}
}
*pFrame += 4*g_width;
*pData += 2;
*pDataRemain -= 2;
}
*pFrame -= (8*g_width - 8);
break;
case 0xe:
for (i = 0; i < 8; i++) {
memset(*pFrame, **pData, 8);
*pFrame += g_width;
}
(*pData)++;
(*pDataRemain)--;
*pFrame -= (8*g_width - 8);
break;
case 0xf:
for (i = 0; i < 8; i++) {
for (j = 0; j < 8; j++) {
(*pFrame)[j] = (*pData)[(i+j)&1];
}
*pFrame += g_width;
}
*pData += 2;
*pDataRemain -= 2;
*pFrame -= (8*g_width - 8);
break;
default:
break;
}
}
-224
View File
@@ -1,224 +0,0 @@
#include "cutscene/ffmpeg/AudioDecoder.h"
#include "tracing/tracing.h"
namespace {
const int OUT_CH_LAYOUT = AV_CH_LAYOUT_STEREO;
const int OUT_SAMPLE_RATE = 48000;
const AVSampleFormat OUT_SAMPLE_FORMAT = AV_SAMPLE_FMT_S16;
const int OUT_NUM_CHANNELS = av_get_channel_layout_nb_channels(OUT_CH_LAYOUT);
const int DEFAULT_SRC_NUM_SAMPLES = 1024;
SwrContext* getSWRContext(uint64_t layout, int rate, AVSampleFormat inFmt) {
auto swr = swr_alloc();
av_opt_set_int(swr, "in_channel_layout", layout, 0);
av_opt_set_int(swr, "in_sample_rate", rate, 0);
av_opt_set_int(swr, "in_sample_fmt", inFmt, 0);
av_opt_set_int(swr, "out_channel_layout", OUT_CH_LAYOUT, 0);
av_opt_set_int(swr, "out_sample_rate", OUT_SAMPLE_RATE, 0);
av_opt_set_int(swr, "out_sample_fmt", OUT_SAMPLE_FORMAT, 0);
swr_init(swr);
return swr;
}
int alloc_array_and_samples(uint8_t*** outData, int* linesize, int channels, int samples, AVSampleFormat format) {
auto planes = av_sample_fmt_is_planar(format) ? channels : 1;
*outData = reinterpret_cast<uint8_t**>(av_mallocz(planes * sizeof(**outData)));
auto ret = av_samples_alloc(*outData, linesize, channels, samples, format, 0);
if (ret < 0) {
av_freep(outData);
}
return ret;
}
int64_t getDelay(SwrContext* ctx, int64_t sampleRate) {
#ifdef WITH_LIBAV
return avresample_get_delay(ctx);
#else
return swr_get_delay(ctx, sampleRate);
#endif
}
int resample_convert(SwrContext* ctx, uint8_t** output,
int out_plane_size, int out_samples, uint8_t** input,
int in_plane_size, int in_samples) {
#ifdef WITH_LIBAV
return avresample_convert(ctx, output, out_plane_size, out_samples, input, in_plane_size, in_samples);
#else
return swr_convert(ctx, output, out_samples, (const uint8_t**) input, in_samples);
#endif
}
}
namespace cutscene {
namespace ffmpeg {
AudioDecoder::AudioDecoder(DecoderStatus* status)
: FFMPEGStreamDecoder(status) {
m_audioBuffer.reserve(static_cast<size_t>(OUT_SAMPLE_RATE * OUT_NUM_CHANNELS / 2));
m_resampleCtx = getSWRContext(m_status->audioCodecPars.channel_layout, m_status->audioCodecPars.sample_rate,
m_status->audioCodecPars.audio_format);
/*
* compute the number of converted samples: buffering is avoided
* ensuring that the output buffer will contain at least all the
* converted input samples
*/
m_maxOutNumSamples = m_outNumSamples = static_cast<int>(av_rescale_rnd(DEFAULT_SRC_NUM_SAMPLES,
OUT_SAMPLE_RATE,
m_status->audioCodecPars.sample_rate,
AV_ROUND_UP));
auto ret = alloc_array_and_samples(&m_outData, &m_outLinesize, OUT_NUM_CHANNELS,
m_outNumSamples, OUT_SAMPLE_FORMAT);
if (ret < 0) {
mprintf(("FFMPEG: Failed to allocate samples array!\n"));
}
}
AudioDecoder::~AudioDecoder() {
if (m_outData) {
av_freep(&m_outData[0]);
}
av_freep(&m_outData);
swr_free(&m_resampleCtx);
}
void AudioDecoder::flushAudioBuffer() {
if (m_audioBuffer.empty()) {
// Nothing to do here
return;
}
AudioFramePtr audioFrame(new AudioFrame());
audioFrame->channels = OUT_NUM_CHANNELS;
audioFrame->rate = OUT_SAMPLE_RATE;
audioFrame->audioData.assign(m_audioBuffer.begin(), m_audioBuffer.end());
pushFrame(std::move(audioFrame));
m_audioBuffer.clear();
}
void AudioDecoder::handleDecodedFrame(AVFrame* frame) {
/* compute destination number of samples */
m_outNumSamples = static_cast<int>(av_rescale_rnd(getDelay(m_resampleCtx, frame->sample_rate)
+ frame->nb_samples, OUT_SAMPLE_RATE, frame->sample_rate,
AV_ROUND_UP));
if (m_outNumSamples > m_maxOutNumSamples) {
av_freep(&m_outData[0]);
auto ret = av_samples_alloc(m_outData, &m_outLinesize, OUT_NUM_CHANNELS, m_outNumSamples,
OUT_SAMPLE_FORMAT, 1);
if (ret < 0) {
mprintf(("FFMPEG: Failed to allocate samples!!!"));
return;
}
m_maxOutNumSamples = m_outNumSamples;
}
/* convert to destination format */
auto ret = resample_convert(m_resampleCtx, m_outData, 0, m_outNumSamples,
(uint8_t**) frame->data, 0, frame->nb_samples);
if (ret < 0) {
mprintf(("FFMPEG: Error while converting audio!\n"));
return;
}
auto outBufsize = av_samples_get_buffer_size(&m_outLinesize, OUT_NUM_CHANNELS, ret, OUT_SAMPLE_FORMAT, 1);
if (outBufsize < 0) {
mprintf(("FFMPEG: Could not get sample buffer size!\n"));
return;
}
auto begin = reinterpret_cast<short*>(m_outData[0]);
auto end = reinterpret_cast<short*>(m_outData[0] + outBufsize);
auto size = std::distance(begin, end);
auto newSize = m_audioBuffer.size() + size;
if (newSize <= m_audioBuffer.capacity()) {
// We haven't filled the buffer yet
m_audioBuffer.insert(m_audioBuffer.end(), begin, end);
} else {
flushAudioBuffer();
m_audioBuffer.assign(begin, end);
}
}
void AudioDecoder::decodePacket(AVPacket* packet) {
TRACE_SCOPE(tracing::CutsceneFFmpegAudioDecoder);
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
int send_result;
do {
send_result = avcodec_send_packet(m_status->audioCodecCtx, packet);
while (avcodec_receive_frame(m_status->audioCodecCtx, m_decodeFrame) == 0) {
handleDecodedFrame(m_decodeFrame);
}
} while (send_result == AVERROR(EAGAIN));
#else
int finishedFrame = 0;
auto err = avcodec_decode_audio4(m_status->audioCodecCtx, m_decodeFrame, &finishedFrame, packet);
if (err >= 0 && finishedFrame) {
handleDecodedFrame(m_decodeFrame);
}
#endif
}
void AudioDecoder::finishDecoding() {
TRACE_SCOPE(tracing::CutsceneFFmpegAudioDecoder);
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
// Send flush packet
avcodec_send_packet(m_status->audioCodecCtx, nullptr);
// Handle those decoders that have a delay
while (true) {
auto ret = avcodec_receive_frame(m_status->audioCodecCtx, m_decodeFrame);
if (ret == 0) {
handleDecodedFrame(m_decodeFrame);
}
else {
// Everything consumed or error
break;
}
}
#else
// Handle those decoders that have a delay
AVPacket nullPacket;
memset(&nullPacket, 0, sizeof(nullPacket));
nullPacket.data = nullptr;
nullPacket.size = 0;
while (true) {
int finishedFrame = 1;
auto err = avcodec_decode_audio4(m_status->audioCodecCtx, m_decodeFrame, &finishedFrame, &nullPacket);
if (err < 0 || !finishedFrame) {
break;
}
handleDecodedFrame(m_decodeFrame);
}
#endif
// Push the last bits of audio data into the queue
flushAudioBuffer();
}
}
}
-35
View File
@@ -1,35 +0,0 @@
#pragma once
#include "cutscene/ffmpeg/internal.h"
#include "cutscene/ffmpeg/FFMPEGDecoder.h"
namespace cutscene {
namespace ffmpeg {
class AudioDecoder: public FFMPEGStreamDecoder<AudioFrame> {
private:
SwrContext* m_resampleCtx;
uint8_t** m_outData;
int m_outLinesize;
int m_maxOutNumSamples;
int m_outNumSamples;
SCP_vector<short> m_audioBuffer;
void handleDecodedFrame(AVFrame* frame);
void flushAudioBuffer();
public:
explicit AudioDecoder(DecoderStatus* status);
virtual ~AudioDecoder();
virtual void decodePacket(AVPacket* packet) SCP_OVERRIDE;
virtual void finishDecoding() SCP_OVERRIDE;
};
}
}
-457
View File
@@ -1,457 +0,0 @@
#include <limits>
#include "cutscene/ffmpeg/FFMPEGDecoder.h"
#include "cfile/cfile.h"
#include "libs/ffmpeg/FFmpegContext.h"
#include "cutscene/ffmpeg/internal.h"
#include "cutscene/ffmpeg/AudioDecoder.h"
#include "cutscene/ffmpeg/VideoDecoder.h"
#include "cutscene/ffmpeg/SubtitleDecoder.h"
#include "localization/localize.h"
using namespace libs::ffmpeg;
namespace {
using namespace cutscene;
using namespace cutscene::ffmpeg;
class AVPacketScope
{
AVPacket* _packet;
public:
explicit AVPacketScope(AVPacket* av_packet)
: _packet(av_packet) {
}
~AVPacketScope() {
av_packet_unref(_packet);
}
};
const char* CHECKED_EXTENSIONS[] = {
"webm",
"mp4",
"ogg",
"mve"
};
double getFrameRate(AVStream* stream, AVCodecContext* codecCtx) {
auto fps = av_q2d(av_stream_get_r_frame_rate(stream));
if (fps < 0.000001)
{
fps = av_q2d(stream->avg_frame_rate);
}
if (fps < 0.000001)
{
fps = 1.0 / av_q2d(codecCtx->time_base);
}
return fps;
}
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.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.codec_id = stream->codecpar->codec_id;
#else
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.codec_id = stream->codec->codec_id;
#endif
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";
}
// 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";
}
}
namespace cutscene {
namespace ffmpeg {
struct InputStream {
std::unique_ptr<FFmpegContext> m_ctx;
};
FFMPEGDecoder::FFMPEGDecoder() {
}
FFMPEGDecoder::~FFMPEGDecoder() {
}
namespace {
std::unique_ptr<InputStream> openStream(const SCP_string& name) {
// Only check the root and movies folders
int dirType;
if (cf_exists_full(name.c_str(), CF_TYPE_ROOT)) {
dirType = CF_TYPE_ROOT;
} else if (cf_exists_full(name.c_str(), CF_TYPE_MOVIES)) {
dirType = CF_TYPE_MOVIES;
} else {
return nullptr;
}
std::unique_ptr<InputStream> input(new InputStream());
try {
// Create the FFmpeg context
input->m_ctx = FFmpegContext::createContext(name, dirType);
// This may fail, in that case return null
if (!input->m_ctx) {
return nullptr;
}
}
catch (const FFmpegException& e) {
mprintf(("Error opening %s: %s\n", name.c_str(), e.what()));
return nullptr;
}
return input;
}
std::unique_ptr<DecoderStatus> initializeStatus(std::unique_ptr<InputStream>& stream) {
std::unique_ptr<DecoderStatus> status(new DecoderStatus());
auto ctx = stream->m_ctx->ctx();
auto videoStream = av_find_best_stream(ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &status->videoCodec, 0);
if (videoStream < 0) {
if (videoStream == AVERROR_STREAM_NOT_FOUND) {
mprintf(("FFmpeg: No video stream found in file!\n"));
} else if (videoStream == AVERROR_DECODER_NOT_FOUND) {
mprintf(("FFmpeg: Codec for video stream could not be found!\n"));
} else {
mprintf(("FFmpeg: Unknown error while finding video stream!\n"));
}
return nullptr;
}
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"));
}
}
status->videoStreamIndex = videoStream;
status->videoStream = ctx->streams[videoStream];
if (audioStream >= 0) {
status->audioStreamIndex = audioStream;
status->audioStream = ctx->streams[audioStream];
}
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& pars = test_stream->codecpar;
if (!(pars->codec_type == AVMEDIA_TYPE_SUBTITLE)) {
continue;
}
AVDictionaryEntry* tag = nullptr;
if ((tag = av_dict_get(test_stream->metadata, "language", nullptr, 0)) == nullptr) {
continue;
}
auto normalized_language = normalizeLanguage(tag->value);
if (!stricmp(normalized_language.c_str(), current_language.lang_name)) {
status->subtitleStreamIndex = i;
status->subtitleStream = test_stream;
break;
}
}
status->videoCodecPars = getCodecParameters(status->videoStream);
int err;
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
status->videoCodecCtx = avcodec_alloc_context3(status->videoCodec);
// Copy codec parameters from input stream to output codec context
err = avcodec_parameters_to_context(status->videoCodecCtx, status->videoStream->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->videoCodecCtx = status->videoStream->codec;
#endif
err = avcodec_open2(status->videoCodecCtx, status->videoCodec, nullptr);
if (err < 0) {
char errorStr[512];
av_strerror(err, errorStr, sizeof(errorStr));
mprintf(("FFMPEG: Failed to open video codec! Error: %s\n", errorStr));
return nullptr;
}
mprintf(("FFmpeg: Using video codec %s (%s).\n", status->videoCodec->long_name ? status->videoCodec->long_name : "<Unknown>",
status->videoCodec->name ? status->videoCodec->name : "<Unknown>"));
// Now initialize audio, if this fails it's not a fatal error
if (audioStream >= 0) {
status->audioCodecPars = getCodecParameters(status->audioStream);
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
status->audioCodecCtx = avcodec_alloc_context3(status->audioCodec);
err = avcodec_parameters_to_context(status->audioCodecCtx, status->audioStream->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->audioCodecCtx = status->audioStream->codec;
#endif
err = avcodec_open2(status->audioCodecCtx, status->audioCodec, nullptr);
if (err < 0) {
char errorStr[512];
av_strerror(err, errorStr, sizeof(errorStr));
mprintf(("FFMPEG: Failed to open audio codec! Error: %s\n", errorStr));
}
mprintf(("FFmpeg: Using audio codec %s (%s).\n", status->audioCodec->long_name ? status->audioCodec->long_name : "<Unknown>",
status->audioCodec->name ? status->audioCodec->name : "<Unknown>"));
}
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);
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
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;
}
#else
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));
}
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;
}
std::unique_ptr<InputStream> openInputStream(const SCP_string& name) {
// Check a list of extensions we might use
// The actual format of the file may be whatever FFmpeg supports
for (auto ext : CHECKED_EXTENSIONS) {
auto fileName = name + "." + ext;
auto input = openStream(fileName);
if (input) {
return input;
}
}
return nullptr;
}
}
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(), ::tolower);
// Then remove the extension
size_t dotPos = movieName.find('.');
if (dotPos != SCP_string::npos) {
movieName.resize(dotPos);
}
// Try to open the input stream
auto input = openInputStream(movieName);
if (!input) {
return false;
}
// We now have a valid input stream, try to find the correct streams
auto status = initializeStatus(input);
if (!status) {
return false;
}
// Buffer ~ 2 seconds of video and audio
initializeQueues(static_cast<size_t>(ceil(getFrameRate(status->videoStream, status->videoCodecCtx))) * 2);
// We're done, now just put the pointer into this
std::swap(m_input, input);
std::swap(m_status, status);
return true;
}
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));
return props;
}
void FFMPEGDecoder::startDecoding() {
std::unique_ptr<VideoDecoder> videoDecoder(new VideoDecoder(m_status.get()));
std::unique_ptr<AudioDecoder> audioDecoder;
std::unique_ptr<SubtitleDecoder> subtitleDecoder;
if (hasAudio()) {
audioDecoder.reset(new AudioDecoder(m_status.get()));
}
if (hasSubtitles()) {
subtitleDecoder.reset(new SubtitleDecoder(m_status.get()));
}
auto ctx = m_input->m_ctx->ctx();
AVPacket packet;
while (isDecoding()) {
auto read_err = av_read_frame(ctx, &packet);
AVPacketScope scope(&packet);
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 {
// 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));
}
}
}
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;
}
}
}
}
-35
View File
@@ -1,35 +0,0 @@
#pragma once
#include "cutscene/Decoder.h"
namespace cutscene {
namespace ffmpeg {
struct InputStream;
struct DecoderStatus;
class FFMPEGDecoder: public Decoder {
private:
std::unique_ptr<InputStream> m_input;
std::unique_ptr<DecoderStatus> m_status;
public:
FFMPEGDecoder();
virtual ~FFMPEGDecoder();
bool initialize(const SCP_string& fileName) SCP_OVERRIDE;
MovieProperties getProperties() SCP_OVERRIDE;
void startDecoding() SCP_OVERRIDE;
bool hasAudio() SCP_OVERRIDE;
bool hasSubtitles() SCP_OVERRIDE;
void close() SCP_OVERRIDE;
};
}
}
-117
View File
@@ -1,117 +0,0 @@
//
//
#include "SubtitleDecoder.h"
namespace {
double getFrameTime(int64_t pts, AVRational time_base) {
return pts * av_q2d(time_base);
}
}
namespace cutscene {
namespace ffmpeg {
SubtitleDecoder::SubtitleDecoder(cutscene::ffmpeg::DecoderStatus* status) : FFMPEGStreamDecoder(status) {
}
SubtitleDecoder::~SubtitleDecoder() {
}
void SubtitleDecoder::decodePacket(AVPacket* packet) {
int finishedFrame = 0;
AVSubtitle subtitle;
auto result = avcodec_decode_subtitle2(m_status->subtitleCodecCtx, &subtitle, &finishedFrame, packet);
if (result >= 0 && finishedFrame) {
pushSubtitleFrame(packet, &subtitle);
avsubtitle_free(&subtitle);
}
}
void SubtitleDecoder::finishDecoding() {
}
void SubtitleDecoder::pushSubtitleFrame(AVPacket* packet, AVSubtitle* subtitle) {
if (subtitle->format != 1) {
// Non-text subtitles are not supported yet.
mprintf(("FFmpeg: Detected a non-text subtitle! This is not supported yet!\n"));
return;
}
if (subtitle->num_rects < 1) {
return;
}
int64_t pts = subtitle->pts;
if (pts == AV_NOPTS_VALUE) {
pts = packet->pts;
}
if (pts == AV_NOPTS_VALUE) {
// Still no valid timestamp...
return;
}
auto packet_time = getFrameTime(pts, m_status->subtitleStream->time_base);
auto start_time = packet_time + (subtitle->start_display_time / 1000.0);
auto end_time = packet_time + (subtitle->end_display_time / 1000.0);
if (subtitle->end_display_time == 0 && m_status->subtitleStream->time_base.num != 0) {
end_time = packet_time + getFrameTime(packet->duration, m_status->subtitleStream->time_base);
}
SCP_string processed_text;
// For now we only use the first subtitle rectangle
auto subtitle_rect = subtitle->rects[0];
if (subtitle_rect->type == SUBTITLE_BITMAP) {
// Same as above, non-text subtitles are not supported yet.
mprintf(("FFmpeg: Detected a non-text subtitle! This is not supported yet!\n"));
return;
} else if (subtitle_rect->type == SUBTITLE_TEXT) {
// Subtitle does not need to be processed any further
processed_text = subtitle_rect->text;
} else if (subtitle_rect->type == SUBTITLE_ASS) {
SCP_string ass_text = subtitle_rect->ass;
// We are not interested in any of the other information contained in the ASS line but we still need to figure
// out where our text starts
auto comma_pos = ass_text.find(',');
for (auto i = 0; i < 8 && comma_pos != SCP_string::npos; ++i) {
comma_pos = ass_text.find(',', comma_pos + 1);
}
Assertion(comma_pos != SCP_string::npos, "Received an ill-formed ASS line from FFmpeg! Text was '%s'.", subtitle_rect->ass);
// This + 1 is safe since comma_pos points to a valid character so the next character is at worst the end of the string
processed_text = ass_text.substr(comma_pos + 1);
// ASS has a special sequence for new lines that needs to be converted to an actual new line
auto newline_pos = processed_text.find("\\N");
while(newline_pos != SCP_string::npos) {
processed_text.replace(newline_pos, 2, "\n");
newline_pos = processed_text.find("\\N");
}
} else {
mprintf(("FFmpeg: Detected unknown subtitle name in movie!\n"));
return;
}
// Remove \r from string. Some subtitles use \r\n for line breaks and we only support \n
auto ret_pos = processed_text.find('\r');
while(ret_pos != SCP_string::npos) {
processed_text.erase(ret_pos, 1);
ret_pos = processed_text.find('\r');
}
SubtitleFramePtr frame(new SubtitleFrame());
frame->text = processed_text;
frame->displayStartTime = start_time;
frame->displayEndTime = end_time;
pushFrame(std::move(frame));
}
}
}
-24
View File
@@ -1,24 +0,0 @@
#pragma once
#include "cutscene/ffmpeg/internal.h"
#include "cutscene/ffmpeg/FFMPEGDecoder.h"
namespace cutscene {
namespace ffmpeg {
class SubtitleDecoder: public FFMPEGStreamDecoder<SubtitleFrame> {
public:
explicit SubtitleDecoder(DecoderStatus* status);
virtual ~SubtitleDecoder();
virtual void decodePacket(AVPacket* packet) SCP_OVERRIDE;
virtual void finishDecoding() SCP_OVERRIDE;
void pushSubtitleFrame(AVPacket* subtitle, AVSubtitle* pSubtitle);
};
}
}
-166
View File
@@ -1,166 +0,0 @@
#include "cutscene/ffmpeg/VideoDecoder.h"
#include "tracing/tracing.h"
namespace {
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) {
return pts * av_q2d(time_base);
}
}
namespace cutscene {
namespace ffmpeg {
class FFMPEGVideoFrame: public VideoFrame {
public:
FFMPEGVideoFrame() : frame(nullptr) {
}
virtual ~FFMPEGVideoFrame() {
if (frame != nullptr) {
av_freep(&frame->data[0]);
av_frame_free(&frame);
}
}
virtual DataPointers getDataPointers() {
DataPointers ptrs;
ptrs.y = frame->data[0];
ptrs.u = frame->data[1];
ptrs.v = frame->data[2];
return ptrs;
}
AVFrame* frame;
};
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);
}
VideoDecoder::~VideoDecoder() {
sws_freeContext(m_swsCtx);
}
void VideoDecoder::convertAndPushPicture(const AVFrame* frame) {
// Allocate a picture to hold the YUV data
AVFrame* yuvFrame = av_frame_alloc();
av_frame_copy(yuvFrame, frame);
yuvFrame->format = DESTINATION_FORMAT;
av_image_alloc(yuvFrame->data,
yuvFrame->linesize,
m_status->videoCodecPars.width,
m_status->videoCodecPars.height,
DESTINATION_FORMAT,
1);
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 YUV
sws_scale(
m_swsCtx,
(uint8_t const* const*) frame->data,
frame->linesize,
0,
m_status->videoCodecPars.height,
yuvFrame->data,
yuvFrame->linesize
);
}
videoFramePtr->id = ++m_frameId;
videoFramePtr->frameTime = getFrameTime(av_frame_get_best_effort_timestamp(frame), m_status->videoStream->time_base);
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()));
}
void VideoDecoder::decodePacket(AVPacket* packet) {
TRACE_SCOPE(tracing::CutsceneFFmpegVideoDecoder);
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
int send_result;
do {
send_result = avcodec_send_packet(m_status->videoCodecCtx, packet);
while(avcodec_receive_frame(m_status->videoCodecCtx, m_decodeFrame) == 0) {
convertAndPushPicture(m_decodeFrame);
}
} while (send_result == AVERROR(EAGAIN));
#else
int finishedFrame = 0;
auto result = avcodec_decode_video2(m_status->videoCodecCtx, m_decodeFrame, &finishedFrame, packet);
if (result >= 0 && finishedFrame) {
convertAndPushPicture(m_decodeFrame);
}
#endif
}
void VideoDecoder::finishDecoding() {
TRACE_SCOPE(tracing::CutsceneFFmpegVideoDecoder);
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
// Send flush packet
avcodec_send_packet(m_status->videoCodecCtx, nullptr);
// Handle those decoders that have a delay
while (true) {
auto ret = avcodec_receive_frame(m_status->videoCodecCtx, m_decodeFrame);
if (ret == 0) {
convertAndPushPicture(m_decodeFrame);
} else {
// Everything consumed or error
break;
}
}
#else
// Handle those decoders that have a delay
AVPacket nullPacket;
memset(&nullPacket, 0, sizeof(nullPacket));
nullPacket.data = nullptr;
nullPacket.size = 0;
while (true) {
int finishedFrame = 1;
auto err = avcodec_decode_video2(m_status->videoCodecCtx, m_decodeFrame, &finishedFrame, &nullPacket);
if (err < 0 || !finishedFrame) {
break;
}
convertAndPushPicture(m_decodeFrame);
}
#endif
}
}
}
-25
View File
@@ -1,25 +0,0 @@
#pragma once
#include "cutscene/ffmpeg/internal.h"
#include "cutscene/ffmpeg/FFMPEGDecoder.h"
namespace cutscene {
namespace ffmpeg {
class VideoDecoder: public FFMPEGStreamDecoder<VideoFrame> {
private:
int m_frameId;
SwsContext* m_swsCtx;
void convertAndPushPicture(const AVFrame* frame);
public:
explicit VideoDecoder(DecoderStatus* status);
virtual ~VideoDecoder();
virtual void decodePacket(AVPacket* packet) SCP_OVERRIDE;
virtual void finishDecoding() SCP_OVERRIDE;
};
}
}
-48
View File
@@ -1,48 +0,0 @@
#include "cutscene/ffmpeg/internal.h"
namespace cutscene {
namespace ffmpeg {
DecoderStatus::DecoderStatus() {}
DecoderStatus::~DecoderStatus() {
videoStreamIndex = -1;
videoStream = nullptr;
videoCodec = nullptr;
if (videoCodecCtx != nullptr) {
avcodec_close(videoCodecCtx);
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
avcodec_free_context(&videoCodecCtx);
#endif
videoCodecCtx = nullptr;
}
audioStreamIndex = -1;
audioStream = nullptr;
audioCodec = nullptr;
if (audioCodecCtx != nullptr) {
avcodec_close(audioCodecCtx);
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
avcodec_free_context(&audioCodecCtx);
#endif
audioCodecCtx = nullptr;
}
subtitleStreamIndex = -1;
subtitleStream = nullptr;
subtitleCodec = nullptr;
if (subtitleCodecCtx != nullptr) {
avcodec_close(subtitleCodecCtx);
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
avcodec_free_context(&subtitleCodecCtx);
#endif
subtitleCodecCtx = nullptr;
}
}
} // namespace ffmpeg
} // namespace cutscene
-109
View File
@@ -1,109 +0,0 @@
#pragma once
#include <functional>
#include "libs/ffmpeg/FFmpegHeaders.h"
#include "cutscene/Decoder.h"
namespace cutscene {
namespace ffmpeg {
struct CodecContextParameters {
int width = -1;
int height = -1;
AVPixelFormat pixel_format = AV_PIX_FMT_NONE;
uint64_t channel_layout = 0;
int sample_rate = -1;
AVSampleFormat audio_format = AV_SAMPLE_FMT_NONE;
AVCodecID codec_id = AV_CODEC_ID_NONE;
};
struct DecoderStatus {
int videoStreamIndex = -1;
AVStream* videoStream = nullptr;
CodecContextParameters videoCodecPars;
AVCodec* videoCodec = nullptr;
AVCodecContext* videoCodecCtx = nullptr;
int audioStreamIndex = -1;
AVStream* audioStream = nullptr;
CodecContextParameters audioCodecPars;
AVCodec* audioCodec = nullptr;
AVCodecContext* audioCodecCtx = nullptr;
int subtitleStreamIndex = -1;
AVStream* subtitleStream = nullptr;
CodecContextParameters subtitleCodecPars;
AVCodec* subtitleCodec = nullptr;
AVCodecContext* subtitleCodecCtx = nullptr;
DecoderStatus();
~DecoderStatus();
private:
DecoderStatus(const DecoderStatus&) SCP_DELETED_FUNCTION;
DecoderStatus& operator=(const DecoderStatus&) SCP_DELETED_FUNCTION;
};
template<typename Frame>
class FFMPEGStreamDecoder {
protected:
typedef Frame frame_type;
DecoderStatus* m_status = nullptr;
AVFrame* m_decodeFrame = nullptr;
SCP_queue<FramePtr<frame_type>> m_decodedFrames;
void pushFrame(FramePtr<frame_type>&& frame);
public:
explicit FFMPEGStreamDecoder(DecoderStatus* status);
virtual ~FFMPEGStreamDecoder();
FFMPEGStreamDecoder(const FFMPEGStreamDecoder&) SCP_DELETED_FUNCTION;
FFMPEGStreamDecoder& operator=(const FFMPEGStreamDecoder&) SCP_DELETED_FUNCTION;
virtual void decodePacket(AVPacket* packet) = 0;
virtual void finishDecoding() = 0;
virtual FramePtr<frame_type> getFrame();
};
template <typename Frame>
void FFMPEGStreamDecoder<Frame>::pushFrame(FramePtr<frame_type>&& frame)
{
m_decodedFrames.push(std::move(frame));
}
template <typename Frame>
FFMPEGStreamDecoder<Frame>::FFMPEGStreamDecoder(DecoderStatus* status):m_status(status)
{
m_decodeFrame = av_frame_alloc();
}
template <typename Frame>
FFMPEGStreamDecoder<Frame>::~FFMPEGStreamDecoder()
{
av_frame_free(&m_decodeFrame);
}
template <typename Frame>
FramePtr<typename FFMPEGStreamDecoder<Frame>::frame_type> FFMPEGStreamDecoder<Frame>::getFrame()
{
if (m_decodedFrames.empty()) {
return nullptr;
}
auto frame = std::move(m_decodedFrames.front());
m_decodedFrames.pop();
return frame;
}
}
}
+95 -208
View File
@@ -13,215 +13,64 @@
#include <windows.h>
#endif
#include "globalincs/pstypes.h"
#include "globalincs/alphacolors.h"
#include "globalincs/systemvars.h"
#include "io/cursor.h"
#include "graphics/2d.h"
#include "cfile/cfile.h"
#include "cmdline/cmdline.h"
#include "cutscene/cutscenes.h" // cutscene_mark_viewable()
#include "cutscene/player.h" // cutscene_mark_viewable()
#include "tracing/categories.h"
#include "tracing/tracing.h"
#include "io/timer.h"
#include "io/key.h"
#include "mod_table/mod_table.h"
#include "cutscene/movie.h"
#include "cutscene/mvelib.h"
#include "cutscene/oggplayer.h"
#include "globalincs/systemvars.h"
#include "graphics/2d.h"
#include "osapi/osapi.h"
extern int Game_mode;
extern int Is_standalone;
namespace {
const char *movie_ext_list[] = { ".ogg", ".mve" };
const int NUM_MOVIE_EXT = sizeof(movie_ext_list) / sizeof(char*);
using namespace cutscene;
struct PlaybackState {
bool playing = true;
#define MOVIE_NONE -1
#define MOVIE_OGG 0
#define MOVIE_MVE 1
vec2d posTopLeft;
vec2d posBottomRight;
// This module links freespace movie calls to the actual API calls the play the movie.
// This module handles all the different requires of OS and gfx API and finding the file to play
int subtitle_font = -1;
};
void processEvents(PlaybackState* state) {
io::mouse::CursorManager::get()->showCursor(false);
// filename - file to search for
// out_name - output, full path to file
// returns non-zero if file is found
int movie_find(char *filename, char *out_name)
{
char full_path[MAX_PATH];
char tmp_name[MAX_PATH];
size_t size, offset = 0;
os_poll();
if (out_name == NULL)
return MOVIE_NONE;
int k = key_inkey();
switch (k) {
case KEY_ESC:
case KEY_ENTER:
case KEY_SPACEBAR:
state->playing = false;
break;
default:
break;
}
memset( full_path, 0, sizeof(full_path) );
memset( tmp_name, 0, sizeof(tmp_name) );
// remove extension
strcpy_s( tmp_name, filename );
char *p = strrchr(tmp_name, '.');
if ( p ) *p = 0;
int rc = cf_find_file_location_ext(tmp_name, NUM_MOVIE_EXT, movie_ext_list, CF_TYPE_ANY, sizeof(full_path) - 1, full_path, &size, &offset, 0);
if (rc == MOVIE_NONE)
return MOVIE_NONE;
strcpy( out_name, full_path );
return rc;
}
template<typename... Args>
float print_string(float x, float y, const char* fmt, Args... params) {
SCP_string text;
sprintf(text, fmt, params...);
gr_string(x, y, text.c_str(), GR_RESIZE_NONE);
return y + font::get_current_font()->getHeight();
}
void showVideoInfo(const PlayerState& state) {
gr_set_color_fast(&Color_white);
font::set_font(font::FONT1);
float y = 200.f;
float x = 100.f;
y = print_string(x, y, "Movie FPS: %f", state.props.fps);
y = print_string(x, y, "Size: %dx%d", state.props.size.width, state.props.size.height);
y = gr_screen.max_h - 200.f;
size_t audio_queue_size = state.decoder->getAudioQueueSize();
if (state.hasAudio) {
ALint queued;
OpenAL_ErrorPrint(alGetSourcei(state.audioSid, AL_BUFFERS_QUEUED, &queued));
audio_queue_size += queued;
}
y = print_string(x, y, "Audio Queue size: " SIZE_T_ARG, audio_queue_size);
y = print_string(x, y, "Video Queue size: " SIZE_T_ARG, state.decoder->getVideoQueueSize());
y += font::get_current_font()->getHeight();
// Estimate the size of the video buffer
// We use YUV420p frames so one pixel uses 1.5 bytes of storage
size_t single_frame_size = (size_t) (state.props.size.width * state.props.size.height * 1.5);
size_t total_size = single_frame_size * state.decoder->getVideoQueueSize();
print_string(x, y, "Video buffer size: " SIZE_T_ARG "B", total_size);
}
void displayVideo(Player* player, PlaybackState* state) {
TRACE_SCOPE(tracing::CutsceneDrawVideoFrame);
GR_DEBUG_SCOPE("Display Video");
gr_clear();
player->draw(state->posTopLeft.x, state->posTopLeft.y, state->posBottomRight.x, state->posBottomRight.y);
auto subtitle = player->getCurrentSubtitle();
if (!subtitle.empty() && state->subtitle_font >= 0) {
gr_set_color_fast(&Color_bright_white);
font::set_font(state->subtitle_font);
int width;
int height;
gr_get_string_size(&width, &height, subtitle.c_str());
// Offset the subtitle by 20% of the viewport size from the bottom
auto y_offset = static_cast<int>((state->posBottomRight.y - state->posTopLeft.y) * 0.1);
auto center_x = (state->posBottomRight.x - state->posTopLeft.x) / 2;
auto text_x = center_x - width / 2;
auto text_y = state->posBottomRight.y - y_offset - height;
gr_string(text_x, text_y, subtitle.c_str(), GR_RESIZE_NONE);
}
if (Cmdline_show_video_info) {
showVideoInfo(player->getInternalState());
}
gr_flip();
}
void determine_display_positions(Player* player, PlaybackState* state) {
auto& props = player->getMovieProperties();
float screen_ratio = (float) gr_screen.center_w / (float) gr_screen.center_h;
float movie_ratio = (float) props.size.width / (float) props.size.height;
float scale_by;
if (screen_ratio > movie_ratio) {
scale_by = (float) gr_screen.center_h / (float) props.size.height;
} else {
scale_by = (float) gr_screen.center_w / (float) props.size.width;
}
float screenX;
float screenY;
if (!Cmdline_noscalevid && (scale_by != 1.0f)) {
screenX = ((gr_screen.center_w / 2.0f + gr_screen.center_offset_x) / scale_by) - (static_cast<int>(props.size.width) / 2.0f) + 0.5f;
screenY = ((gr_screen.center_h / 2.0f + gr_screen.center_offset_y) / scale_by) - (static_cast<int>(props.size.height) / 2.0f) + 0.5f;
} else {
// centers on 1024x768, fills on 640x480
screenX = i2fl(((gr_screen.center_w - static_cast<int>(props.size.width)) / 2) + gr_screen.center_offset_x);
screenY = i2fl(((gr_screen.center_h - static_cast<int>(props.size.height)) / 2) + gr_screen.center_offset_y);
}
// set additional values for screen width/height and UV coords
float screenXW = screenX + static_cast<int>(props.size.width);
float screenYH = screenY + static_cast<int>(props.size.height);
if (!Cmdline_noscalevid && (scale_by != 1.0f)) {
// Apply scaling
screenX *= scale_by;
screenY *= scale_by;
screenXW *= scale_by;
screenYH *= scale_by;
}
state->posTopLeft.x = screenX;
state->posTopLeft.y = screenY;
state->posBottomRight.x = screenXW;
state->posBottomRight.y = screenYH;
}
void initialize_player_state(Player* player, PlaybackState* state) {
determine_display_positions(player, state);
state->subtitle_font = font::FontManager::getFontIndex(Movie_subtitle_font);
if (state->subtitle_font < 0) {
Warning(LOCATION, "Failed to load subtitle font '%s'! Subtitles will be disabled.", Movie_subtitle_font.c_str());
}
}
void movie_display_loop(Player* player, PlaybackState* state) {
// Compute the maximum time we will sleep to make sure we can still maintain the movie FPS
// and not waste too much CPU time
// 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 lastDisplayTimestamp = timer_get_microseconds();
while (state->playing) {
TRACE_SCOPE(tracing::CutsceneStep);
auto timestamp = timer_get_microseconds();
auto passed = timestamp - lastDisplayTimestamp;
lastDisplayTimestamp = timestamp;
// Play as long as the player reports that there is more to display
state->playing = player->update(passed);
displayVideo(player, state);
processEvents(state);
if (passed < sleepTime) {
auto sleep = sleepTime - passed;
os_sleep(static_cast<uint>(sleep));
}
}
}
}
namespace movie {
// Play one movie
bool play(const char* name) {
bool movie_play(char *name)
{
// mark the movie as viewable to the player when in a campaign
// do this before anything else so that we're sure the movie is available
// to the player even if it's not going to play right now
@@ -229,7 +78,25 @@ bool play(const char* name) {
cutscene_mark_viewable(name);
}
if (Cmdline_nomovies || Is_standalone) {
extern int Is_standalone;
if (Cmdline_nomovies || Is_standalone)
return false;
char full_name[MAX_PATH];
int rc = 0;
memset(full_name, 0, sizeof(full_name));
rc = movie_find(name, full_name);
if (rc == MOVIE_NONE) {
strcpy_s(full_name, name);
char *p = strrchr(full_name, '.');
if ( p ) *p = 0;
mprintf(("Movie Error: Unable to open '%s' movie in any supported format.\n", full_name));
return false;
}
@@ -249,17 +116,38 @@ bool play(const char* name) {
// clear third buffer (may not be one, but that's ok)
gr_clear();
auto player = cutscene::Player::newPlayer(name);
if (player) {
PlaybackState state;
initialize_player_state(player.get(), &state);
if (rc == MOVIE_OGG) {
THEORAFILE *movie_ogg = theora_open(name);
movie_display_loop(player.get(), &state);
if (movie_ogg) {
// start playing ...
theora_play(movie_ogg);
player->stopPlayback();
} else {
// uh-oh, movie is invalid... Abory, Retry, Fail?
mprintf(("MOVIE ERROR: Found invalid movie! (%s)\n", name));
// ... done playing, close the movie
theora_close(movie_ogg);
} else {
// uh-oh, movie is invalid... Abory, Retry, Fail?
mprintf(("MOVIE ERROR: Found invalid movie! (%s)\n", name));
io::mouse::CursorManager::get()->popStatus();
return false;
}
} else if (rc == MOVIE_MVE) {
MVESTREAM *movie_mve = mve_open(name);
if (movie_mve) {
// start playing ...
mve_init(movie_mve);
mve_play(movie_mve);
// ... done playing, close the movie
mve_shutdown();
mve_close(movie_mve);
} else {
// uh-oh, movie is invalid... Abory, Retry, Fail?
mprintf(("MOVIE ERROR: Found invalid movie! (%s)\n", name));
io::mouse::CursorManager::get()->popStatus();
return false;
}
}
// show the mouse cursor again
@@ -268,9 +156,8 @@ bool play(const char* name) {
return true;
}
void play_two(const char* name1, const char* name2) {
if (play(name1)) {
play(name2);
}
}
void movie_play_two(char *name1, char *name2)
{
if ( movie_play(name1) )
movie_play(name2);
}
+4 -6
View File
@@ -12,12 +12,10 @@
#ifndef _MOVIE_HEADER_FILE
#define _MOVIE_HEADER_FILE
namespace movie {
extern const char *movie_ext_list[];
extern const int NUM_MOVIE_EXT;
bool play(const char* name);
void play_two(const char* name1, const char* name2);
}
bool movie_play(char *name);
void movie_play_two(char *name1, char *name2);
#endif
+56
View File
@@ -0,0 +1,56 @@
static int audio_exp_table[256] =
{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 47, 51, 56, 61,
66, 72, 79, 86, 94, 102, 112, 122, 133, 145, 158, 173, 189, 206, 225, 245,
267, 292, 318, 348, 379, 414, 452, 493, 538, 587, 640, 699, 763, 832, 908, 991,
1081, 1180, 1288, 1405, 1534, 1673, 1826, 1993, 2175, 2373, 2590, 2826, 3084, 3365, 3672, 4008,
4373, 4772, 5208, 5683, 6202, 6767, 7385, 8059, 8794, 9597, 10472, 11428, 12471, 13609, 14851, 16206,
17685, 19298, 21060, 22981, 25078, 27367, 29864, 32589, -29973, -26728, -23186, -19322, -15105, -10503, -5481, -1,
1, 1, 5481, 10503, 15105, 19322, 23186, 26728, 29973, -32589, -29864, -27367, -25078, -22981, -21060, -19298,
-17685, -16206, -14851, -13609, -12471, -11428, -10472, -9597, -8794, -8059, -7385, -6767, -6202, -5683, -5208, -4772,
-4373, -4008, -3672, -3365, -3084, -2826, -2590, -2373, -2175, -1993, -1826, -1673, -1534, -1405, -1288, -1180,
-1081, -991, -908, -832, -763, -699, -640, -587, -538, -493, -452, -414, -379, -348, -318, -292,
-267, -245, -225, -206, -189, -173, -158, -145, -133, -122, -112, -102, -94, -86, -79, -72,
-66, -61, -56, -51, -47, -43, -42, -41, -40, -39, -38, -37, -36, -35, -34, -33,
-32, -31, -30, -29, -28, -27, -26, -25, -24, -23, -22, -21, -20, -19, -18, -17,
-16, -15, -14, -13, -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1
};
static int getWord(unsigned char **fin)
{
int value = ((*fin)[1] << 8) | (*fin)[0];
*fin += 2;
return value;
}
static void sendWord(short **fout, int nOffset)
{
*(*fout)++ = (short)nOffset;
}
static void processSwath(short *fout, unsigned char *data, int swath, int *offsets)
{
int i;
for (i=0; i<swath; i++) {
offsets[i&1] += audio_exp_table[data[i]];
sendWord(&fout, offsets[i&1]);
}
}
void mveaudio_uncompress(short *buffer, unsigned char *data)
{
int nCurOffsets[2];
int swath;
data += 4;
swath = getWord(&data) / 2;
nCurOffsets[0] = getWord(&data);
nCurOffsets[1] = getWord(&data);
sendWord(&buffer, nCurOffsets[0]);
sendWord(&buffer, nCurOffsets[1]);
processSwath(buffer, data, swath, nCurOffsets);
}
+371
View File
@@ -0,0 +1,371 @@
#include "cfile/cfile.h"
#include "cutscene/mvelib.h"
#include "globalincs/pstypes.h"
static const char MVE_HEADER[] = "Interplay MVE File\x1A";
static const short MVE_HDRCONST1 = 0x001A;
static const short MVE_HDRCONST2 = 0x0100;
static const short MVE_HDRCONST3 = 0x1133;
// -----------------------------------------------------------
// public MVEFILE functions
// -----------------------------------------------------------
// utility functions for mvefile and mveplayer
short mve_get_short(ubyte *data)
{
short value;
value = data[0] | (data[1] << 8);
return value;
}
ushort mve_get_ushort(ubyte *data)
{
ushort value;
value = data[0] | (data[1] << 8);
return value;
}
int mve_get_int(ubyte *data)
{
int value;
value = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
return value;
}
// open an MVE file
MVEFILE *mvefile_open(char *filename)
{
int cf_opened = 0;
int mve_valid = 1;
char lower_name[MAX_FILENAME_LEN];
char buffer[20];
MVEFILE *file;
// create the file
file = (MVEFILE *)vm_malloc(sizeof(MVEFILE));
// set defaults
file->stream = NULL;
file->cur_chunk = NULL;
file->buf_size = 0;
file->cur_fill = 0;
file->next_segment = 0;
// lower case filename for checking
strncpy(lower_name, filename, strlen(filename)+1);
strlwr(lower_name);
char *p = strchr( lower_name, '.' );
if ( p ) *p = 0;
strcat_s( lower_name, ".mve" );
// NOTE: CF_TYPE *must* be ANY to get movies off of the CDs
// assume lower case filename for *nix
file->stream = cfopen(lower_name, "rb", CFILE_NORMAL, CF_TYPE_ANY);
if ( file->stream ) {
cf_opened = 1;
}
if (!cf_opened) {
mvefile_close(file);
return NULL;
}
// initialize the buffer
file->cur_chunk = (ubyte *)vm_malloc(100 + 1024);
file->buf_size = 100 + 1024;
// verify the file's header
cfread_string(buffer, 20, file->stream);
if (strcmp(buffer, MVE_HEADER))
mve_valid = 0;
if (cfread_short(file->stream) != MVE_HDRCONST1)
mve_valid = 0;
if (cfread_short(file->stream) != MVE_HDRCONST2)
mve_valid = 0;
if (cfread_short(file->stream) != MVE_HDRCONST3)
mve_valid = 0;
if (!mve_valid) {
mvefile_close(file);
return NULL;
}
// now, prefetch the next chunk
mvefile_fetch_next_chunk(file);
return file;
}
// close a MVE file
void mvefile_close(MVEFILE *file)
{
// free the stream
if (file->stream)
cfclose(file->stream);
file->stream = NULL;
// free the buffer
if (file->cur_chunk)
vm_free(file->cur_chunk);
file->cur_chunk = NULL;
// not strictly necessary
file->buf_size = 0;
file->cur_fill = 0;
file->next_segment = 0;
// free the struct
vm_free(file);
}
// get the size of the next segment
int mvefile_get_next_segment_size(MVEFILE *file)
{
// if nothing is cached, fail
if (file->cur_chunk == NULL || file->next_segment >= file->cur_fill)
return -1;
// if we don't have enough data to get a segment, fail
if (file->cur_fill - file->next_segment < 4)
return -1;
// otherwise, get the data length
return mve_get_short(file->cur_chunk + file->next_segment);
}
// get type of next segment in chunk (0xff if no more segments in chunk)
ubyte mvefile_get_next_segment_major(MVEFILE *file)
{
// if nothing is cached, fail
if (file->cur_chunk == NULL || file->next_segment >= file->cur_fill)
return 0xff;
// if we don't have enough data to get a segment, fail
if (file->cur_fill - file->next_segment < 4)
return 0xff;
// otherwise, get the data length
return file->cur_chunk[file->next_segment + 2];
}
// get subtype (version) of next segment in chunk (0xff if no more segments in chunk)
ubyte mvefile_get_next_segment_minor(MVEFILE *file)
{
// if nothing is cached, fail
if (file->cur_chunk == NULL || file->next_segment >= file->cur_fill)
return 0xff;
// if we don't have enough data to get a segment, fail
if (file->cur_fill - file->next_segment < 4)
return 0xff;
// otherwise, get the data length
return file->cur_chunk[file->next_segment + 3];
}
// see next segment (return NULL if no next segment)
ubyte *mvefile_get_next_segment(MVEFILE *file)
{
// if nothing is cached, fail
if (file->cur_chunk == NULL || file->next_segment >= file->cur_fill)
return NULL;
// if we don't have enough data to get a segment, fail
if (file->cur_fill - file->next_segment < 4)
return NULL;
// otherwise, get the data length
return file->cur_chunk + file->next_segment + 4;
}
// advance to next segment
void mvefile_advance_segment(MVEFILE *file)
{
// if nothing is cached, fail
if (file->cur_chunk == NULL || file->next_segment >= file->cur_fill)
return;
// if we don't have enough data to get a segment, fail
if (file->cur_fill - file->next_segment < 4)
return;
// else, advance to next segment
file->next_segment += (4 + mve_get_ushort(file->cur_chunk + file->next_segment));
}
// fetch the next chunk (return 0 if at end of stream)
int mvefile_fetch_next_chunk(MVEFILE *file)
{
ubyte buffer[4];
ubyte *new_buffer;
ushort length;
// fail if not open
if (file->stream == NULL)
return 0;
// fail if we can't read the next segment descriptor
if (cfread(buffer, 1, 4, file->stream) < 4)
return 0;
// pull out the next length
length = mve_get_short(buffer);
// setup a new buffer if needed --
// only allocate new buffer is old one is too small
if (length > file->buf_size) {
// allocate new buffer
new_buffer = (ubyte *)vm_malloc(100 + length);
// copy old data
if (file->cur_chunk && file->cur_fill)
memcpy(new_buffer, file->cur_chunk, file->cur_fill);
// free old buffer
if (file->cur_chunk) {
vm_free(file->cur_chunk);
file->cur_chunk = NULL;
}
// install new buffer
file->cur_chunk = new_buffer;
file->buf_size = 100 + length;
}
// read the chunk
if (length > 0) {
if (cfread(file->cur_chunk, 1, length, file->stream) < length)
return 0;
}
file->cur_fill = length;
file->next_segment = 0;
return 1;
}
// -----------------------------------------------------------
// public MVESTREAM functions
// -----------------------------------------------------------
// open an MVE stream
MVESTREAM *mve_open(char *filename)
{
MVESTREAM *stream;
// allocate
stream = (MVESTREAM *)vm_malloc(sizeof(MVESTREAM));
// defaults
stream->movie = NULL;
// open
stream->movie = mvefile_open(filename);
if (stream->movie == NULL) {
mve_close(stream);
return NULL;
}
return stream;
}
// close an MVE stream
void mve_close(MVESTREAM *stream)
{
// close MVEFILE
if (stream->movie)
mvefile_close(stream->movie);
stream->movie = NULL;
vm_free(stream);
}
// play next chunk
int mve_play_next_chunk(MVESTREAM *stream)
{
ubyte major, minor;
ubyte *data;
int len;
// loop over segments
major = mvefile_get_next_segment_major(stream->movie);
while (major != 0xff) {
// check whether to handle the segment
if (major < 32) {
minor = mvefile_get_next_segment_minor(stream->movie);
len = mvefile_get_next_segment_size(stream->movie);
data = mvefile_get_next_segment(stream->movie);
switch (major) {
case 0x00:
mve_end_movie();
break;
case 0x01:
mve_end_chunk();
break;
case 0x02:
mve_timer_create(data);
break;
case 0x03:
mve_audio_createbuf(minor, data);
break;
case 0x04:
mve_audio_play();
break;
case 0x05:
if (!mve_video_createbuf(minor, data))
return 0;
break;
case 0x07:
mve_video_display();
break;
case 0x08:
mve_audio_data(major, data);
break;
case 0x09:
mve_audio_data(major, data);
break;
case 0x0a:
if (!mve_video_init(data))
return 0;
break;
case 0x0c:
mve_video_palette(data);
break;
case 0x0f:
mve_video_codemap(data, len);
break;
case 0x11:
mve_video_data(data, len);
break;
default:
break;
}
}
// advance to next segment
mvefile_advance_segment(stream->movie);
major = mvefile_get_next_segment_major(stream->movie);
}
if (!mvefile_fetch_next_chunk(stream->movie))
return 0;
// return status
return 1;
}
Loaded 100 of 1073 files, more files were not shown because too many files have changed in this diff. Show more