Compare commits

..
Author SHA1 Message Date
SirKnightly fff318aeac Automated build commit 2017-06-23 08:16:57 -04:00
715 changed files with 17708 additions and 72330 deletions

No files matched your search

+30 -4
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
@@ -256,7 +286,3 @@ CMakeSettings.json
# Weird files created by Linux
.fuse_hidden*
# This gets ignored by one of the rules above for some reason...
!/code/scripting/lua/LuaConvert.h
!/code/debugconsole/
+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
+3 -37
View File
@@ -4,7 +4,6 @@ dist: trusty
cache:
directories:
- $HOME/cmake
- $HOME/.ccache
addons:
apt:
packages: &global_deps
@@ -17,7 +16,6 @@ addons:
- libjansson-dev
- libsdl2-dev
- valgrind
- qt57base
coverity_scan:
project:
name: "scp-fs2open/fs2open.github.com"
@@ -50,18 +48,11 @@ deploy:
tags: true
- provider: script
script: bash ci/travis/ftp_deploy.sh
script: ci/travis/nightly_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
@@ -71,19 +62,8 @@ matrix:
apt:
sources:
- ubuntu-toolchain-r-test
- sourceline: 'ppa:beineri/opt-qt571-trusty'
packages:
- *global_deps
- g++-5
- os: linux
env: CONFIGURATION="Debug" CC=gcc-7 CXX=g++-7
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- sourceline: 'ppa:beineri/opt-qt571-trusty'
packages:
- g++-7
- *global_deps
- os: linux
env: CONFIGURATION="Debug" CC=clang-3.6 CXX=clang++-3.6
@@ -91,11 +71,10 @@ matrix:
apt:
sources:
- llvm-toolchain-precise
- sourceline: 'ppa:beineri/opt-qt571-trusty'
packages:
- *global_deps
- clang-3.6
- libc++-dev
- *global_deps
- os: osx
env: CONFIGURATION="Debug"
@@ -105,19 +84,8 @@ matrix:
apt:
sources:
- ubuntu-toolchain-r-test
- sourceline: 'ppa:beineri/opt-qt571-trusty'
packages:
- *global_deps
- g++-5
- os: linux
env: CONFIGURATION="Release" CC=gcc-7 CXX=g++-7
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- sourceline: 'ppa:beineri/opt-qt571-trusty'
packages:
- g++-7
- *global_deps
- os: linux
env: CONFIGURATION="Release" CC=clang-3.6 CXX=clang++-3.6
@@ -125,11 +93,10 @@ matrix:
apt:
sources:
- llvm-toolchain-precise
- sourceline: 'ppa:beineri/opt-qt571-trusty'
packages:
- *global_deps
- clang-3.6
- libc++-dev
- *global_deps
- os: osx
env: CONFIGURATION="Release"
before_install:
@@ -145,7 +112,6 @@ install:
- "./ci/travis/install.sh"
- export PATH=$HOME/cmake/bin:$PATH
before_script:
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then QT_ENV_SCRIPT=$(find /opt -name 'qt*-env.sh'); source $QT_ENV_SCRIPT; fi
- "./ci/travis/before_script.sh"
script:
- if [ "$BUILD_DEPLOYMENT" = true ] ; then ./ci/travis/release.sh ; else ./ci/travis/script.sh ; fi
+7 -14
View File
@@ -40,14 +40,6 @@ set(CMAKE_CONFIGURATION_TYPES Debug Release FastDebug CACHE STRING "Available co
PROJECT(FS2_Open)
find_program(CCACHE_PROGRAM ccache)
# Currently only GCC support ccache properly without generating additional warnings
if(CCACHE_PROGRAM AND "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
message(STATUS "Using ccache for compilation: ${CCACHE_PROGRAM}")
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_PROGRAM}")
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK "${CCACHE_PROGRAM}")
endif()
IF(CMAKE_CROSSCOMPILING)
SET(IMPORT_EXE_DIR "IMPORT_EXE_DIR-NOTFOUND" CACHE FILEPATH "Required for a cross compiling build, point to binary directory of a cmake build for the real OS")
INCLUDE(${IMPORT_EXE_DIR}/ImportExecutables.cmake)
@@ -61,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 "")
@@ -93,7 +85,7 @@ OPTION(FSO_BUILD_TESTS "Build unit tests" OFF)
OPTION(FSO_DEVELOPMENT_MODE "Generate binaries in development mode, only use if you know what you're doing!" OFF)
OPTION(FSO_BUILD_QTFRED "Build qtFRED2 binary" OFF)
OPTION(FSO_BUILD_WXFRED2 "Build wxFRED2 binary" OFF)
IF(WIN32 OR APPLE)
# On windows and mac the default should be to always build the included libraries
@@ -155,9 +147,9 @@ IF(FSO_BUILD_FRED2)
ADD_SUBDIRECTORY(fred2)
ENDIF(FSO_BUILD_FRED2)
IF(FSO_BUILD_QTFRED)
ADD_SUBDIRECTORY(qtfred)
ENDIF()
IF(FSO_BUILD_WXFRED2)
ADD_SUBDIRECTORY(wxfred2)
ENDIF(FSO_BUILD_WXFRED2)
if(FSO_BUILD_TESTS)
add_subdirectory(test)
@@ -184,11 +176,12 @@ include(doxygen)
# Print used options to log
IF (WIN32)
message(STATUS "Building FRED2: ${FSO_BUILD_FRED2}")
message(STATUS "Using text to speech: ${FSO_USE_SPEECH}")
message(STATUS "Using voice recogition: ${FSO_USE_VOICEREC}")
elseif(UNIX)
message(STATUS "Building AppImage: ${FSO_BUILD_APPIMAGE}")
ENDIF()
message(STATUS "Building FSO tools: ${FSO_BUILD_TOOLS}")
message(STATUS "Building qtFRED: ${FSO_BUILD_QTFRED}")
message(STATUS "Building wxFRED: ${FSO_BUILD_WXFRED2}")
message(STATUS "Fatal warnings: ${FSO_FATAL_WARNINGS}")
-14
View File
@@ -8,11 +8,9 @@ environment:
- BuildID: 0
CMAKE_GENERATOR: Visual Studio 12 2013
PlatformToolset: v120_xp
QT_DIR: C:\Qt\5.7\msvc2013
- BuildID: 1
CMAKE_GENERATOR: Visual Studio 14 2015 Win64
PlatformToolset: v140_xp
QT_DIR: C:\Qt\5.7\msvc2015_64
before_build:
- git submodule update --init --recursive
build_script:
@@ -49,15 +47,3 @@ deploy:
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
+5 -42
View File
@@ -4,8 +4,6 @@ class BuildConfig {
[string]$PackageType
[string]$Toolset
[string]$SimdType
[string]$QtDir
[Bool]$SourcePackage
}
$NightlyConfigurations = @(
@@ -14,16 +12,12 @@ $NightlyConfigurations = @(
PackageType="Win64";
Toolset="v140_xp";
SimdType="SSE2";
QtDir="C:\Qt\5.7\msvc2015_64";
SourcePackage=$false;
},
[BuildConfig]@{
Generator="Visual Studio 14 2015";
PackageType="Win32";
Toolset="v140_xp";
SimdType="SSE2";
QtDir="C:\Qt\5.7\msvc2015";
SourcePackage=$false;
}
)
$ReleaseConfigurations = @(
@@ -32,32 +26,24 @@ $ReleaseConfigurations = @(
PackageType="Win32";
Toolset="v140_xp";
SimdType="SSE2";
QtDir="C:\Qt\5.7\msvc2015";
SourcePackage=$true;
}
[BuildConfig]@{
Generator="Visual Studio 14 2015";
PackageType="Win32-AVX";
Toolset="v140_xp";
SimdType="AVX";
QtDir="C:\Qt\5.7\msvc2015";
SourcePackage=$false;
}
[BuildConfig]@{
Generator="Visual Studio 14 2015 Win64";
PackageType="Win64";
Toolset="v140_xp";
SimdType="SSE2";
QtDir="C:\Qt\5.7\msvc2015_64";
SourcePackage=$false;
}
[BuildConfig]@{
Generator="Visual Studio 14 2015 Win64";
PackageType="Win64-AVX";
Toolset="v140_xp";
SimdType="AVX";
QtDir="C:\Qt\5.7\msvc2015_64";
SourcePackage=$false;
}
)
@@ -66,21 +52,16 @@ $BuildConfigurations = $null
# Default values
$ReleaseBuild = $false
$NightlyBuild = $false
$TestBuild = $false
$DeployBuild = $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_(.*)"))) {
if ([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_(.*)"))) {
if ([System.Convert]::ToBoolean($env:APPVEYOR_REPO_TAG) -And ("$env:APPVEYOR_REPO_TAG_NAME" -match "^nightly_(.*)")) {
# Tag matches
$NightlyBuild = $true
$PackageName = "nightly_$($matches[1])"
@@ -88,31 +69,19 @@ if ($NightlyTest -Or ([System.Convert]::ToBoolean($env:APPVEYOR_REPO_TAG) -And (
$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
}
Write-Host "$buildID"
$DeployBuild = $false
if ($ReleaseBuild -Or $NightlyBuild -Or $TestBuild) {
if ($ReleaseBuild -Or $NightlyBuild) {
$DeployBuild = $true
}
Set-AppveyorBuildVariable 'ReleaseBuild' "$ReleaseBuild"
Set-AppveyorBuildVariable 'NightlyBuild' "$NightlyBuild"
Set-AppveyorBuildVariable 'TestBuild' "$TestBuild"
New-Item build -type directory
Set-Location -Path build
@@ -125,11 +94,6 @@ if ($DeployBuild) {
}
$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)" `
@@ -148,7 +112,6 @@ if ($DeployBuild) {
Push-AppveyorArtifact "$($PackageName)-builds-$($buildConfig.PackageType).zip"
} else {
cmake -DFSO_USE_SPEECH="ON" -DFSO_FATAL_WARNINGS="ON" -DFSO_USE_VOICEREC="ON" -DFSO_BUILD_TESTS="ON" -DMSVC_SIMD_INSTRUCTIONS=SSE2 `
-DFSO_BUILD_QTFRED=ON -DQT5_INSTALL_ROOT="$env:QT_DIR" -DFSO_BUILD_FRED2="OFF" `
-G "$Env:CMAKE_GENERATOR" -T "$Env:PlatformToolset" ..
cmake --build . --config "$Env:CONFIGURATION" -- /verbosity:minimal
+15 -2
View File
@@ -1,8 +1,21 @@
if ([System.Convert]::ToBoolean($env:ReleaseBuild) -Or [System.Convert]::ToBoolean($env:NightlyBuild) -Or [System.Convert]::ToBoolean($env:TestBuild)) {
if ([System.Convert]::ToBoolean($env:ReleaseBuild) -Or [System.Convert]::ToBoolean($env:NightlyBuild)) {
# Skip tests for deployment
exit 0
} else {
} else {
# Appveyor doesn't have OpenAL so copy our DLLs to the output FOLDER
$arch=""
if ($Env:CMAKE_GENERATOR -Match "Win64") {
$arch="win64"
} else {
$arch="win32"
}
$dllPath = "$Env:APPVEYOR_BUILD_FOLDER\lib\openal\libs\$arch\OpenAL32.dll"
$copyDestination = "$pwd\bin\$Env:CONFIGURATION\"
write "Copying OpenAL DLL..."
Copy-Item "$dllPath" "$copyDestination"
write "Running unit tests..."
# Run unit tests
&"$pwd\bin\$Env:CONFIGURATION\unittests.exe" --gtest_shuffle 2>&1
+1 -6
View File
@@ -6,11 +6,6 @@ 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"
@@ -32,7 +27,7 @@ if [ "$TRAVIS_OS_NAME" = "linux" ]; then
cd ..
done
else
eval $CMAKE -DCMAKE_BUILD_TYPE=$CONFIGURATION -DFSO_BUILD_TESTS=ON -DFSO_BUILD_INCLUDED_LIBS=ON -DFSO_BUILD_QTFRED=ON ..
eval $CMAKE -DCMAKE_BUILD_TYPE=$CONFIGURATION -DFSO_BUILD_TESTS=ON -DFSO_BUILD_INCLUDED_LIBS=ON ..
fi
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
if [ "$BUILD_DEPLOYMENT" = true ]; then
+2 -21
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,12 +9,10 @@ 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
echo "This is a release tag!";
@@ -29,27 +25,13 @@ if [ "$NIGHTLY_TEST" = true ] || [[ "$TRAVIS_TAG" =~ $NIGHTLY_PATTERN ]]; then
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-5.*$ ]])); then
if ([ "$TRAVIS_OS_NAME" = "linux" ] && (! [[ "$CC" =~ ^gcc.*$ ]])); then
echo "Skipping non-release compiler";
exit 0;
fi
@@ -62,7 +44,6 @@ fi
export RELEASE_BUILD
export NIGHTLY_BUILD
export TEST_BUILD
export BUILD_DEPLOYMENT
export BUILD_CONFIGS
export VERSION_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
+14
View File
@@ -0,0 +1,14 @@
#!/usr/bin/env sh
set -e
set -u
cd /tmp/builds
for file in *; do
# Upload to indiegames
curl -k "ftp://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
done
+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";
Vendored Submodule
+1
Submodule cmake/external/cotire added at 40a46bf2fb.
-4054
View File
File diff suppressed because it is too large. Load diff
-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)
+2 -5
View File
@@ -15,9 +15,9 @@ 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")
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
set(CMAKE_REQUIRED_FLAGS "-std=c++11") # required for g++ <= 5
endif()
endif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
set(CMAKE_EXTRA_INCLUDE_FILES "cstddef")
CHECK_TYPE_SIZE("std::max_align_t" STD_MAX_ALIGN_T LANGUAGE CXX)
@@ -25,9 +25,6 @@ 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)
-4
View File
@@ -9,7 +9,6 @@
#cmakedefine HAVE_STD_MAX_ALIGN_T
#cmakedefine HAVE_STD_IS_TRIVIALLY_COPYABLE
#cmakedefine HAVE_STD_IS_TRIVIALLY_COPYABLE_ARRAY
#cmakedefine01 IS_64BIT
@@ -22,7 +21,4 @@
#cmakedefine01 HAVE_STRINGS_H
#cmakedefine01 HAVE_CHAR32_T
#cmakedefine01 HAVE_UNICODE_CHAR_LITERAL
#endif // __PLATFORM_CHECKS_H__
+1 -3
View File
@@ -33,9 +33,7 @@ set(WARNING_FLAGS
/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
)
target_compile_options(compiler INTERFACE ${WARNING_FLAGS})
@@ -90,7 +88,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)
-28
View File
@@ -195,31 +195,3 @@ function(suppress_warnings _target)
target_compile_options(${_target} PRIVATE "-w")
endif()
endfunction(suppress_warnings)
function(list_target_dependencies _target _out_var)
set(out_list)
set(work_libs ${_target})
list(LENGTH work_libs libs_length)
while(libs_length GREATER 0)
list(GET work_libs 0 current)
list(REMOVE_AT work_libs 0)
list(APPEND out_list ${current})
get_target_property(current_libs ${current} INTERFACE_LINK_LIBRARIES)
if(current_libs)
foreach(lib ${current_libs})
if (TARGET ${lib})
list(APPEND work_libs ${lib})
endif (TARGET ${lib})
endforeach(lib)
endif(current_libs)
list(LENGTH work_libs libs_length)
endwhile(libs_length GREATER 0)
list(REMOVE_DUPLICATES out_list)
set(${_out_var} ${out_list} PARENT_SCOPE)
endfunction(list_target_dependencies)
+2 -2
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)
+3 -3
View File
@@ -21,7 +21,7 @@ TARGET_INCLUDE_DIRECTORIES(code PUBLIC ${GENERATED_SOURCE_DIR}/code)
target_link_libraries(code PUBLIC OpenGL)
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})
@@ -30,8 +30,6 @@ TARGET_LINK_LIBRARIES(code PUBLIC sdl2)
TARGET_LINK_LIBRARIES(code PUBLIC ffmpeg)
TARGET_LINK_LIBRARIES(code PUBLIC utfcpp)
TARGET_LINK_LIBRARIES(code PUBLIC platform)
TARGET_LINK_LIBRARIES(code PUBLIC compiler)
@@ -60,6 +58,8 @@ set_target_properties(code PROPERTIES COTIRE_CXX_PREFIX_HEADER_INIT "prefix_head
include(util)
configure_cotire(code)
include(../cmake/Cxx11.cmake)
# 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")
+1 -2
View File
@@ -498,8 +498,7 @@ void parse_ai_profiles_tbl(const char *filename)
}
// find next valid option
if (!skip_to_start_of_string_either("$", "#"))
break;
skip_to_start_of_string_either("$", "#");
saved_Mp = Mp;
}
}
+6 -14
View File
@@ -3814,7 +3814,7 @@ float ai_path_0()
int path_num;
Assert(aip->active_goal >= 0);
ai_goal *aigp = &aip->goals[aip->active_goal];
Assert(aigp->flags[AI::Goal_Flags::Dockee_index_valid] && aigp->flags[AI::Goal_Flags::Docker_index_valid]);
Assert(aigp->flags[AI::Goal_Flags::Dockee_index_valid] || aigp->flags[AI::Goal_Flags::Docker_index_valid]);
path_num = ai_return_path_num_from_dockbay(&Objects[aip->goal_objnum], aigp->dockee.index);
ai_find_path(Pl_objp, aip->goal_objnum, path_num, 0);
@@ -3957,7 +3957,7 @@ float ai_path_1()
int path_num;
Assert(aip->active_goal >= 0);
ai_goal *aigp = &aip->goals[aip->active_goal];
Assert(aigp->flags[AI::Goal_Flags::Dockee_index_valid] && aigp->flags[AI::Goal_Flags::Docker_index_valid]);
Assert(aigp->flags[AI::Goal_Flags::Dockee_index_valid] || aigp->flags[AI::Goal_Flags::Docker_index_valid]);
path_num = ai_return_path_num_from_dockbay(&Objects[aip->goal_objnum], aigp->dockee.index);
ai_find_path(Pl_objp, aip->goal_objnum, path_num, 0);
@@ -10395,12 +10395,11 @@ void ai_get_dock_goal_indexes(object *objp, ai_info *aip, ai_goal *aigp, object
case AIS_DOCK_2:
case AIS_DOCK_3:
Warning(LOCATION, "Normally dock indexes should be calculated for only AIS_DOCK_0 and AIS_UNDOCK_0. Trace out and debug.");
FALLTHROUGH;
case AIS_DOCK_0:
{
// get them from the active goal
Assert(aigp != NULL);
Assert(aigp->flags[AI::Goal_Flags::Dockee_index_valid] && aigp->flags[AI::Goal_Flags::Docker_index_valid]);
Assert(aigp->flags[AI::Goal_Flags::Dockee_index_valid] || aigp->flags[AI::Goal_Flags::Docker_index_valid]);
docker_index = aigp->docker.index;
dockee_index = aigp->dockee.index;
Assert(docker_index >= 0);
@@ -10413,7 +10412,6 @@ void ai_get_dock_goal_indexes(object *objp, ai_info *aip, ai_goal *aigp, object
case AIS_UNDOCK_1:
case AIS_UNDOCK_2:
Warning(LOCATION, "Normally dock indexes should be calculated for only AIS_DOCK_0 and AIS_UNDOCK_0. Trace out and debug.");
FALLTHROUGH;
case AIS_UNDOCK_0:
{
// get them from the guy I'm docked to
@@ -10480,11 +10478,9 @@ void ai_cleanup_dock_mode_subjective(object *objp)
case AIS_UNDOCK_0:
model_anim_start_type(shipp, TRIGGER_TYPE_DOCKED, docker_index, -1);
model_anim_start_type(goal_shipp, TRIGGER_TYPE_DOCKED, dockee_index, -1);
FALLTHROUGH;
case AIS_UNDOCK_1:
model_anim_start_type(shipp, TRIGGER_TYPE_DOCKING_STAGE_3, docker_index, -1);
model_anim_start_type(goal_shipp, TRIGGER_TYPE_DOCKING_STAGE_3, dockee_index, -1);
FALLTHROUGH;
case AIS_UNDOCK_2:
model_anim_start_type(shipp, TRIGGER_TYPE_DOCKING_STAGE_2, docker_index, -1);
model_anim_start_type(goal_shipp, TRIGGER_TYPE_DOCKING_STAGE_2, dockee_index, -1);
@@ -10494,11 +10490,9 @@ void ai_cleanup_dock_mode_subjective(object *objp)
case AIS_DOCK_4A:
model_anim_start_type(shipp, TRIGGER_TYPE_DOCKED, docker_index, -1);
model_anim_start_type(goal_shipp, TRIGGER_TYPE_DOCKED, dockee_index, -1);
FALLTHROUGH;
case AIS_DOCK_3:
model_anim_start_type(shipp, TRIGGER_TYPE_DOCKING_STAGE_3, docker_index, -1);
model_anim_start_type(goal_shipp, TRIGGER_TYPE_DOCKING_STAGE_3, dockee_index, -1);
FALLTHROUGH;
case AIS_DOCK_2:
model_anim_start_type(shipp, TRIGGER_TYPE_DOCKING_STAGE_2, docker_index, -1);
model_anim_start_type(goal_shipp, TRIGGER_TYPE_DOCKING_STAGE_2, dockee_index, -1);
@@ -10839,7 +10833,7 @@ void ai_dock()
if (aip->submode == AIS_DOCK_3) {
// Play a ship docking attach sound
snd_play_3d( gamesnd_get_game_sound(SND_DOCK_ATTACH), &Pl_objp->pos, &View_position );
snd_play_3d( &Snds[SND_DOCK_ATTACH], &Pl_objp->pos, &View_position );
// start the dock animation
model_anim_start_type(shipp, TRIGGER_TYPE_DOCKED, docker_index, 1);
@@ -10966,7 +10960,7 @@ void ai_dock()
ai_find_path(Pl_objp, OBJ_INDEX(goal_objp), path_num, 0);
// Play a ship docking detach sound
snd_play_3d( gamesnd_get_game_sound(SND_DOCK_DETACH), &Pl_objp->pos, &View_position );
snd_play_3d( &Snds[SND_DOCK_DETACH], &Pl_objp->pos, &View_position );
aip->submode = AIS_UNDOCK_1;
aip->submode_start_time = Missiontime;
@@ -10986,7 +10980,7 @@ void ai_dock()
// play the depart sound, but only once, since this mode is called multiple times per frame
if ( !(aigp->flags[AI::Goal_Flags::Depart_sound_played]))
{
snd_play_3d( gamesnd_get_game_sound(SND_DOCK_DEPART), &Pl_objp->pos, &View_position );
snd_play_3d( &Snds[SND_DOCK_DEPART], &Pl_objp->pos, &View_position );
aigp->flags.set(AI::Goal_Flags::Depart_sound_played);
}
@@ -12382,7 +12376,6 @@ void ai_maybe_evade_locked_missile(object *objp, ai_info *aip)
case AIM_DOCK: // Ships in dock mode can evade iif they are not currently repairing or docked.
if (object_is_docked(objp) || (aip->ai_flags[AI::AI_Flags::Repairing, AI::AI_Flags::Being_repaired]))
break;
FALLTHROUGH;
case AIM_GUARD:
// If in guard mode and far away from guard object, don't pursue guy that hit me.
if ((aip->guard_objnum != -1) && (aip->guard_signature == Objects[aip->guard_objnum].signature)) {
@@ -12390,7 +12383,6 @@ void ai_maybe_evade_locked_missile(object *objp, ai_info *aip)
return;
}
}
FALLTHROUGH;
case AIM_EVADE:
case AIM_GET_BEHIND:
case AIM_STAY_NEAR:
+2 -2
View File
@@ -2051,7 +2051,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 );
}
}
}
@@ -2138,7 +2138,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 );
}
}
+1 -1
View File
@@ -765,7 +765,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);
+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(const 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();
+3 -7
View File
@@ -1312,7 +1312,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 +1568,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
+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 );
+32 -191
View File
@@ -24,7 +24,6 @@
#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"
@@ -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;
@@ -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;
@@ -878,7 +871,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 +942,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 +967,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 +989,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 +1022,6 @@ void bm_init() {
bm_free_data(i); // clears flags, bbp, data, etc
}
bm_inited = true;
}
int bm_is_compressed(int num) {
@@ -1213,7 +1203,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 +1509,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)
@@ -1709,8 +1701,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 +1787,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;
@@ -1914,15 +1873,14 @@ int bm_load_sub_slow(const char *real_filename, const int num_ext, const char **
char full_path[MAX_PATH];
size_t size = 0, offset = 0;
int rval = -1;
const void* file_data = nullptr;
rval = cf_find_file_location_ext(real_filename, num_ext, ext_list, dir_type, sizeof(full_path) - 1, full_path, &size, &offset, 0, &file_data);
rval = cf_find_file_location_ext(real_filename, num_ext, ext_list, dir_type, sizeof(full_path) - 1, full_path, &size, &offset, 0);
// could not be found, or is invalid for some reason
if ((rval < 0) || (rval >= num_ext))
return -1;
CFILE *test = cfopen_special(full_path, "rb", size, offset, file_data, dir_type);
CFILE *test = cfopen_special(full_path, "rb", size, offset, dir_type);
if (test != NULL) {
if (img_cfp != NULL)
@@ -1939,7 +1897,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;
@@ -2281,9 +2239,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
@@ -2344,7 +2299,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));
@@ -2423,7 +2378,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);
@@ -2508,7 +2463,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--) {
@@ -2881,16 +2837,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;
@@ -2939,7 +2891,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))
@@ -3119,7 +3072,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;
}
@@ -3249,7 +3205,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;
@@ -3305,118 +3261,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 (handle == -1) {
if (num_frames != nullptr) {
*num_frames = 0;
}
return -1;
}
// 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;
}
bool bm_validate_filename(const SCP_string& file, bool single_frame, bool animation) {
Assertion(single_frame || animation, "At least one of single_frame or animation must be true!");
if (!VALID_FNAME(file.c_str())) {
return false;
}
int handle = -1;
if (single_frame && animation) {
// Caller has indicated that single frames and animations are valid
handle = bm_load_either(file.c_str());
} else if (single_frame) {
handle = bm_load(file);
} else {
handle = bm_load_animation(file.c_str());
}
if (handle != -1) {
bm_release(handle);
return true;
}
return false;
}
SDL_Surface* bm_to_sdl_surface(int handle) {
Assertion(bm_is_valid(handle), "%d is no valid bitmap handle!", handle);
int w;
int h;
bm_get_info(handle, &w, &h, nullptr, nullptr);
Uint32 rmask, gmask, bmask, amask;
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
rmask = 0x0000ff00;
gmask = 0x00ff0000;
bmask = 0xff000000;
amask = 0x000000ff;
#else
rmask = 0x00ff0000;
gmask = 0x0000ff00;
bmask = 0x000000ff;
amask = 0xff000000;
#endif
SDL_Surface* bitmapSurface = SDL_CreateRGBSurface(0, w, h, 32, rmask, gmask, bmask, amask);
if (SDL_LockSurface(bitmapSurface) < 0) {
return nullptr;
}
bitmap* bmp = bm_lock(handle, 32, BMP_TEX_XPARENT);
memcpy(bitmapSurface->pixels, reinterpret_cast<void*>(bmp->data), static_cast<size_t>(w * h * 4));
bm_unlock(handle);
SDL_UnlockSurface(bitmapSurface);
return bitmapSurface;
}
+2 -62
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,61 +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();
/**
* @brief Checks if the given filename is a valid effect or texture file name
*
* @note At least one of @c single_frame or @c animation must be true since the result would make no sense otherwise. It
* is also valid to set both parmeters to @c true.
*
* @todo This currently just tries to load the file but could be improved by not actually loading the file in the future.
*
* @param file The file name to check
* @param single_frame If set to @c true then single frames are valid files
* @param animation If set to @c true then animations are valid files
* @return @c true if the file name is valid, @c false otherwise
*/
bool bm_validate_filename(const SCP_string& file, bool single_frame, bool animation);
SDL_Surface* bm_to_sdl_surface(int handle);
#endif
+1 -1
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"
+35 -67
View File
@@ -88,7 +88,6 @@ cf_pathtype Pathtypes[CF_MAX_PATH_TYPES] = {
{ 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 },
};
@@ -110,7 +109,6 @@ static const char *Cfile_cdrom_dir = NULL;
static int cfget_cfile_block();
static CFILE *cf_open_fill_cfblock(const char* source, int line, FILE * fp, int type);
static CFILE *cf_open_packed_cfblock(const char* source, int line, FILE *fp, int type, size_t offset, size_t size);
static CFILE *cf_open_memory_fill_cfblock(const char* source, int line, const void* data, size_t size, int dir_type);
#if defined _WIN32
static CFILE *cf_open_mapped_fill_cfblock(const char* source, int line, HANDLE hFile, int type);
@@ -765,16 +763,16 @@ CFILE *_cfopen(const char* source, int line, const char *file_path, const char *
char copy_file_path[MAX_PATH_LEN]; // FIX change in memory from cf_find_file_location
strcpy_s(copy_file_path, file_path);
const void* file_data = nullptr;
if ( cf_find_file_location( copy_file_path, dir_type, sizeof(longname) - 1, longname, &size, &offset, localize, &file_data ) ) {
if ( cf_find_file_location( copy_file_path, dir_type, sizeof(longname) - 1, longname, &size, &offset, localize ) ) {
// Fount it, now create a cfile out of it
nprintf(("CFileDebug", "Requested file %s found at: %s\n", file_path, longname));
if ( type & CFILE_MEMORY_MAPPED ) {
// Can't open memory mapped files out of pack or memory files
if ( offset == 0 && file_data != nullptr ) {
// Can't open memory mapped files out of pack files
if ( offset == 0 ) {
#if defined _WIN32
HANDLE hFile;
@@ -792,8 +790,18 @@ CFILE *_cfopen(const char* source, int line, const char *file_path, const char *
}
} else {
// since cfopen_special already has all the code to handle the opening we can just use that here
return _cfopen_special(source, line, longname, mode, size, offset, file_data, dir_type);
FILE *fp = fopen( longname, "rb" );
if ( fp ) {
if ( offset ) {
// Found it in a pack file
return cf_open_packed_cfblock(source, line, fp, dir_type, offset, size );
} else {
// Found it in a normal file
return cf_open_fill_cfblock(source, line, fp, dir_type);
}
}
}
}
@@ -812,7 +820,7 @@ CFILE *_cfopen(const char* source, int line, const char *file_path, const char *
// returns: success ==> address of CFILE structure
// error ==> NULL
//
CFILE *_cfopen_special(const char* source, int line, const char *file_path, const char *mode, const size_t size, const size_t offset, const void* data, int dir_type)
CFILE *_cfopen_special(const char* source, int line, const char *file_path, const char *mode, const size_t size, const size_t offset, int dir_type)
{
if ( !cfile_inited) {
Int3();
@@ -828,27 +836,19 @@ CFILE *_cfopen_special(const char* source, int line, const char *file_path, cons
return NULL;
}
// In-Memory files are a bit different from normal files so we need to handle them separately
if (data != nullptr) {
return cf_open_memory_fill_cfblock(source, line, data, size, dir_type);
}
else {
// "file_path" should already be a fully qualified path, so just try to open it
FILE *fp = fopen(file_path, "rb");
// "file_path" should already be a fully qualified path, so just try to open it
FILE *fp = fopen( file_path, "rb" );
if (fp) {
if (offset) {
// Found it in a pack file
return cf_open_packed_cfblock(source, line, fp, dir_type, offset, size);
}
else {
// Found it in a normal file
return cf_open_fill_cfblock(source, line, fp, dir_type);
}
}
}
if ( !fp )
return NULL;
return NULL;
if ( offset ) {
// it's in a pack file
return cf_open_packed_cfblock(source, line, fp, dir_type, offset, size);
} else {
// it's a normal file
return cf_open_fill_cfblock(source, line, fp, dir_type);
}
}
@@ -922,7 +922,7 @@ int cfclose( CFILE * cfile )
cb = &Cfile_block_list[cfile->id];
result = 0;
if ( cb->data && cb->mem_mapped ) {
if ( cb->data ) {
// close memory mapped file
#if defined _WIN32
result = UnmapViewOfFile((void*)cb->data);
@@ -936,8 +936,7 @@ int cfclose( CFILE * cfile )
// FIXME: result is wrong after munmap() but it is successful
//result = munmap(cb->data, cb->data_length);
//Assert(result);
// This const_cast is safe since the pointer returned by mmap was also non-const
munmap(const_cast<void*>(cb->data), cb->data_length);
munmap(cb->data, cb->data_length);
if ( cb->fp != NULL)
result = fclose(cb->fp);
#endif
@@ -997,7 +996,6 @@ static CFILE *cf_open_fill_cfblock(const char* source, int line, FILE *fp, int t
cfp->id = cfile_block_index;
cfp->version = 0;
cfbp->data = NULL;
cfbp->mem_mapped = false;
cfbp->fp = fp;
cfbp->dir_type = type;
cfbp->max_read_len = 0;
@@ -1040,7 +1038,6 @@ static CFILE *cf_open_packed_cfblock(const char* source, int line, FILE *fp, int
cfp->version = 0;
cfbp->data = NULL;
cfbp->fp = fp;
cfbp->mem_mapped = false;
cfbp->dir_type = type;
cfbp->max_read_len = 0;
@@ -1086,7 +1083,6 @@ static CFILE *cf_open_mapped_fill_cfblock(const char* source, int line, FILE *fp
cfp->version = 0;
cfbp->max_read_len = 0;
cfbp->fp = NULL;
cfbp->mem_mapped = true;
#if defined _WIN32
cfbp->hInFile = hFile;
#endif
@@ -1121,37 +1117,6 @@ static CFILE *cf_open_mapped_fill_cfblock(const char* source, int line, FILE *fp
}
}
static CFILE *cf_open_memory_fill_cfblock(const char* source, int line, const void* data, size_t size, int dir_type)
{
int cfile_block_index;
cfile_block_index = cfget_cfile_block();
if ( cfile_block_index == -1 ) {
return NULL;
}
else {
CFILE *cfp;
Cfile_block *cfbp;
cfbp = &Cfile_block_list[cfile_block_index];
cfp = &Cfile_list[cfile_block_index];
cfp->id = cfile_block_index;
cfp->version = 0;
cfbp->max_read_len = 0;
cfbp->fp = NULL;
cfbp->mem_mapped = false;
cfbp->dir_type = dir_type;
cfbp->source_file = source;
cfbp->line_num = line;
cf_init_lowlevel_read_code(cfp, 0, size, 0 );
cfbp->data = data;
return cfp;
}
}
int cf_get_dir_type(CFILE *cfile)
{
return Cfile_block_list[cfile->id].dir_type;
@@ -1162,7 +1127,7 @@ int cf_get_dir_type(CFILE *cfile)
//
//
const void *cf_returndata(CFILE *cfile)
void *cf_returndata(CFILE *cfile)
{
Assert(cfile != NULL);
Cfile_block *cb;
@@ -1453,7 +1418,9 @@ int cfilelength( CFILE * cfile )
cb = &Cfile_block_list[cfile->id];
// TODO: return length of memory mapped file
Assert( !cb->mem_mapped );
Assert( !cb->data );
Assert(cb->fp != NULL);
// cb->size gets set at cfopen
@@ -1552,6 +1519,7 @@ int cfputc(int c, CFILE *cfile)
return result;
}
// cfputs() writes a string to a file
//
// returns: success ==> non-negative value
+8 -9
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
@@ -140,7 +139,7 @@ CFILE *_cfopen(const char* source_file, int line, const char *filename, const ch
// like cfopen(), but it accepts a fully qualified path only (ie, the result of a cf_find_file_location() call)
// NOTE: only supports reading files!!
CFILE *_cfopen_special(const char* source_file, int line, const char *file_path, const char *mode,
const size_t size, const size_t offset, const void* data, int dir_type = CF_TYPE_ANY);
const size_t size, const size_t offset, int dir_type = CF_TYPE_ANY);
#define cfopen_special(...) _cfopen_special(LOCATION, __VA_ARGS__) // Pass source location to the function
// Flush the open file buffer
@@ -198,9 +197,9 @@ int cfwrite_compressed(void *param_buf, int param_elsize, int param_nelem, CFILE
int cfseek(CFILE *fp, int offset, int where);
// Returns current position of file.
int cftell(CFILE *fp);
// cfputc() writes a character to a file
int cftell(CFILE *fp);
// cfputc() writes a character to a file
int cfputc(int c, CFILE *cfile);
// cfputs() writes a string to a file
@@ -216,7 +215,7 @@ char *cfgets(char *buf, int n, CFILE *cfile);
int cfeof(CFILE *cfile);
// Return the data pointer associated with the CFILE structure (for memory mapped files)
const void *cf_returndata(CFILE *cfile);
void *cf_returndata(CFILE *cfile);
// get the 2 byte checksum of the passed filename - return 0 if operation failed, 1 if succeeded
int cf_chksum_short(const char *filename, ushort *chksum, int max_size = -1, int cf_type = CF_TYPE_ANY );
@@ -326,7 +325,7 @@ void cf_sort_filenames( SCP_vector<SCP_string> &list, int sort, SCP_vector<file_
// size - File size
// offset - Offset into pack file. 0 if not a packfile.
// Returns: If not found returns 0.
int cf_find_file_location( const char *filespec, int pathtype, int max_out, char *pack_filename, size_t *size, size_t *offset, bool localize = false, const void** data_out = nullptr);
int cf_find_file_location( const char *filespec, int pathtype, int max_out, char *pack_filename, size_t *size, size_t *offset, bool localize = false);
// Searches for a file. Follows all rules and precedence and searches
// CD's and pack files. Searches all locations in order for first filename using ext filter list.
@@ -340,7 +339,7 @@ int cf_find_file_location( const char *filespec, int pathtype, int max_out, char
// offset - Offset into pack file. 0 if not a packfile.
// Returns: If not found returns -1, else returns offset into ext_list.
// (NOTE: This function is exponentially slow, so don't use it unless truely needed!!)
int cf_find_file_location_ext(const char *filename, const int ext_num, const char **ext_list, int pathtype, int max_out = 0, char *pack_filename = NULL, size_t *size = NULL, size_t *offset = NULL, bool localize = false, const void** data_out = nullptr);
int cf_find_file_location_ext(const char *filename, const int ext_num, const char **ext_list, int pathtype, int max_out = 0, char *pack_filename = NULL, size_t *size = NULL, size_t *offset = NULL, bool localize = false);
// Functions to change directories
int cfile_chdir(const char *dir);
+38 -56
View File
@@ -74,13 +74,18 @@ int cfeof(CFILE *cfile)
Assert(cfile->id >= 0 && cfile->id < MAX_CFILE_BLOCKS);
cb = &Cfile_block_list[cfile->id];
int result = 0;
int result;
result = 0;
// cfeof() not supported for memory-mapped files
Assert( !cb->data );
Assert(cb->fp != NULL);
#if defined(CHECK_POSITION) && !defined(NDEBUG)
if (cb->fp) {
auto raw_position = ftell(cb->fp) - cb->lib_offset;
Assert(raw_position == cb->raw_position);
}
auto raw_position = ftell(cb->fp) - cb->lib_offset;
Assert(raw_position == cb->raw_position);
#endif
if (cb->raw_position >= cb->size ) {
@@ -104,11 +109,14 @@ int cftell( CFILE * cfile )
Assert(cfile->id >= 0 && cfile->id < MAX_CFILE_BLOCKS);
cb = &Cfile_block_list[cfile->id];
// Doesn't work for memory mapped files
Assert( !cb->data );
Assert(cb->fp != NULL);
#if defined(CHECK_POSITION) && !defined(NDEBUG)
if (cb->fp) {
auto raw_position = ftell(cb->fp) - cb->lib_offset;
Assert(raw_position == cb->raw_position);
}
auto raw_position = ftell(cb->fp) - cb->lib_offset;
Assert(raw_position == cb->raw_position);
#endif
// The rest of the code still uses ints, do an overflow check to detect cases where this fails
@@ -133,7 +141,8 @@ int cfseek( CFILE *cfile, int offset, int where )
// TODO: seek to offset in memory mapped file
Assert( !cb->mem_mapped );
Assert( !cb->data );
Assert( cb->fp != NULL );
size_t goal_position;
@@ -157,22 +166,14 @@ int cfseek( CFILE *cfile, int offset, int where )
// 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 = 0;
if (cb->fp) {
// If we have a file pointer we can also seek in that file
result = fseek(cb->fp, (long)goal_position, SEEK_SET );
Assertion(goal_position >= cb->lib_offset, "Invalid offset values detected while seeking! Goal was " SIZE_T_ARG ", lib_offset is " SIZE_T_ARG ".", goal_position, cb->lib_offset);
}
// If we only have a data pointer this will do all the work
int result = fseek(cb->fp, (long)goal_position, SEEK_SET );
Assertion(goal_position >= cb->lib_offset, "Invalid offset values detected while seeking! Goal was " SIZE_T_ARG ", lib_offset is " SIZE_T_ARG ".", goal_position, cb->lib_offset);
cb->raw_position = goal_position - cb->lib_offset;
Assertion(cb->raw_position <= cb->size, "Invalid raw_position value detected!");
#if defined(CHECK_POSITION) && !defined(NDEBUG)
if (cb->fp) {
auto tmp_offset = ftell(cb->fp) - cb->lib_offset;
Assert(tmp_offset == cb->raw_position);
}
auto tmp_offset = ftell(cb->fp) - cb->lib_offset;
Assert(tmp_offset==cb->raw_position);
#endif
return result;
@@ -196,6 +197,13 @@ int cfread(void *buf, int elsize, int nelem, CFILE *cfile)
Cfile_block *cb = &Cfile_block_list[cfile->id];
// cfread() not supported for memory-mapped files
if(cb->data != NULL)
{
Warning(LOCATION, "Writing is not supported for mem-mapped files");
return 0;
}
if ( (cb->raw_position+size) > cb->size ) {
Assertion(cb->raw_position <= cb->size, "Invalid raw_position value detected!");
size = cb->size - cb->raw_position;
@@ -214,24 +222,15 @@ int cfread(void *buf, int elsize, int nelem, CFILE *cfile)
}
}
size_t bytes_read;
if (cb->data != nullptr) {
// This is a file from memory
bytes_read = size;
memcpy(buf, reinterpret_cast<const char*>(cb->data) + cb->raw_position, size);
} else {
bytes_read = fread( buf, 1, size, cb->fp );
}
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)
if (cb->fp) {
auto tmp_offset = ftell(cb->fp) - cb->lib_offset;
Assert(tmp_offset==cb->raw_position);
}
auto tmp_offset = ftell(cb->fp) - cb->lib_offset;
Assert(tmp_offset==cb->raw_position);
#endif
return (int)(bytes_read / elsize);
@@ -255,31 +254,14 @@ int cfread_lua_number(double *buf, CFILE *cfile)
return 0;
}
size_t advance = 0;
int items_read;
if (cb->fp) {
long orig_pos = ftell(cb->fp);
items_read = fscanf(cb->fp, LUA_NUMBER_SCAN, buf);
advance = (size_t) (ftell(cb->fp)-orig_pos);
} else {
int read;
// %n returns the number of bytes currently read so we append that to the scan format at the end so it will return
// how many bytes we have consumed
items_read = sscanf(reinterpret_cast<const char*>(cb->data), LUA_NUMBER_SCAN "%n", buf, &read);
if (items_read == 2) {
// We need to correct the items read counter since we read one additional item
items_read = 1;
}
advance = (size_t) read;
}
cb->raw_position += advance;
long orig_pos = ftell(cb->fp);
int items_read = fscanf(cb->fp, LUA_NUMBER_SCAN, buf);
cb->raw_position += ftell(cb->fp)-orig_pos;
Assertion(cb->raw_position <= cb->size, "Invalid raw_position value detected!");
#if defined(CHECK_POSITION) && !defined(NDEBUG)
if (cb->fp) {
auto tmp_offset = ftell(cb->fp) - cb->lib_offset;
Assert(tmp_offset==cb->raw_position);
}
auto tmp_offset = ftell(cb->fp) - cb->lib_offset;
Assert(tmp_offset==cb->raw_position);
#endif
return items_read;
+1 -2
View File
@@ -26,8 +26,7 @@ typedef struct Cfile_block {
int type; // CFILE_BLOCK_UNUSED, CFILE_BLOCK_USED
int dir_type; // directory location
FILE *fp; // File pointer if opening an individual file
const void *data; // Pointer for memory-mapped file access. NULL if not mem-mapped.
bool mem_mapped; // Flag for memory mapped files (if data is not null and this is false it means that it's an embedded file)
void *data; // Pointer for memory-mapped file access. NULL if not mem-mapped.
#ifdef _WIN32
HANDLE hInFile; // Handle from CreateFile()
HANDLE hMapFile; // Handle from CreateFileMapping()
+29 -146
View File
@@ -37,16 +37,12 @@
#include "cfile/cfilesystem.h"
#include "cmdline/cmdline.h"
#include "globalincs/pstypes.h"
#include "def_files/def_files.h"
#include "localization/localize.h"
#include "osapi/osapi.h"
#include "parse/parselo.h"
enum CfileRootType {
CF_ROOTTYPE_PATH = 0,
CF_ROOTTYPE_PACK = 1,
CF_ROOTTYPE_MEMORY = 2,
};
#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;
@@ -57,8 +53,8 @@ SCP_string Pilot_file_path;
// specifying cd-rom tree
// searching for pack files on CD-rom tree
typedef struct cf_root {
char path[CF_MAX_PATHNAME_LENGTH]; // Contains something like c:\projects\freespace or c:\projects\freespace\freespace.vp
int roottype; // CF_ROOTTYPE_PATH = Path, CF_ROOTTYPE_PACK =Pack file, CF_ROOTTYPE_MEMORY=In memory
char path[CF_MAX_PATHNAME_LENGTH]; // Contains something like c:\projects\freespace or c:\projects\freespace\freespace.vp
int roottype; // CF_ROOTTYPE_PATH = Path, CF_ROOTTYPE_PACK =Pack file
} cf_root;
// convenient type for sorting (see cf_build_pack_list())
@@ -83,14 +79,13 @@ 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
const void* data; // For in-memory files, the data pointer
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
} cf_file;
#define CF_NUM_FILES_PER_BLOCK 512
@@ -515,11 +510,6 @@ void cf_build_root_list(const char *cdrom_dir)
}
// The final root is the in-memory root
root = cf_create_root();
memset(root->path, 0, sizeof(root->path));
root->roottype = CF_ROOTTYPE_MEMORY;
}
// Given a lower case list of file extensions
@@ -846,48 +836,7 @@ void cf_search_root_pack(int root_index)
mprintf(( "%i files\n", num_files ));
}
void cf_search_memory_root(int root_index) {
int num_files = 0;
mprintf(( "Searching memory root ... " ));
auto default_files = defaults_get_all();
for (auto& default_file : default_files) {
// Pure built in files have an empty path_type string
if (strlen(default_file.path_type) <= 0) {
// Ignore pure builtin files. They should only be accessible with defaults_get_file
continue;
}
int pathtype = -1;
for (int i = 0; i < CF_MAX_PATH_TYPES; ++i) {
if (Pathtypes[i].path == nullptr) {
continue;
}
if (!strcmp(Pathtypes[i].path, default_file.path_type)) {
pathtype = i;
break;
}
}
Assertion(pathtype != -1, "Default file '%s%s%s' does not use a valid path type!",
default_file.path_type,
DIR_SEPARATOR_STR,
default_file.filename);
cf_file *file = cf_create_file();
strcpy_s( file->name_ext, default_file.filename );
file->root_index = root_index;
file->pathtype_index = pathtype;
file->write_time = time(nullptr); // Just assume that memory files were last written to just now
file->size = (int)default_file.size;
file->data = default_file.data;
num_files++;
}
mprintf(( "%i files\n", num_files ));
}
void cf_build_file_list()
{
@@ -902,8 +851,6 @@ void cf_build_file_list()
cf_search_root_path(i);
} else if ( root->roottype == CF_ROOTTYPE_PACK ) {
cf_search_root_pack(i);
} else if (root->roottype == CF_ROOTTYPE_MEMORY) {
cf_search_memory_root(i);
}
}
@@ -985,7 +932,7 @@ void cf_free_secondary_filelist()
*
* @return If not found returns 0.
*/
int cf_find_file_location( const char *filespec, int pathtype, int max_out, char *pack_filename, size_t *size, size_t *offset, bool localize, const void** data_out )
int cf_find_file_location( const char *filespec, int pathtype, int max_out, char *pack_filename, size_t *size, size_t *offset, bool localize )
{
int i;
uint ui;
@@ -1120,16 +1067,8 @@ int cf_find_file_location( const char *filespec, int pathtype, int max_out, char
if (offset)
*offset = (size_t)f->pack_offset;
if (data_out)
*data_out = f->data;
if (pack_filename) {
if (f->data != nullptr) {
// This is an in-memory file so we just copy the pathtype name + file name
strncpy(pack_filename, Pathtypes[f->pathtype_index].path, max_out);
strncat(pack_filename, DIR_SEPARATOR_STR, max_out);
strncat(pack_filename, f->name_ext, max_out);
} else if (f->pack_offset < 1) {
if (f->pack_offset < 1) {
// This is a real file, return the actual file path
strncpy( pack_filename, f->real_name, max_out );
} else {
@@ -1153,16 +1092,8 @@ int cf_find_file_location( const char *filespec, int pathtype, int max_out, char
if (offset)
*offset = (size_t)f->pack_offset;
if (data_out)
*data_out = f->data;
if (pack_filename) {
if (f->data != nullptr) {
// This is an in-memory file so we just copy the pathtype name + file name
strncpy(pack_filename, Pathtypes[f->pathtype_index].path, max_out);
strncat(pack_filename, DIR_SEPARATOR_STR, max_out);
strncat(pack_filename, f->name_ext, max_out);
} else if (f->pack_offset < 1) {
if (f->pack_offset < 1) {
// This is a real file, return the actual file path
strncpy( pack_filename, f->real_name, max_out );
} else {
@@ -1201,7 +1132,7 @@ extern char *stristr(char *str, const char *substr);
*
* @return If not found returns -1, else returns offset into ext_list.
*/
int cf_find_file_location_ext( const char *filename, const int ext_num, const char **ext_list, int pathtype, int max_out, char *pack_filename, size_t *size, size_t *offset, bool localize, const void** data_out)
int cf_find_file_location_ext( const char *filename, const int ext_num, const char **ext_list, int pathtype, int max_out, char *pack_filename, size_t *size, size_t *offset, bool localize )
{
int cur_ext, i;
uint ui;
@@ -1286,9 +1217,6 @@ int cf_find_file_location_ext( const char *filename, const int ext_num, const ch
if (size)
*size = findstruct.size;
if (data_out)
*data_out = nullptr;
_findclose(findhandle);
if (offset)
@@ -1307,9 +1235,6 @@ int cf_find_file_location_ext( const char *filename, const int ext_num, const ch
if (size)
*size = filelength( fileno(fp) );
if (data_out)
*data_out = nullptr;
fclose(fp);
if (offset)
@@ -1409,25 +1334,15 @@ int cf_find_file_location_ext( const char *filename, const int ext_num, const ch
if (offset)
*offset = f->pack_offset;
if (data_out)
*data_out = f->data;
if (pack_filename) {
if (f->data != nullptr) {
// This is an in-memory file so we just copy the pathtype name + file name
strncpy(pack_filename, Pathtypes[f->pathtype_index].path, max_out);
strncat(pack_filename, DIR_SEPARATOR_STR, max_out);
strncat(pack_filename, f->name_ext, max_out);
}
else if (f->pack_offset < 1) {
if (f->pack_offset < 1) {
// This is a real file, return the actual file path
strncpy(pack_filename, f->real_name, max_out);
}
else {
strncpy( pack_filename, f->real_name, max_out );
} else {
// File is in a pack file
cf_root *r = cf_get_root(f->root_index);
strncpy(pack_filename, r->path, max_out);
strncpy( pack_filename, r->path, max_out );
}
}
@@ -1447,25 +1362,15 @@ int cf_find_file_location_ext( const char *filename, const int ext_num, const ch
if (offset)
*offset = f->pack_offset;
if (data_out)
*data_out = f->data;
if (pack_filename) {
if (f->data != nullptr) {
// This is an in-memory file so we just copy the pathtype name + file name
strncpy(pack_filename, Pathtypes[f->pathtype_index].path, max_out);
strncat(pack_filename, DIR_SEPARATOR_STR, max_out);
strncat(pack_filename, f->name_ext, max_out);
}
else if (f->pack_offset < 1) {
if (f->pack_offset < 1) {
// This is a real file, return the actual file path
strncpy(pack_filename, f->real_name, max_out);
}
else {
strncpy( pack_filename, f->real_name, max_out );
} else {
// File is in a pack file
cf_root *r = cf_get_root(f->root_index);
strncpy(pack_filename, r->path, max_out);
strncpy( pack_filename, r->path, max_out );
}
}
@@ -1527,7 +1432,6 @@ int cf_matches_spec(const char *filespec, const char *filename)
int (*Get_file_list_filter)(const char *filename) = NULL;
const char *Get_file_list_child = NULL;
int Skip_packfile_search = 0;
bool Skip_memory_files = false;
static bool verify_file_list_child()
{
@@ -1663,10 +1567,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) {
@@ -1731,11 +1633,6 @@ int cf_get_file_list( SCP_vector<SCP_string> &list, int pathtype, const char *fi
continue;
}
if (Skip_memory_files && f->data != nullptr) {
// If we want to skip memory files and this is a memory file then ignore it
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 ));
@@ -1879,10 +1776,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) {
@@ -1948,11 +1843,6 @@ int cf_get_file_list( int max, char **list, int pathtype, const char *filter, in
continue;
}
if (Skip_memory_files && f->data != nullptr) {
// If we want to skip memory files and this is a memory file then ignore it
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 ));
@@ -2101,10 +1991,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) {
@@ -2173,11 +2061,6 @@ int cf_get_file_list_preallocated( int max, char arr[][MAX_FILENAME_LEN], char *
continue;
}
if (Skip_memory_files && f->data != nullptr) {
// If we want to skip memory files and this is a memory file then ignore it
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 ));
+65 -297
View File
@@ -23,9 +23,6 @@
#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);
@@ -160,6 +148,7 @@ Flag exe_params[] =
{ "-noenv", "Disable environment maps", true, EASY_DEFAULT_MEM, EASY_MEM_ALL_ON, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-env", },
{ "-nomotiondebris", "Disable motion debris", true, EASY_ALL_ON, EASY_DEFAULT, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-nomotiondebris",},
{ "-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" },
@@ -188,6 +177,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", },
@@ -215,11 +205,11 @@ Flag exe_params[] =
{ "-use_gldrawelements","Don't use glDrawRangeElements", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-use_gldrawelements", },
{ "-old_collision", "Use old collision detection system", true, EASY_DEFAULT, EASY_ALL_ON, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-old_collision", },
{ "-gl_finish", "Fix input lag on some ATI+Linux systems", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-gl_finish", },
{ "-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", },
{ "-no_bindless_tex", "Disable bindless texturing", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_bindless_tex", },
#ifdef WIN32
{ "-fix_registry", "Use a different registry path", true, 0, EASY_DEFAULT, "Troubleshoot", "", },
#endif
@@ -228,7 +218,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", },
@@ -314,6 +303,7 @@ cmdline_parm spec_static_arg("-spec_static", "Adjusts suns contribution to specu
cmdline_parm spec_point_arg("-spec_point", "Adjusts laser weapons contribution to specular highlights", AT_FLOAT);
cmdline_parm spec_tube_arg("-spec_tube", "Adjusts beam weapons contribution to specular highlights", AT_FLOAT);
cmdline_parm ambient_factor_arg("-ambient_factor", "Adjusts ambient light applied to all parts of a ship", AT_INT); // Cmdline_ambient_factor
cmdline_parm missile_lighting_arg("-missile_lighting", NULL, AT_NONE); // Cmdline_missile_lighting
cmdline_parm env("-noenv", NULL, AT_NONE); // Cmdline_env
cmdline_parm glow_arg("-noglow", NULL, AT_NONE); // Cmdline_glow -- use Bobs glow code
cmdline_parm nomotiondebris_arg("-nomotiondebris", NULL, AT_NONE); // Cmdline_nomotiondebris -- Removes those ugly floating rocks -C
@@ -331,10 +321,10 @@ cmdline_parm fxaa_preset_arg("-fxaa_preset", "FXAA quality (0-9), requires -post
cmdline_parm fb_explosions_arg("-fb_explosions", NULL, AT_NONE);
cmdline_parm fb_thrusters_arg("-fb_thrusters", NULL, AT_NONE);
cmdline_parm flightshaftsoff_arg("-nolightshafts", NULL, AT_NONE);
cmdline_parm no_batching("-no_batching", NULL, AT_NONE);
cmdline_parm shadow_quality_arg("-shadow_quality", NULL, AT_INT);
cmdline_parm enable_shadows_arg("-enable_shadows", NULL, AT_NONE);
cmdline_parm no_deferred_lighting_arg("-no_deferred", NULL, AT_NONE); // Cmdline_no_deferred
cmdline_parm anisotropy_level_arg("-anisotropic_filter", NULL, AT_INT);
float Cmdline_clip_dist = Default_min_draw_distance;
float Cmdline_fov = 0.75f;
@@ -342,6 +332,7 @@ float Cmdline_ogl_spec = 80.0f;
int Cmdline_ambient_factor = 128;
int Cmdline_env = 1;
int Cmdline_mipmap = 0;
int Cmdline_missile_lighting = 0;
int Cmdline_glow = 1;
int Cmdline_nomotiondebris = 0;
int Cmdline_noscalevid = 0;
@@ -358,10 +349,10 @@ int Cmdline_fxaa_preset = 6;
extern int Fxaa_preset_last_frame;
bool Cmdline_fb_explosions = 0;
bool Cmdline_fb_thrusters = false;
bool Cmdline_no_batching = false;
extern bool ls_force_off;
int Cmdline_shadow_quality = 0;
int Cmdline_no_deferred_lighting = 0;
int Cmdline_aniso_level = 0;
// Game Speed related
cmdline_parm cache_bitmaps_arg("-cache_bitmaps", NULL, AT_NONE); // Cmdline_cache_bitmaps
@@ -402,9 +393,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;
@@ -450,7 +443,6 @@ 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);
cmdline_parm no_bindless_tex_arg("-no_bindless_tex", NULL, AT_NONE);
#ifdef WIN32
cmdline_parm fix_registry("-fix_registry", NULL, AT_NONE);
#endif
@@ -469,7 +461,6 @@ bool Cmdline_no_geo_sdr_effects = false;
bool Cmdline_set_cpu_affinity = false;
bool Cmdline_nograb = false;
bool Cmdline_noshadercache = false;
bool Cmdline_no_bindless_textures = false;
#ifdef WIN32
bool Cmdline_alternate_registry_path = false;
#endif
@@ -481,7 +472,6 @@ 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 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
@@ -507,13 +497,11 @@ char *Cmdline_start_mission = NULL;
int Cmdline_old_collision_sys = 0;
int Cmdline_dis_collisions = 0;
int Cmdline_dis_weapons = 0;
bool Cmdline_output_sexp_info = false;
int Cmdline_noparseerrors = 0;
#ifdef Allow_NoWarn
int Cmdline_nowarn = 0; // turn warnings off in FRED
#endif
int Cmdline_extra_warn = 0;
int Cmdline_bmpman_usage = 0;
int Cmdline_show_pos = 0;
int Cmdline_show_stats = 0;
int Cmdline_save_render_targets = 0;
@@ -534,7 +522,7 @@ 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,8 +535,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);
cmdline_parm deprecated_missile_lighting_arg("-missile_lighting", "Deprecated", AT_NONE);
int Cmdline_deprecated_spec = 0;
int Cmdline_deprecated_glow = 0;
@@ -558,7 +544,6 @@ int Cmdline_deprecated_tbp = 0;
int Cmdline_deprecated_jpgtga = 0;
int Cmdline_deprecated_nohtl = 0;
bool Cmdline_deprecated_brief_lighting = 0;
bool Cmdline_deprecated_missile_lighting = false;
#ifndef NDEBUG
// NOTE: this assumes that os_init() has already been called but isn't a fatal error if it hasn't
@@ -624,11 +609,6 @@ void cmdline_debug_print_cmdline()
{
mprintf(("Deprecated flag '-brief_lighting' found. Please remove from your cmdline.\n"));
}
if (Cmdline_deprecated_missile_lighting)
{
mprintf(("Deprecated flag '-missile_lighting' found. Please remove from your cmdline.\n"));
}
}
#endif
@@ -1163,9 +1143,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.
@@ -1264,248 +1241,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
{
@@ -1513,7 +1248,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;
}
@@ -1766,11 +1541,6 @@ bool SetCmdlineParams()
Show_framerate = 1;
}
if (bmpmanusage_arg.found())
{
Cmdline_bmpman_usage = 1;
}
if(pos_arg.found())
{
Cmdline_show_pos = 1;
@@ -1897,7 +1667,7 @@ bool SetCmdlineParams()
Output_scripting_meta = true;
if (output_sexp_arg.found() ) {
Cmdline_output_sexp_info = true;
output_sexps("sexps.html");
}
if ( no_pbo_arg.found() )
@@ -1940,11 +1710,6 @@ bool SetCmdlineParams()
Cmdline_noshadercache = true;
}
if (no_bindless_tex_arg.found())
{
Cmdline_no_bindless_textures = true;
}
if (portable_mode.found())
{
Cmdline_portable_mode = true;
@@ -1956,6 +1721,11 @@ bool SetCmdlineParams()
}
#endif
if ( snd_preload_arg.found() )
{
Cmdline_snd_preload = 1;
}
if ( env.found() ) {
Cmdline_env = 0;
}
@@ -1994,6 +1764,9 @@ bool SetCmdlineParams()
if ( rearm_timer_arg.found() )
Cmdline_rearm_timer = 1;
if ( missile_lighting_arg.found() )
Cmdline_missile_lighting = 1;
if ( save_render_targets_arg.found() )
Cmdline_save_render_targets = 1;
@@ -2028,6 +1801,11 @@ bool SetCmdlineParams()
Cmdline_fb_thrusters = true;
}
if ( no_batching.found() )
{
Cmdline_no_batching = true;
}
if ( postprocess_arg.found() )
{
Cmdline_postprocess = 1;
@@ -2063,11 +1841,6 @@ bool SetCmdlineParams()
Cmdline_no_deferred_lighting = 1;
}
if (anisotropy_level_arg.found())
{
Cmdline_aniso_level = anisotropy_level_arg.get_int();
}
if (frame_profile_write_file.found())
{
Cmdline_profile_write_file = true;
@@ -2153,11 +1926,6 @@ bool SetCmdlineParams()
Cmdline_deprecated_brief_lighting = 1;
}
if (deprecated_missile_lighting_arg.found())
{
Cmdline_deprecated_missile_lighting = true;
}
return true;
}
+3 -4
View File
@@ -62,6 +62,7 @@ extern float static_point_factor;
extern float static_tube_factor;
extern int Cmdline_ambient_factor;
extern int Cmdline_env;
extern int Cmdline_missile_lighting;
extern int Cmdline_glow;
extern int Cmdline_nomotiondebris;
extern int Cmdline_noscalevid; // disables fit-to-window for movies - taylor
@@ -76,10 +77,10 @@ extern bool Cmdline_fxaa;
extern int Cmdline_fxaa_preset;
extern bool Cmdline_fb_explosions;
extern bool Cmdline_fb_thrusters;
extern bool Cmdline_no_batching;
extern int Cmdline_shadow_quality;
extern int Cmdline_no_deferred_lighting;
extern int Cmdline_no_emissive;
extern int Cmdline_aniso_level;
// Game Speed related
extern int Cmdline_cache_bitmaps;
@@ -103,6 +104,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;
@@ -135,7 +137,6 @@ extern bool Cmdline_no_geo_sdr_effects;
extern bool Cmdline_set_cpu_affinity;
extern bool Cmdline_nograb;
extern bool Cmdline_noshadercache;
extern bool Cmdline_no_bindless_textures;
#ifdef WIN32
extern bool Cmdline_alternate_registry_path;
#endif
@@ -145,10 +146,8 @@ extern char *Cmdline_start_mission;
extern int Cmdline_old_collision_sys;
extern int Cmdline_dis_collisions;
extern int Cmdline_dis_weapons;
extern bool Cmdline_output_sexp_info;
extern int Cmdline_noparseerrors;
extern int Cmdline_extra_warn;
extern int Cmdline_bmpman_usage;
extern int Cmdline_show_pos;
extern int Cmdline_show_stats;
extern int Cmdline_save_render_targets;
+1 -1
View File
@@ -92,7 +92,7 @@ void cmeasure_maybe_alert_success(object *objp)
if ( objp->parent == OBJ_INDEX(Player_obj) ) {
hud_start_text_flash(XSTR("Evaded", 1430), 800);
snd_play(gamesnd_get_game_sound(ship_get_sound(Player_obj, 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 );
}
-21
View File
@@ -14,11 +14,6 @@ bool Decoder::tryPopAudioData(AudioFramePtr& 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;
@@ -29,7 +24,6 @@ void Decoder::initializeQueues(size_t 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() {
@@ -37,7 +31,6 @@ void Decoder::stopDecoder() {
m_videoQueue->close();
m_audioQueue->close();
m_subtitleQueue->close();
}
bool Decoder::canPushAudioData() {
@@ -55,20 +48,6 @@ void Decoder::pushAudioData(AudioFramePtr&& data) {
}
}
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();
}
-23
View File
@@ -58,14 +58,6 @@ struct AudioFrame {
};
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
*
@@ -76,7 +68,6 @@ 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;
@@ -118,8 +109,6 @@ class Decoder {
*/
virtual bool hasAudio() = 0;
virtual bool hasSubtitles() = 0;
/**
* @brief Ends decoding of the video file
*/
@@ -133,14 +122,6 @@ class Decoder {
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(); }
@@ -160,10 +141,6 @@ class Decoder {
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
+2 -98
View File
@@ -9,9 +9,6 @@
#include "cutscene/ffmpeg/AudioDecoder.h"
#include "cutscene/ffmpeg/VideoDecoder.h"
#include "cutscene/ffmpeg/SubtitleDecoder.h"
#include "localization/localize.h"
using namespace libs::ffmpeg;
@@ -65,8 +62,6 @@ CodecContextParameters getCodecParameters(AVStream* stream) {
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;
@@ -75,29 +70,9 @@ CodecContextParameters getCodecParameters(AVStream* stream) {
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 {
@@ -180,32 +155,7 @@ std::unique_ptr<DecoderStatus> initializeStatus(std::unique_ptr<InputStream>& st
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];
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
auto& pars = test_stream->codecpar;
if (!(pars->codec_type == AVMEDIA_TYPE_SUBTITLE)) {
continue;
}
#endif
AVDictionaryEntry* tag = nullptr;
if ((tag = av_dict_get(test_stream->metadata, "language", nullptr, 0)) == nullptr) {
continue;
}
auto normalized_language = normalizeLanguage(tag->value);
if (!stricmp(normalized_language.c_str(), current_language.lang_name)) {
status->subtitleStreamIndex = i;
status->subtitleStream = test_stream;
break;
}
}
status->videoCodecPars = getCodecParameters(status->videoStream);
status->videoCodecPars = getCodecParameters(status->videoStream);
int err;
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
@@ -263,37 +213,6 @@ std::unique_ptr<DecoderStatus> initializeStatus(std::unique_ptr<InputStream>& st
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;
}
@@ -360,14 +279,10 @@ 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;
@@ -407,14 +322,7 @@ void FFMPEGDecoder::startDecoding() {
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()) {
@@ -441,10 +349,6 @@ 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;
-2
View File
@@ -27,8 +27,6 @@ class FFMPEGDecoder: public Decoder {
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);
};
}
}
-12
View File
@@ -30,18 +30,6 @@ DecoderStatus::~DecoderStatus() {
#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
-8
View File
@@ -16,8 +16,6 @@ struct CodecContextParameters {
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 {
@@ -33,12 +31,6 @@ struct DecoderStatus {
AVCodec* audioCodec = nullptr;
AVCodecContext* audioCodecCtx = nullptr;
int subtitleStreamIndex = -1;
AVStream* subtitleStream = nullptr;
CodecContextParameters subtitleCodecPars;
AVCodec* subtitleCodec = nullptr;
AVCodecContext* subtitleCodecCtx = nullptr;
DecoderStatus();
~DecoderStatus();
+1 -200
View File
@@ -14,7 +14,6 @@
#endif
#include "globalincs/pstypes.h"
#include "globalincs/alphacolors.h"
#include "globalincs/systemvars.h"
#include "io/cursor.h"
#include "graphics/2d.h"
@@ -22,203 +21,10 @@
#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"
extern int Game_mode;
extern int Is_standalone;
namespace {
using namespace cutscene;
struct PlaybackState {
bool playing = true;
vec2d posTopLeft;
vec2d posBottomRight;
int subtitle_font = -1;
};
void processEvents(PlaybackState* state) {
io::mouse::CursorManager::get()->showCursor(false);
os_poll();
int k = key_inkey();
switch (k) {
case KEY_ESC:
case KEY_ENTER:
case KEY_SPACEBAR:
state->playing = false;
break;
default:
break;
}
}
template<typename... Args>
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) {
@@ -251,12 +57,7 @@ bool play(const char* name) {
auto player = cutscene::Player::newPlayer(name);
if (player) {
PlaybackState state;
initialize_player_state(player.get(), &state);
movie_display_loop(player.get(), &state);
player->stopPlayback();
player->startPlayback();
} else {
// uh-oh, movie is invalid... Abory, Retry, Fail?
mprintf(("MOVIE ERROR: Found invalid movie! (%s)\n", name));
+176 -96
View File
@@ -1,7 +1,7 @@
#include "cutscene/player.h"
#include "cutscene/Decoder.h"
#include "cutscene/VideoPresenter.h"
#include "cutscene/player/VideoPresenter.h"
#include "cutscene/ffmpeg/FFMPEGDecoder.h"
#include "graphics/2d.h"
@@ -19,19 +19,62 @@
#include "parse/parselo.h"
#include "cutscene/player/OpenGLVideoPresenter.h"
using namespace cutscene::player;
namespace cutscene {
struct PlayerState {
MovieProperties props;
Decoder* decoder = nullptr;
bool playing = true;
bool playbackHasBegun = false;
// Timing state
std::uint64_t playback_time = 0;
// Audio state
bool audioInited = false;
bool hasAudio = false;
ALuint audioSid = 0;
SCP_vector<ALuint> audioBuffers;
SCP_queue<ALuint> unqueuedAudioBuffers;
// Graphics state following
bool videoInited = false;
VideoFramePtr currentFrame;
VideoFramePtr nextFrame;
bool newFrameAdded = false;
std::unique_ptr<VideoPresenter> videoPresenter;
PlayerState() : decoder(nullptr), playing(true), playbackHasBegun(false),
playback_time(0),
audioInited(0), hasAudio(false), audioSid(0),
videoInited(false), newFrameAdded(false) {}
private:
PlayerState(const PlayerState&) SCP_DELETED_FUNCTION;
PlayerState& operator=(const PlayerState&) SCP_DELETED_FUNCTION;
};
}
namespace {
using namespace cutscene;
const int MAX_AUDIO_BUFFERS = 15;
std::unique_ptr<Decoder> findDecoder(const SCP_string& name) {
Decoder* findDecoder(const SCP_string& name) {
{
std::unique_ptr<Decoder> ffmpeg(new ffmpeg::FFMPEGDecoder());
auto ffmpeg = new ffmpeg::FFMPEGDecoder();
if (ffmpeg->initialize(name)) {
return ffmpeg;
}
delete ffmpeg;
}
return nullptr;
@@ -50,7 +93,7 @@ void videoPlaybackInit(PlayerState* state) {
Assert(state != NULL);
if (gr_screen.mode == GR_OPENGL) {
state->videoPresenter.reset(new VideoPresenter(state->props));
state->videoPresenter.reset(new OpenGLVideoPresenter(state->props));
}
state->videoInited = true;
@@ -120,7 +163,7 @@ void processVideoData(PlayerState* state) {
return;
}
while (currentTime >= state->nextFrame->frameTime) {
while(currentTime >= state->nextFrame->frameTime) {
// Move the next frame to the current frame slot
state->currentFrame = std::move(state->nextFrame);
@@ -141,34 +184,6 @@ void processVideoData(PlayerState* state) {
}
}
void processSubtitleData(PlayerState* state) {
SubtitleFramePtr ptr;
while (state->decoder->tryPopSubtitleData(ptr)) {
// Take all subtitle frames from our queue
state->queued_subtitles.push(std::move(ptr));
}
if (state->currentSubtitle && playbackGetTime(state) <= state->currentSubtitle->displayEndTime) {
// We currently have a frame and it it still being displayed so there is nothing for us to do here
return;
}
// Subtitle has expired so we don't need it anymore
state->currentSubtitle = nullptr;
while(!state->queued_subtitles.empty()) {
// Take a look at the first entry and check if it's time to display it yet
auto& nextSubtitle = state->queued_subtitles.front();
if (playbackGetTime(state) >= nextSubtitle->displayStartTime) {
state->currentSubtitle = std::move(nextSubtitle);
state->queued_subtitles.pop();
} else {
// The next subtitle should not be displayed yet so we are done here
break;
}
}
}
bool processAudioData(PlayerState* state) {
TRACE_SCOPE(tracing::CutsceneProcessAudioData);
@@ -176,7 +191,7 @@ bool processAudioData(PlayerState* state) {
if (state->decoder->hasAudio()) {
// Even if we don't play the sound we still need to remove it from the queue
AudioFramePtr audioData;
while (state->decoder->tryPopAudioData(audioData)) {
while(state->decoder->tryPopAudioData(audioData)) {
// Intentionally left empty
}
}
@@ -201,9 +216,7 @@ bool processAudioData(PlayerState* state) {
ALenum format = (audioData->channels == 2) ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16;
OpenAL_ErrorCheck(alBufferData(buffer,
format,
audioData->audioData.data(),
OpenAL_ErrorCheck(alBufferData(buffer, format, audioData->audioData.data(),
static_cast<ALsizei>(audioData->audioData.size() * sizeof(short)),
static_cast<ALsizei>(audioData->rate)), return false);
@@ -256,10 +269,82 @@ void videoPlaybackClose(PlayerState* state) {
state->videoInited = false;
}
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(PlayerState* state) {
gr_set_color_fast(&Color_white);
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(PlayerState* state) {
if (!state->currentFrame) {
return;
}
TRACE_SCOPE(tracing::CutsceneDrawVideoFrame);
gr_clear();
if (state->videoPresenter) {
state->videoPresenter->displayFrame();
}
if (Cmdline_show_video_info) {
showVideoInfo(state);
}
gr_flip();
}
void processEvents(PlayerState* state) {
io::mouse::CursorManager::get()->showCursor(false);
os_poll();
int k = key_inkey();
switch (k) {
case KEY_ESC:
case KEY_ENTER:
case KEY_SPACEBAR:
state->playing = false;
break;
default:
break;
}
}
bool shouldBeginPlayback(Decoder* decoder) {
auto video = decoder->isVideoQueueFull();
auto audio = decoder->isAudioQueueFull();
auto subtitles = decoder->isSubtitleQueueFull();
// Wait until one of the queues is full, that should make sure
// that we have enough frames at the beginning of playback and that
@@ -267,79 +352,92 @@ bool shouldBeginPlayback(Decoder* decoder) {
// or video at the beginning
// Also only wait while the decoder is still working. Otherwise we will wait indefinitely if the video
// is very short.
return (audio || video || subtitles) || !decoder->isDecoding();
return (audio || video) || !decoder->isDecoding();
}
}
namespace cutscene {
Player::Player(std::unique_ptr<Decoder>&& decoder) : m_decoder(std::move(decoder)) {
initPlayback();
Player::Player() {
}
Player::~Player() {
// If video is initialized it means that stopPlayback has not been called yet
if (m_state.videoInited) {
stopPlayback();
}
if (m_decoder) {
m_decoder->close();
}
}
bool Player::processDecoderData() {
if (!m_state.playbackHasBegun) {
void Player::processDecoderData(PlayerState* state) {
if (!state->playbackHasBegun) {
// Wait until video and audio are available
// If we don't have audio, don't wait for it (obviously...)
if (!shouldBeginPlayback(m_state.decoder)) {
return true;
if (!shouldBeginPlayback(state->decoder)) {
return;
}
m_state.playbackHasBegun = true;
state->playbackHasBegun = true;
}
TRACE_SCOPE(tracing::CutsceneProcessDecoder);
processVideoData(&m_state);
processVideoData(state);
processSubtitleData(&m_state);
auto audioPlaying = processAudioData(&m_state);
auto audioPlaying = processAudioData(state);
// Set the playing flag if the decoder is still active or there is still data available
auto decoding = m_decoder->isDecoding();
// Audio is pending if there is data left in the queue or if OpenAL is still playing audio
// Audio is pending if there is data left in the queue or of OpenAL is still playing audio
auto pendingAudio = (m_decoder->isAudioFrameAvailable() && m_decoder->hasAudio()) || audioPlaying;
auto pendingVideo = m_decoder->isVideoFrameAvailable();
return decoding || pendingAudio || pendingVideo;
state->playing = decoding || pendingAudio || pendingVideo;
}
void Player::initPlayback() {
Assertion(!m_state.videoInited, "Internal State has been initialized before! Create a new player for replaying a movie.");
void Player::startPlayback() {
m_decoderThread.reset(new std::thread(std::bind(&Player::decoderThread, this)));
m_state.props = m_decoder->getProperties();
m_state.decoder = m_decoder.get();
PlayerState state;
state.props = m_decoder->getProperties();
state.decoder = m_decoder.get();
videoPlaybackInit(&m_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. * state.props.fps)) * 1000.);
audioPlaybackInit(&m_state);
}
bool Player::update(uint64_t diff_time_micro) {
if (m_state.playbackHasBegun) {
m_state.playback_time += diff_time_micro;
videoPlaybackInit(&state);
audioPlaybackInit(&state);
auto lastDisplayTimestamp = timer_get_microseconds();
while (state.playing) {
TRACE_SCOPE(tracing::CutsceneStep);
processDecoderData(&state);
displayVideo(&state);
processEvents(&state);
auto timestamp = timer_get_microseconds();
auto passed = timestamp - lastDisplayTimestamp;
lastDisplayTimestamp = timestamp;
if (state.playbackHasBegun) {
state.playback_time += passed;
}
if (passed < sleepTime) {
auto sleep = sleepTime - passed;
os_sleep(static_cast<uint>(sleep));
}
}
return processDecoderData();
}
void Player::stopPlayback() {
m_decoder->stopDecoder();
audioPlaybackClose(&m_state);
videoPlaybackClose(&m_state);
audioPlaybackClose(&state);
videoPlaybackClose(&state);
m_decoderThread->join();
}
@@ -362,28 +460,10 @@ std::unique_ptr<Player> Player::newPlayer(const SCP_string& name) {
if (decoder == nullptr) {
return nullptr;
}
return std::unique_ptr<Player>(new Player(std::move(decoder)));
}
const PlayerState& Player::getInternalState() const {
return m_state;
}
const MovieProperties& Player::getMovieProperties() const {
return m_state.props;
}
void Player::draw(float x1, float y1, float x2, float y2) {
if (!m_state.currentFrame) {
return;
}
if (m_state.videoPresenter) {
m_state.videoPresenter->displayFrame(x1, y1, x2, y2);
}
}
SCP_string Player::getCurrentSubtitle() {
if (!m_state.currentSubtitle) {
return "";
} else {
return m_state.currentSubtitle->text;
}
std::unique_ptr<Player> player(new Player());
player->m_decoder.reset(decoder);
return player;
}
}
+8 -89
View File
@@ -5,48 +5,11 @@
#include <thread>
#include "globalincs/pstypes.h"
#include "sound/openal.h"
#include "Decoder.h"
#include "VideoPresenter.h"
namespace cutscene {
class Decoder;
struct PlayerState {
MovieProperties props;
Decoder* decoder = nullptr;
bool playbackHasBegun = false;
// Timing state
std::uint64_t playback_time = 0;
// Audio state
bool audioInited = false;
bool hasAudio = false;
ALuint audioSid = 0;
SCP_vector<ALuint> audioBuffers;
SCP_queue<ALuint> unqueuedAudioBuffers;
// Graphics state following
bool videoInited = false;
VideoFramePtr currentFrame;
VideoFramePtr nextFrame;
bool newFrameAdded = false;
std::unique_ptr<player::VideoPresenter> videoPresenter;
SCP_queue<SubtitleFramePtr> queued_subtitles;
SubtitleFramePtr currentSubtitle;
PlayerState() {
}
PlayerState(const PlayerState&) = delete;
PlayerState& operator=(const PlayerState&) = delete;
};
struct PlayerState;
/**
* @brief A movie player
@@ -57,66 +20,22 @@ class Player {
std::unique_ptr<std::thread> m_decoderThread;
PlayerState m_state;
bool processDecoderData();
void processDecoderData(PlayerState* state);
private:
Player(const Player&) = delete;
void decoderThread();
void initPlayback();
public:
explicit Player(std::unique_ptr<Decoder>&& decoder);
Player();
~Player();
Player(const Player&) = delete;
Player& operator=(const Player&) = delete;
/**
* @brief Update the player and increase display timestamp by specified delta time
* @param diff_time_micro The time to increase the display timestamp in microseconds (not milliseconds!)
* @return @c true if there is more content to display. @c false if the player reached the end of the movie and has
* displayed the last frame.
*/
bool update(uint64_t diff_time_micro);
/**
* @brief Gives access to the internal state of the player
*
* @warning This should only be used for debugging purposed!
*
* @return A reference to the internal state
*/
const PlayerState& getInternalState() const;
/**
* @brief Gets the properties of the movie that this player is displaying
* @return A reference to the movie properties
*/
const MovieProperties& getMovieProperties() const;
/**
* @brief Draws the current movie frame at the specified coordinates.
*
* This may not draw anything if there is currently not a frame to display.
*
* @param x1 The X coordinate of the top left corner
* @param y1 The Y coordinate of the top left corner
* @param x2 The X coordinate of the bottom right corner
* @param y2 The Y coordinate of the bottom right corner
*/
void draw(float x1, float y1, float x2, float y2);
SCP_string getCurrentSubtitle();
/**
* @brief Stops playback
*
* This is also automatically called when this instance is destroyed.
*/
void stopPlayback();
* @brief Begin playing the previously selected movie
*/
void startPlayback();
/**
* @brief Creates a player
@@ -0,0 +1,223 @@
#include "OpenGLVideoPresenter.h"
#include "graphics/opengl/gropenglstate.h"
#include "graphics/opengl/gropengltnl.h"
#include "graphics/opengl/gropengldraw.h"
using namespace cutscene;
using namespace cutscene::player;
namespace cutscene {
namespace player {
OpenGLVideoPresenter::OpenGLVideoPresenter(const MovieProperties& props) : _scaleVideo(false),
_ytex(0), _utex(0), _vtex(0) {
GR_DEBUG_SCOPE("Init video");
opengl_set_texture_target(GL_TEXTURE_2D);
_vertexBuffer = gr_create_vertex_buffer(true);
auto w = static_cast<int>(props.size.width);
auto h = static_cast<int>(props.size.height);
_sdr_handle = gr_maybe_create_shader(SDR_TYPE_VIDEO_PROCESS, 0);
glGenTextures(1, &_ytex);
glGenTextures(1, &_utex);
glGenTextures(1, &_vtex);
if (_ytex + _utex + _vtex == 0) {
throw std::runtime_error("Can't create a GL texture");
}
opengl_shader_set_current(_sdr_handle);
gr_set_lighting(false, false);
GL_state.SetAlphaBlendMode(ALPHA_BLEND_NONE);
GL_state.SetZbufferType(ZBUFFER_TYPE_NONE);
GL_state.Texture.SetActiveUnit(0);
GL_state.Texture.SetTarget(GL_texture_target);
GL_state.Texture.Enable(_ytex);
glTexParameteri(GL_texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// NOTE: using NULL instead of pixelbuf crashes some drivers, but then so does pixelbuf
glTexImage2D(GL_state.Texture.GetTarget(), 0, GL_RED, w, h, 0, GL_RED,
GL_UNSIGNED_BYTE, NULL);
GL_state.Texture.SetActiveUnit(1);
GL_state.Texture.SetTarget(GL_texture_target);
GL_state.Texture.Enable(_utex);
glTexParameteri(GL_texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// NOTE: using NULL instead of pixelbuf crashes some drivers, but then so does pixelbuf
glTexImage2D(GL_state.Texture.GetTarget(), 0, GL_RED, w / 2, h / 2, 0, GL_RED,
GL_UNSIGNED_BYTE, NULL);
GL_state.Texture.SetActiveUnit(2);
GL_state.Texture.SetTarget(GL_texture_target);
GL_state.Texture.Enable(_vtex);
glTexParameteri(GL_texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// NOTE: using NULL instead of pixelbuf crashes some drivers, but then so does pixelbuf
glTexImage2D(GL_state.Texture.GetTarget(), 0, GL_RED, w / 2, h / 2, 0, GL_RED,
GL_UNSIGNED_BYTE, NULL);
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;
}
// don't bother setting anything if we aren't going to need it
if (!Cmdline_noscalevid && (scale_by != 1.0f)) {
vec3d scale;
scale.xyz.x = scale_by;
scale.xyz.y = scale_by;
scale.xyz.z = -1.0f;
gr_push_scale_matrix(&scale);
_scaleVideo = true;
}
int screenX;
int screenY;
if (_scaleVideo) {
screenX = fl2i(((gr_screen.center_w / 2.0f + gr_screen.center_offset_x) / scale_by) - (static_cast<int>(props.size.width) / 2.0f) + 0.5f);
screenY = fl2i(((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 = ((gr_screen.center_w - static_cast<int>(props.size.width)) / 2) + gr_screen.center_offset_x;
screenY = ((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
int screenXW = screenX + static_cast<int>(props.size.width);
int screenYH = screenY + static_cast<int>(props.size.height);
Current_shader->program->Uniforms.setUniformi("ytex", 0);
Current_shader->program->Uniforms.setUniformi("utex", 1);
Current_shader->program->Uniforms.setUniformi("vtex", 2);
Current_shader->program->Uniforms.setUniformMatrix4f("projMatrix", GL_projection_matrix);
Current_shader->program->Uniforms.setUniformMatrix4f("modelViewMatrix", GL_model_view_matrix);
GLfloat glVertices[4][4] = {{0}};
glVertices[0][0] = (GLfloat)screenX;
glVertices[0][1] = (GLfloat)screenY;
glVertices[0][2] = 0.0f;
glVertices[0][3] = 0.0f;
glVertices[1][0] = (GLfloat)screenX;
glVertices[1][1] = (GLfloat)screenYH;
glVertices[1][2] = 0.0f;
glVertices[1][3] = 1.0f;
glVertices[2][0] = (GLfloat)screenXW;
glVertices[2][1] = (GLfloat)screenY;
glVertices[2][2] = 1.0f;
glVertices[2][3] = 0.0f;
glVertices[3][0] = (GLfloat)screenXW;
glVertices[3][1] = (GLfloat)screenYH;
glVertices[3][2] = 1.0f;
glVertices[3][3] = 1.0f;
_vertexLayout.add_vertex_component(vertex_format_data::POSITION2, sizeof(glVertices[0]), 0);
_vertexLayout.add_vertex_component(vertex_format_data::TEX_COORD, sizeof(glVertices[0]), sizeof(GLfloat) * 2);
gr_update_buffer_data(_vertexBuffer, sizeof(glVertices[0]) * 4, glVertices);
}
OpenGLVideoPresenter::~OpenGLVideoPresenter() {
GR_DEBUG_SCOPE("Deinit video");
if (_scaleVideo) {
gr_pop_scale_matrix();
}
gr_delete_buffer(_vertexBuffer);
_vertexBuffer = -1;
GL_state.Texture.Delete(_ytex);
GL_state.Texture.Delete(_utex);
GL_state.Texture.Delete(_vtex);
glDeleteTextures(1, &_ytex);
glDeleteTextures(1, &_utex);
glDeleteTextures(1, &_vtex);
opengl_set_texture_target();
_ytex = _utex = _vtex = 0;
opengl_shader_set_current();
}
void OpenGLVideoPresenter::uploadVideoFrame(const VideoFramePtr& frame) {
GR_DEBUG_SCOPE("Update video frame");
auto ptrs = frame->getDataPointers();
auto stride = static_cast<GLint>(frame->ySize.stride);
auto width = static_cast<GLint>(frame->ySize.width);
auto height = static_cast<GLint>(frame->ySize.height);
GL_state.Texture.SetActiveUnit(0);
GL_state.Texture.Enable(_ytex);
glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
glTexSubImage2D(GL_state.Texture.GetTarget(), 0, 0, 0, width, height, GL_RED, GL_UNSIGNED_BYTE,
ptrs.y);
stride = static_cast<int>(frame->uvSize.stride);
width = static_cast<int>(frame->uvSize.width);
height = static_cast<int>(frame->uvSize.height);
GL_state.Texture.SetActiveUnit(1);
GL_state.Texture.Enable(_utex);
glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
glTexSubImage2D(GL_state.Texture.GetTarget(), 0, 0, 0, width, height, GL_RED, GL_UNSIGNED_BYTE,
ptrs.u);
GL_state.Texture.SetActiveUnit(2);
GL_state.Texture.Enable(_vtex);
glTexSubImage2D(GL_state.Texture.GetTarget(), 0, 0, 0, width, height, GL_RED, GL_UNSIGNED_BYTE,
ptrs.v);
// Reset this back to default
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
}
void OpenGLVideoPresenter::displayFrame() {
opengl_shader_set_current(_sdr_handle);
opengl_bind_buffer_object(_vertexBuffer);
opengl_bind_vertex_layout(_vertexLayout);
// Bind textures
GL_state.Texture.SetActiveUnit(0);
GL_state.Texture.Enable(_ytex);
GL_state.Texture.SetActiveUnit(1);
GL_state.Texture.Enable(_utex);
GL_state.Texture.SetActiveUnit(2);
GL_state.Texture.Enable(_vtex);
GR_DEBUG_SCOPE("Draw video frame");
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
}
}
@@ -0,0 +1,38 @@
#ifndef FS2_OPEN_OPENGLVIDEOPRESENTER_H
#define FS2_OPEN_OPENGLVIDEOPRESENTER_H
#include "globalincs/pstypes.h"
#include "cutscene/player/VideoPresenter.h"
#include <glad/glad.h>
#include <memory>
#include <graphics/2d.h>
namespace cutscene {
namespace player {
class OpenGLVideoPresenter: public VideoPresenter {
int _vertexBuffer = -1;
vertex_layout _vertexLayout;
int _sdr_handle = -1;
bool _scaleVideo = false;
GLuint _ytex = 0;
GLuint _utex = 0;
GLuint _vtex = 0;
public:
OpenGLVideoPresenter(const MovieProperties& props);
virtual ~OpenGLVideoPresenter();
virtual void uploadVideoFrame(const VideoFramePtr& frame) SCP_OVERRIDE;
virtual void displayFrame() SCP_OVERRIDE;
};
}
}
#endif //FS2_OPEN_OPENGLVIDEOPRESENTER_H
+21
View File
@@ -0,0 +1,21 @@
#ifndef FS2_OPEN_VIDEOPRESENTER_H
#define FS2_OPEN_VIDEOPRESENTER_H
#include "globalincs/pstypes.h"
#include "cutscene/Decoder.h"
namespace cutscene {
namespace player {
class VideoPresenter {
public:
virtual ~VideoPresenter() {}
virtual void uploadVideoFrame(const VideoFramePtr& frame) = 0;
virtual void displayFrame() = 0;
};
}
}
#endif //FS2_OPEN_VIDEOPRESENTER_H
+6 -6
View File
@@ -74,7 +74,7 @@ static void debris_start_death_roll(object *debris_obj, debris *debris_p)
// only play debris destroy sound if hull piece and it has been around for at least 2 seconds
if ( Missiontime > debris_p->time_started + 2*F1_0 ) {
snd_play_3d( gamesnd_get_game_sound(SND_MISSILE_IMPACT1), &debris_obj->pos, &View_position, debris_obj->radius );
snd_play_3d( &Snds[SND_MISSILE_IMPACT1], &debris_obj->pos, &View_position, debris_obj->radius );
}
}
@@ -324,19 +324,19 @@ void debris_process_post(object * obj, float frame_time)
//Play a sound effect
if ( lifetime > 750 ) {
// 1.00 second effect
snd_play_3d( gamesnd_get_game_sound(SND_DEBRIS_ARC_05), &snd_pos, &View_position, obj->radius );
snd_play_3d( &Snds[SND_DEBRIS_ARC_05], &snd_pos, &View_position, obj->radius );
} else if ( lifetime > 500 ) {
// 0.75 second effect
snd_play_3d( gamesnd_get_game_sound(SND_DEBRIS_ARC_04), &snd_pos, &View_position, obj->radius );
snd_play_3d( &Snds[SND_DEBRIS_ARC_04], &snd_pos, &View_position, obj->radius );
} else if ( lifetime > 250 ) {
// 0.50 second effect
snd_play_3d( gamesnd_get_game_sound(SND_DEBRIS_ARC_03), &snd_pos, &View_position, obj->radius );
snd_play_3d( &Snds[SND_DEBRIS_ARC_03], &snd_pos, &View_position, obj->radius );
} else if ( lifetime > 100 ) {
// 0.25 second effect
snd_play_3d( gamesnd_get_game_sound(SND_DEBRIS_ARC_02), &snd_pos, &View_position, obj->radius );
snd_play_3d( &Snds[SND_DEBRIS_ARC_02], &snd_pos, &View_position, obj->radius );
} else {
// 0.10 second effect
snd_play_3d( gamesnd_get_game_sound(SND_DEBRIS_ARC_01), &snd_pos, &View_position, obj->radius );
snd_play_3d( &Snds[SND_DEBRIS_ARC_01], &snd_pos, &View_position, obj->radius );
}
}
}
-541
View File
@@ -1,541 +0,0 @@
#include <nebula/neb.h>
#include <utility>
#include "decals/decals.h"
#include "graphics/2d.h"
#include "graphics/decal_draw_list.h"
#include "graphics/util/uniform_structs.h"
#include "parse/parselo.h"
#include "tracing/tracing.h"
#include "ship/ship.h"
namespace {
class DecalDefinition {
SCP_string _name;
SCP_string _diffuseFilename;
bool _loopDiffuse = true;
SCP_string _glowFilename;
bool _loopGlow = true;
SCP_string _normalMapFilename;
bool _loopNormal = true;
int _diffuseBitmap = -1;
int _glowBitmap = -1;
int _normalBitmap = -1;
public:
explicit DecalDefinition(SCP_string name) : _name(std::move(name)) {
}
~DecalDefinition() {
if (_diffuseBitmap >= 0) {
bm_release(_diffuseBitmap);
}
if (_glowBitmap >= 0) {
bm_release(_glowBitmap);
}
if (_normalBitmap >= 0) {
bm_release(_normalBitmap);
}
}
// Disallow copying
DecalDefinition(const DecalDefinition&) = delete;
DecalDefinition& operator=(const DecalDefinition&) = delete;
// Move constructor and operator
DecalDefinition(DecalDefinition&& other) {
*this = std::move(other); // Use operator implementation
}
DecalDefinition& operator=(DecalDefinition&& other) {
std::swap(_name, other._name);
std::swap(_diffuseFilename, other._diffuseFilename);
std::swap(_glowFilename, other._glowFilename);
std::swap(_normalMapFilename, other._normalMapFilename);
std::swap(_diffuseBitmap, other._diffuseBitmap);
std::swap(_glowBitmap, other._glowBitmap);
std::swap(_normalBitmap, other._normalBitmap);
std::swap(_loopDiffuse, other._loopDiffuse);
std::swap(_loopGlow, other._loopGlow);
std::swap(_loopNormal, other._loopNormal);
return *this;
}
void parse() {
if (optional_string("+Diffuse:")) {
stuff_string(_diffuseFilename, F_FILESPEC);
if (!bm_validate_filename(_diffuseFilename, true, true)) {
error_display(0, "Animation '%s' is not valid!", _diffuseFilename.c_str());
_diffuseFilename = "";
}
if (optional_string("+Loop:")) {
stuff_boolean(&_loopDiffuse);
}
}
if (optional_string("+Glow:")) {
stuff_string(_glowFilename, F_FILESPEC);
if (!bm_validate_filename(_glowFilename, true, true)) {
error_display(0, "Animation '%s' is not valid!", _glowFilename.c_str());
_glowFilename = "";
}
if (optional_string("+Loop:")) {
stuff_boolean(&_loopGlow);
}
}
if (optional_string("+Normal:")) {
stuff_string(_normalMapFilename, F_FILESPEC);
if (!bm_validate_filename(_normalMapFilename, true, true)) {
error_display(0, "Animation '%s' is not valid!", _normalMapFilename.c_str());
_normalMapFilename = "";
}
if (optional_string("+Loop:")) {
stuff_boolean(&_loopNormal);
}
}
}
void loadBitmaps() {
if (_diffuseBitmap == -1 && VALID_FNAME(_diffuseFilename)) {
_diffuseBitmap = bm_load_either(_diffuseFilename.c_str());
if (_diffuseBitmap == -1) {
Warning(LOCATION,
"Bitmap '%s' failed to load for decal definition %s!",
_diffuseFilename.c_str(),
_name.c_str());
}
}
if (_glowBitmap == -1 && VALID_FNAME(_glowFilename)) {
_glowBitmap = bm_load_either(_glowFilename.c_str());
if (_glowBitmap == -1) {
Warning(LOCATION,
"Bitmap '%s' failed to load for decal definition %s!",
_glowFilename.c_str(),
_name.c_str());
}
}
if (_normalBitmap == -1 && VALID_FNAME(_normalMapFilename)) {
_normalBitmap = bm_load_either(_normalMapFilename.c_str());
if (_normalBitmap == -1) {
Warning(LOCATION,
"Bitmap '%s' failed to load for decal definition %s!",
_normalMapFilename.c_str(),
_name.c_str());
}
}
}
void pageIn() {
if (_diffuseBitmap >= 0) {
bm_page_in_texture(_diffuseBitmap);
}
if (_glowBitmap >= 0) {
bm_page_in_texture(_glowBitmap);
}
if (_normalBitmap >= 0) {
bm_page_in_texture(_normalBitmap);
}
}
bool bitmapsLoaded() {
// Since both bitmap types are optional we need to check if either is loaded to determine if any bitmap is loaded
return _diffuseBitmap >= 0 || _glowBitmap >= 0 || _normalBitmap >= 0;
}
const SCP_string& getName() const {
return _name;
}
int getDiffuseBitmap() const {
return _diffuseBitmap;
}
int getGlowBitmap() const {
return _glowBitmap;
}
int getNormalBitmap() const {
return _normalBitmap;
}
bool isDiffuseLooping() const {
return _loopDiffuse;
}
bool isGlowLooping() const {
return _loopGlow;
}
bool isNormalLooping() const {
return _loopNormal;
}
};
SCP_vector<DecalDefinition> decalDefinitions;
// Variable to indicate if the system is able to work correctly on the current system
bool decal_system_active = true;
void parse_decals_table(const char* filename) {
try {
read_file_text(filename, CF_TYPE_TABLES);
reset_parse();
required_string("#Decals");
while (optional_string("$Decal:")) {
SCP_string name;
stuff_string(name, F_NAME);
DecalDefinition def(name);
def.parse();
decalDefinitions.push_back(std::move(def));
}
required_string("#End");
} catch (const parse::ParseException& e) {
mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", filename, e.what()));
return;
}
if (!gr_is_capable(CAPABILITY_DEFERRED_LIGHTING)) {
// we need deferred lighting
decal_system_active = false;
mprintf(("Note: Decal system has been disabled due to lack of deferred lighting.\n"));
}
if (!gr_is_capable(CAPABILITY_NORMAL_MAP)) {
// We need normal mapping for the full feature range
decal_system_active = false;
mprintf(("Note: Decal system has been disabled due to lack of normal mapping.\n"));
}
if (!gr_is_capable(CAPABILITY_SEPARATE_BLEND_FUNCTIONS)) {
// WWe need separate blending functions for different color buffers
decal_system_active = false;
mprintf(("Note: Decal system has been disabled due to lack of separate color buffer blend functions.\n"));
}
}
struct Decal {
int definition_handle = -1;
object_h object;
int submodel = -1;
float creation_time = -1.0f; //!< The mission time at which this decal was created
float lifetime = -1.0f; //!< The time this decal is active. When negative it never expires
vec3d position = vmd_zero_vector;
vec3d scale;
matrix orientation = vmd_identity_matrix;
Decal() {
vm_vec_make(&scale, 1.f, 1.f, 1.f);
}
bool isValid() {
if (!object.IsValid()) {
return false;
}
if (lifetime > 0.0f) {
if (f2fl(Missiontime) >= creation_time + lifetime) {
// Decal has expired
return false;
}
}
auto objp = object.objp;
if (objp->type == OBJ_SHIP) {
auto shipp = &Ships[objp->instance];
auto model_instance = model_get_instance(shipp->model_instance_num);
Assertion(submodel >= 0 && submodel < model_get(object_get_model(objp))->n_models,
"Invalid submodel number detected!");
auto smi = &model_instance->submodel[submodel];
if (smi->blown_off) {
return false;
}
}
return true;
}
};
SCP_vector<Decal> active_decals;
bool required_string_if_new(const char* token, bool new_entry) {
if (!new_entry) {
return optional_string(token) == 1;
}
required_string(token);
return true;
}
float clamp(float x, float min, float max) {
return std::min(std::max(x, min), max);
}
/**
* @brief Produces a smoothstep value as specified by the GLSL specification
* @param edge0
* @param edge1
* @param x
* @return
*/
float smoothstep(float edge0, float edge1, float x) {
auto t = clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
return t * t * (3.0f - 2.0f * t);
}
}
namespace decals {
void initialize() {
decalDefinitions.clear();
graphics::decal_draw_list::globalInit();
parse_modular_table(NOX("*-dcl.tbm"), parse_decals_table);
}
void shutdown() {
graphics::decal_draw_list::globalShutdown();
// Free allocated resources
decalDefinitions.clear();
}
int getDecalConfig(const SCP_string& name) {
int index = 0;
for (auto& def : decalDefinitions) {
if (!stricmp(def.getName().c_str(), name.c_str())) {
return index;
}
++index;
}
return -1;
}
void parseDecalReference(creation_info& dest_info, bool is_new_entry) {
SCP_string name;
stuff_string(name, F_NAME);
auto decalRef = getDecalConfig(name);
if (decalRef < 0) {
error_display(0, "Decal definition '%s' is unknown!", name.c_str());
}
dest_info.definition_handle = decalRef;
if (required_string_if_new("+Radius:", is_new_entry)) {
stuff_float(&dest_info.radius);
if (dest_info.radius <= 0.0f) {
error_display(0, "Invalid radius of %f! Must be a positive number.", dest_info.radius);
dest_info.radius = 1.0f;
}
}
if (required_string_if_new("+Lifetime:", is_new_entry)) {
if (optional_string("Eternal")) {
dest_info.lifetime = util::UniformFloatRange(-1.0f);
} else {
// Require at least a small lifetime so that the calculations don't have to deal with div-by-zero
dest_info.lifetime = util::parseUniformRange(0.0001f);
}
}
}
void loadBitmaps(const creation_info& info) {
if (!decal_system_active) {
return;
}
// Silently ignore invalid definition handle since weapons use the default values if the decal option is not present
if (info.definition_handle < 0) {
return;
}
Assertion(info.definition_handle >= 0 && info.definition_handle < (int) decalDefinitions.size(),
"Invalid decal handle detected!");
auto& def = decalDefinitions[info.definition_handle];
def.loadBitmaps();
}
void pageInDecal(const creation_info& info) {
if (!decal_system_active) {
return;
}
// Silently ignore invalid definition handle since weapons use the default values if the decal option is not present
if (info.definition_handle < 0) {
return;
}
Assertion(info.definition_handle >= 0 && info.definition_handle < (int) decalDefinitions.size(),
"Invalid decal handle detected!");
decalDefinitions[info.definition_handle].pageIn();
}
void initializeMission() {
active_decals.clear();
}
matrix4 getDecalTransform(Decal& decal) {
Assertion(decal.object.objp->type == OBJ_SHIP, "Only ships are currently supported for decals!");
auto objp = decal.object.objp;
auto ship = &Ships[objp->instance];
vec3d worldPos;
model_instance_find_world_point(&worldPos,
&decal.position,
ship->model_instance_num,
decal.submodel,
&objp->orient,
&objp->pos);
vec3d worldDir;
model_instance_find_world_dir(&worldDir,
&decal.orientation.vec.fvec,
ship->model_instance_num,
decal.submodel,
&objp->orient);
vec3d worldUp;
model_instance_find_world_dir(&worldUp,
&decal.orientation.vec.fvec,
ship->model_instance_num,
decal.submodel,
&objp->orient);
matrix worldOrient;
vm_vector_2_matrix(&worldOrient, &worldDir, &worldUp);
// Apply scaling
worldOrient.a2d[0][0] *= decal.scale.xyz.x;
worldOrient.a2d[0][1] *= decal.scale.xyz.x;
worldOrient.a2d[0][2] *= decal.scale.xyz.x;
worldOrient.a2d[1][0] *= decal.scale.xyz.y;
worldOrient.a2d[1][1] *= decal.scale.xyz.y;
worldOrient.a2d[1][2] *= decal.scale.xyz.y;
worldOrient.a2d[2][0] *= decal.scale.xyz.z;
worldOrient.a2d[2][1] *= decal.scale.xyz.z;
worldOrient.a2d[2][2] *= decal.scale.xyz.z;
matrix4 mat4;
vm_matrix4_set_transform(&mat4, &worldOrient, &worldPos);
return mat4;
}
void renderAll() {
if (!decal_system_active) {
return;
}
// Clear out any invalid decals
for (auto iter = active_decals.begin(); iter != active_decals.end(); ++iter) {
if (!iter->isValid()) {
// if we're sitting on the very last element, popping-back will invalidate the iterator!
if (iter + 1 == active_decals.end()) {
active_decals.pop_back();
break;
}
*iter = active_decals.back();
active_decals.pop_back();
continue;
}
}
if (active_decals.empty()) {
return;
}
graphics::decal_draw_list draw_list;
auto mission_time = f2fl(Missiontime);
for (auto& decal : active_decals) {
int diffuse_bm = -1;
int glow_bm = -1;
int normal_bm = -1;
Assertion(decal.definition_handle >= 0 && decal.definition_handle < (int) decalDefinitions.size(),
"Invalid decal handle detected!");
auto& decalDef = decalDefinitions[decal.definition_handle];
auto decal_time = mission_time - decal.creation_time;
auto progress = decal_time / decal.lifetime;
float alpha = 1.0f;
if (progress > 0.8) {
// Fade the decal out for the last 20% of its lifetime
alpha = 1.0f - smoothstep(0.8f, 1.0f, progress);
}
if (decalDef.getDiffuseBitmap() >= 0) {
diffuse_bm = decalDef.getDiffuseBitmap()
+ bm_get_anim_frame(decalDef.getDiffuseBitmap(), decal_time, 0.0f, decalDef.isDiffuseLooping());
}
if (decalDef.getGlowBitmap() >= 0) {
glow_bm = decalDef.getGlowBitmap()
+ bm_get_anim_frame(decalDef.getGlowBitmap(), decal_time, 0.0f, decalDef.isGlowLooping());
}
if (decalDef.getNormalBitmap() >= 0) {
normal_bm = decalDef.getNormalBitmap()
+ bm_get_anim_frame(decalDef.getNormalBitmap(), decal_time, 0.0f, decalDef.isNormalLooping());
}
draw_list.add_decal(diffuse_bm, glow_bm, normal_bm, decal_time, getDecalTransform(decal), alpha);
}
draw_list.render();
}
void
addDecal(creation_info& info, object* host, int submodel, const vec3d& local_pos, const matrix& local_orient) {
if (!decal_system_active) {
return;
}
// Silently ignore invalid definition handle since weapons use the default values if the decal option is not present
if (info.definition_handle < 0) {
return;
}
Assertion(info.definition_handle >= 0 && info.definition_handle < (int) decalDefinitions.size(),
"Invalid decal handle detected!");
auto& def = decalDefinitions[info.definition_handle];
if (!def.bitmapsLoaded()) {
// If this decal was never used before then the bitmaps are not loaded so we need to do that here.
def.loadBitmaps();
}
Decal newDecal;
newDecal.definition_handle = info.definition_handle;
newDecal.object = object_h(host);
newDecal.submodel = submodel;
newDecal.creation_time = f2fl(Missiontime);
newDecal.lifetime = info.lifetime.next();
newDecal.position = local_pos;
newDecal.orientation = local_orient;
newDecal.scale.xyz.x = info.radius;
newDecal.scale.xyz.y = info.radius;
newDecal.scale.xyz.z = info.radius;
active_decals.push_back(newDecal);
}
}
-87
View File
@@ -1,87 +0,0 @@
#pragma once
#include "globalincs/pstypes.h"
#include "object/object.h"
#include "utils/RandomRange.h"
namespace decals {
/**
* @brief A reference to a decal definition
*/
typedef int DecalReference;
/**
* @brief A structure containing all information for creating a decal
*/
struct creation_info {
DecalReference definition_handle = -1;
float radius = -1.0f;
util::UniformFloatRange lifetime = ::util::UniformFloatRange(-1.0f);
};
/**
* @brief Initializes the global state of the decal system. Call once at game init.
*/
void initialize();
/**
* @brief Parses the information for a decal reference
*
* @details This function expects that the initial token has already been consumed by the parse system.
*
* @param dest_info The creation information struct to parse the information into
* @param is_new_entry Set to @c false if the currently parsed object used +nocreate
*/
void parseDecalReference(creation_info& dest_info, bool is_new_entry = true);
/**
* @brief Loads the bitmaps specified by the creation info into texture memory
*
* This should be called when the bitmaps of the object using this decal are loaded.
*
* @param info The creation information containing the decal definition handle
*/
void loadBitmaps(const creation_info& info);
/**
* @brief Page in the bitmap data of the specified creation information. Needs to be called after loadBitmaps
* @param info The information to page in
*/
void pageInDecal(const creation_info& info);
/**
* @brief Shut down the decal system. Must be called from game_shutdown
*/
void shutdown();
/**
* @brief Initialize the decal system for the mission. Must be called before every mission is started
*/
void initializeMission();
/**
* @brief Renders all currently active decals and removes invalid decals from the active list.
*/
void renderAll();
/**
* @brief Creates a new decal on the specified object at the specified location
*
* @param info The decal to create
* @param host The object host on which to create this decal. Must be a ship.
* @param submodel The submodel of the object model on which to create the decal.
* @param local_pos The position in the frame of reference of the submodel at which the decal should be created.
* @param local_orient The orientation of the decal in the frame of reference of the submodel. The forward vector of the
* orientation should look along the direction
*/
void addDecal(creation_info& info,
object* host,
int submodel,
const vec3d& local_pos,
const matrix& local_orient);
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+3
View File
@@ -0,0 +1,3 @@
#ControlConfigOverride
#End
-18
View File
@@ -1,18 +0,0 @@
#include "gamma.sdr"
in vec4 fragTexCoord;
in vec4 fragColor;
out vec4 fragOut0;
uniform sampler2DArray baseMap;
uniform float intensity;
void main()
{
vec4 baseColor = texture(baseMap, fragTexCoord.xyz);
baseColor.rgb = srgb_to_linear(baseColor.rgb);
vec4 blendColor = vec4(srgb_to_linear(fragColor.rgb), fragColor.a);
fragOut0 = baseColor * blendColor * intensity;
}
-14
View File
@@ -1,14 +0,0 @@
in vec4 vertPosition;
in vec4 vertTexCoord;
in vec4 vertColor;
out vec4 fragTexCoord;
out vec4 fragColor;
uniform mat4 modelViewMatrix;
uniform mat4 projMatrix;
uniform vec4 color;
void main()
{
fragTexCoord = vec4(vertTexCoord.xyz, 0.0);
fragColor = vertColor * color;
gl_Position = projMatrix * modelViewMatrix * vertPosition;
}
-180
View File
@@ -1,180 +0,0 @@
// NOTE: The technique and some of this code is based on this tutorial:
// http://martindevans.me/game-development/2015/02/27/Drawing-Stuff-On-Other-Stuff-With-Deferred-Screenspace-Decals/
#include "lighting.sdr"
#include "normals.sdr"
#include "gamma.sdr"
out vec4 fragOut0; // Diffuse buffer
out vec4 fragOut1; // Normal buffer
out vec4 fragOut2; // Emissive buffer
uniform sampler2D gDepthBuffer;
uniform sampler2D gNormalBuffer;
uniform sampler2DArray diffuseMap;
uniform sampler2DArray glowMap;
uniform sampler2DArray normalMap;
layout (std140) uniform decalGlobalData {
mat4 viewMatrix;
mat4 projMatrix;
mat4 invViewMatrix;
mat4 invProjMatrix;
vec3 ambientLight;
vec2 viewportSize;
};
layout (std140) uniform decalInfoData {
mat4 model_matrix;
mat4 inv_model_matrix;
vec3 decal_direction;
float normal_angle_cutoff;
int diffuse_index;
int glow_index;
int normal_index;
float angle_fade_start;
float alpha_scale;
int diffuse_blend_mode;
int glow_blend_mode;
};
vec3 computeViewPosition(vec2 textureCoord) {
vec4 clipSpaceLocation;
vec2 normalizedCoord = textureCoord / viewportSize;
clipSpaceLocation.xy = normalizedCoord * 2.0f - 1.0f;
clipSpaceLocation.z = texelFetch(gDepthBuffer, ivec2(textureCoord), 0).r * 2.0f - 1.0f;
clipSpaceLocation.w = 1.0f;
vec4 homogenousLocation = invProjMatrix * clipSpaceLocation;
return homogenousLocation.xyz / homogenousLocation.w;
}
vec3 getPixelNormal(vec3 frag_position, vec2 tex_coord, inout float alpha, out vec3 binormal, out vec3 tangent) {
#ifdef USE_NORMAL_MAP
// If we can then we just use the existing normal buffer
vec3 normal = texelFetch(gNormalBuffer, ivec2(tex_coord), 0).xyz;
// If we use the normal map then we don't really need these values so we don't need to compute them here
binormal = vec3(0.0);
tangent = vec3(0.0);
#else
// Use some fancy screen-space derivates to determine the normal of the current pixel by looking at the surrounding pixels
vec3 pos_dx = dFdx(frag_position);
vec3 pos_dy = dFdy(frag_position);
vec3 normal = normalize(cross(pos_dx, pos_dy));
binormal = normalize(pos_dx);
tangent = normalize(pos_dy);
#endif
//Calculate angle between surface normal and decal direction
float angle = acos(dot(normal, decal_direction));
if (angle > normal_angle_cutoff) {
// The angle between surface normal and decal direction is too big
discard;
}
// Make a smooth alpha transition leading up to an edge
alpha = alpha * (1 - smoothstep(angle_fade_start, normal_angle_cutoff, angle));
return normal;
}
vec2 getDecalTexCoord(vec3 view_pos, inout float alpha) {
vec4 object_pos = inv_model_matrix * invViewMatrix * vec4(view_pos, 1.0);
bvec3 invalidComponents = greaterThan(abs(object_pos.xyz), vec3(0.5));
bvec4 nanComponents = isnan(object_pos); // nan can happen some times if we have an infinite depth value
if (any(invalidComponents) || any(nanComponents)) {
// Fragment is out of the box
discard;
}
// Fade out the texture when it gets close to the top or bottom of the decal box
alpha = alpha * (1.0 - smoothstep(0.4, 0.5, abs(object_pos.z)));
return object_pos.xy + 0.5;
}
void main() {
vec3 frag_position = computeViewPosition(gl_FragCoord.xy);
float alpha = alpha_scale;
vec2 tex_coord = getDecalTexCoord(frag_position, alpha);
vec3 binormal;
vec3 tangent;
vec3 normal = getPixelNormal(frag_position, gl_FragCoord.xy, alpha, binormal, tangent);
vec4 diffuse_out = vec4(0.0);
vec4 emissive_out = vec4(0.0, 0.0, 0.0, 0.0);
vec3 normal_out = vec3(0.0);
if (diffuse_index >= 0) {
// We have a valid diffuse map
vec4 color = texture(diffuseMap, vec3(tex_coord, float(diffuse_index)));
color.rgb = srgb_to_linear(color.rgb);
if (diffuse_blend_mode == 0) {
// Normal alpha blending
diffuse_out = vec4(color.rgb, color.a * alpha);
} else {
// Additive blending
diffuse_out = vec4(color.rgb * alpha, 1.0);
}
// The main model shader applies ambient lighting by drawing the ambient part of the texture into the emissive
// texture. We do the same here to make sure the decal material is applied correctly
if (glow_blend_mode == 0) {
// Normal alpha blending
emissive_out = vec4(color.rgb * ambientLight, color.a * alpha);
} else {
// Additive blending
emissive_out = vec4(alpha * color.rgb * ambientLight, 1.0);
}
}
if (glow_index >= 0) {
// We have a valid diffuse map
vec4 color = texture(glowMap, vec3(tex_coord, float(glow_index)));
color.rgb = srgb_to_linear(color.rgb) * GLOW_MAP_SRGB_MULTIPLIER;
color.rgb *= GLOW_MAP_INTENSITY;
if (glow_blend_mode == 0) {
// Normal alpha blending
emissive_out = vec4(color.rgb + emissive_out.rgb * emissive_out.a, color.a * alpha);
} else {
// Additive blending
emissive_out.rgb += color.rgb * alpha;
}
}
if (normal_index >= 0) {
vec3 decalNormal = unpackNormal(texture(normalMap, vec3(tex_coord, float(normal_index))).ag);
mat3 tangentToView;
tangentToView[0] = tangent;
tangentToView[1] = binormal;
tangentToView[2] = normal;
normal_out = tangentToView * decalNormal * alpha;
}
fragOut0 = diffuse_out;
fragOut1 = vec4(normal_out, 0.0);
fragOut2 = emissive_out;
}
-33
View File
@@ -1,33 +0,0 @@
in vec4 vertPosition;
layout (std140) uniform decalGlobalData {
mat4 viewMatrix;
mat4 projMatrix;
mat4 invViewMatrix;
mat4 invProjMatrix;
vec3 ambientLight;
vec2 viewportSize;
};
layout (std140) uniform decalInfoData {
mat4 model_matrix;
mat4 inv_model_matrix;
vec3 decal_direction;
float normal_angle_cutoff;
int diffuse_index;
int glow_index;
int normal_index;
float angle_fade_start;
float alpha_scale;
int diffuse_blend_mode;
int glow_blend_mode;
};
void main() {
gl_Position = projMatrix * viewMatrix * model_matrix * vertPosition;
}
-138
View File
@@ -1,138 +0,0 @@
#include "lighting.sdr"
#include "shadows.sdr"
in vec3 beamVec;
in vec3 lightPosition;
out vec4 fragOut0;
uniform sampler2D ColorBuffer;
uniform sampler2D NormalBuffer;
uniform sampler2D PositionBuffer;
uniform sampler2D SpecBuffer;
uniform sampler2DArray shadow_map;
layout (std140) uniform globalDeferredData {
mat4 shadow_mv_matrix;
mat4 shadow_proj_matrix[4];
mat4 inv_view_matrix;
float veryneardist;
float neardist;
float middist;
float fardist;
float specFactor;
float invScreenWidth;
float invScreenHeight;
};
layout (std140) uniform lightData {
vec3 diffuseLightColor;
float coneAngle;
vec3 specLightColor;
float coneInnerAngle;
vec3 coneDir;
bool dualCone;
vec3 scale;
float lightRadius;
vec3 lightDir;
int lightType;
bool enable_shadows;
};
void GetLightInfo(vec3 position, out vec3 lightDir, out float attenuation)
{
if (lightType == LT_DIRECTIONAL) {
lightDir = normalize(lightPosition);
attenuation = 1.0;
} else {
// Positional light source
lightDir = lightPosition - position.xyz;
float dist = length(lightDir);
attenuation = 1.0 - clamp(dist / lightRadius, 0.0, 1.0);
if(dist > lightRadius && lightType != LT_TUBE) {
discard;
}
if (lightType == LT_TUBE) { // Tube light
float beamLength = length(beamVec);
vec3 beamDir = beamVec / beamLength;
// Get nearest point on line
float neardist = clamp(dot(lightDir, beamDir), 0.0, beamLength);
// Move back from the endpoint of the beam along the beam by the distance we calculated
vec3 nearest = lightPosition - beamDir * neardist;
lightDir = nearest - position.xyz;
dist = length(lightDir);
if(dist > lightRadius) {
discard;
}
} else if (lightType == LT_CONE) {
float coneDot = dot(normalize(-lightDir), coneDir);
if(dualCone) {
if(abs(coneDot) < coneAngle) {
discard;
} else {
attenuation *= smoothstep(coneAngle, coneInnerAngle, abs(coneDot));
}
} else {
if (coneDot < coneAngle) {
discard;
} else {
attenuation *= smoothstep(coneAngle, coneInnerAngle, coneDot);
}
}
}
lightDir = normalize(lightDir);
}
}
void main()
{
vec2 screenPos = gl_FragCoord.xy * vec2(invScreenWidth, invScreenHeight);
vec3 position = texture(PositionBuffer, screenPos).xyz;
if(abs(dot(position, position)) < 0.1)
discard;
vec3 color = texture(ColorBuffer, screenPos).rgb;
vec4 normalData = texture(NormalBuffer, screenPos);
vec4 specColor = texture(SpecBuffer, screenPos);
// The vector in the normal buffer could be longer than the unit vector since decal rendering only adds to the normal buffer
vec3 normal = normalize(normalData.xyz);
float gloss = normalData.a;
float fresnel = specColor.a;
vec3 eyeDir = normalize(-position);
vec3 lightDir;
float attenuation;
GetLightInfo(position, lightDir, attenuation);
if (enable_shadows) {
vec4 fragShadowPos = shadow_mv_matrix * inv_view_matrix * vec4(position, 1.0);
vec4 fragShadowUV[4];
fragShadowUV[0] = transformToShadowMap(shadow_proj_matrix[0], 0, fragShadowPos);
fragShadowUV[1] = transformToShadowMap(shadow_proj_matrix[1], 1, fragShadowPos);
fragShadowUV[2] = transformToShadowMap(shadow_proj_matrix[2], 2, fragShadowPos);
fragShadowUV[3] = transformToShadowMap(shadow_proj_matrix[3], 3, fragShadowPos);
attenuation *= getShadowValue(shadow_map, -position.z, fragShadowPos.z, fragShadowUV, fardist, middist,
neardist, veryneardist);
}
vec3 halfVec = normalize(lightDir + eyeDir);
float NdotL = clamp(dot(normal, lightDir), 0.0, 1.0);
vec4 fragmentColor = vec4(color * (diffuseLightColor * NdotL * attenuation), 1.0);
fragmentColor.rgb += computeLighting(specColor.rgb, lightDir, normal.xyz, halfVec, eyeDir, gloss, fresnel, NdotL).rgb * specLightColor * attenuation;
fragOut0 = max(fragmentColor, vec4(0.0));
}
@@ -1,40 +0,0 @@
#include "lighting.sdr"
in vec4 vertPosition;
uniform mat4 modelViewMatrix;
uniform mat4 projMatrix;
layout (std140) uniform lightData {
vec3 diffuseLightColor;
float coneAngle;
vec3 specLightColor;
float coneInnerAngle;
vec3 coneDir;
bool dualCone;
vec3 scale;
float lightRadius;
vec3 lightDir;
int lightType;
bool enable_shadows;
};
out vec3 lightPosition;
out vec3 beamVec;
void main()
{
if (lightType == LT_DIRECTIONAL) {
gl_Position = vec4(vertPosition.xyz, 1.0);
lightPosition = lightDir;
} else {
gl_Position = projMatrix * modelViewMatrix * vec4(vertPosition.xyz * scale, 1.0);
lightPosition = modelViewMatrix[3].xyz;
if(lightType == LT_TUBE)
beamVec = vec3(modelViewMatrix * vec4(0.0, 0.0, -scale.z, 0.0));
}
}
-34
View File
@@ -1,34 +0,0 @@
#include "gamma.sdr"
in vec4 fragTexCoord;
out vec4 fragOut0;
uniform sampler2D tex;
uniform sampler2D depth_tex;
uniform float fog_start;
uniform float fog_scale;
uniform vec3 fog_color;
uniform float zNear;
uniform float zFar;
void main()
{
vec4 color_in = texture(tex, fragTexCoord.xy);
// If the scene is in fog then we change the color we operate on based on the depth of the pixel
float depth_val = texture(depth_tex, fragTexCoord.xy).x;
// Transform depth value from [-1, 1] to [0, 1]
float depth_normalized = 2.0 * depth_val - 1.0;
// Now we compute the depth value in projection space using the clipping plane information
float view_depth = 2.0 * zNear * zFar / (zFar + zNear - depth_normalized * (zFar - zNear));
// This is the same formula that is also used by the main shader
float fog_dist = isinf(view_depth) ? 1.0 : clamp((view_depth - fog_start) * 0.75 * fog_scale, 0.0, 1.0);
vec3 finalFogColor = srgb_to_linear(fog_color);
fragOut0.rgb = mix(color_in.rgb, finalFogColor, fog_dist);
fragOut0.a = 1.0;
}
-29
View File
@@ -1,29 +0,0 @@
const float SRGB_GAMMA = 2.2;
const float SRGB_GAMMA_INVERSE = 1.0 / SRGB_GAMMA;
float srgb_to_linear(float val) {
return pow(val, SRGB_GAMMA);
}
vec2 srgb_to_linear(vec2 val) {
return pow(val, vec2(SRGB_GAMMA));
}
vec3 srgb_to_linear(vec3 val) {
return pow(val, vec3(SRGB_GAMMA));
}
vec4 srgb_to_linear(vec4 val) {
return pow(val, vec4(SRGB_GAMMA));
}
float linear_to_srgb(float val) {
return pow(val, SRGB_GAMMA_INVERSE);
}
vec2 linear_to_srgb(vec2 val) {
return pow(val, vec2(SRGB_GAMMA_INVERSE));
}
vec3 linear_to_srgb(vec3 val) {
return pow(val, vec3(SRGB_GAMMA_INVERSE));
}
vec4 linear_to_srgb(vec4 val) {
return pow(val, vec4(SRGB_GAMMA_INVERSE));
}
-58
View File
@@ -1,58 +0,0 @@
const int LT_DIRECTIONAL = 0; // A light like a sun
const int LT_POINT = 1; // A point light, like an explosion
const int LT_TUBE = 2; // A tube light, like a fluorescent light
const int LT_CONE = 3; // A cone light, like a flood light
const float SPEC_INTENSITY_POINT = 5.3 ;// Point light
const float SPEC_INTENSITY_DIRECTIONAL = 3.0 ;// Directional light
const float SPECULAR_FACTOR = 1.75;
const float SPECULAR_ALPHA = 0.1;
const float SPEC_FACTOR_NO_SPEC_MAP = 0.6;
const float ENV_ALPHA_FACTOR = 0.3;
const float GLOW_MAP_INTENSITY = 1.5;
const float AMBIENT_LIGHT_BOOST = 1.0;
const float GLOW_MAP_SRGB_MULTIPLIER = 3.0;
vec3 FresnelSchlick(vec3 specColor, vec3 light, vec3 halfVec)
{
return specColor + (vec3(1.0) - specColor) * pow(1.0 - clamp(dot(light, halfVec), 0.0, 1.0), 5.0);
}
vec3 SpecularBlinnPhong(vec3 specColor, vec3 light, vec3 normal, vec3 halfVec, float specPower, float fresnel, float dotNL)
{
return mix(specColor, FresnelSchlick(specColor, light, halfVec), fresnel) * ((specPower + 2.0) / 8.0 ) * pow(clamp(dot(normal, halfVec), 0.0, 1.0), specPower) * dotNL;
}
vec3 SpecularGGX(vec3 specColor, vec3 light, vec3 normal, vec3 halfVec, vec3 view, float gloss, float fresnelFactor, float dotNL)
{
float roughness = clamp(1.0f - gloss, 0.0f, 1.0f);
float alpha = roughness * roughness;
float dotNH = clamp(dot(normal, halfVec), 0.0f, 1.0f);
float dotNV = clamp(dot(normal, view), 0.0f, 1.0f);
float alphaSqr = alpha * alpha;
float pi = 3.14159f;
float denom = dotNH * dotNH * (alphaSqr - 1.0f) + 1.0f;
float distribution = alphaSqr / (pi * denom * denom);
vec3 fresnel = mix(specColor, FresnelSchlick(specColor, light, halfVec), fresnelFactor);
float alphaPrime = roughness + 1.0f;
float k = alphaPrime * alphaPrime / 8.0f;
float g1vNL = 1.0f / (dotNL * (1.0f - k) + k);
float g1vNV = 1.0f / (dotNV * (1.0f - k) + k);
float visibility = g1vNL * g1vNV;
return distribution * fresnel * visibility * dotNL;
}
vec3 computeLighting(vec3 specColor, vec3 light, vec3 normal, vec3 halfVec, vec3 view, float gloss, float fresnelFactor, float dotNL)
{
#ifdef FLAG_LIGHT_MODEL_BLINN_PHONG
return SpecularBlinnPhong(specColor, light, normal, halfVec, 32, fresnelFactor, dotNL);
#else
return SpecularGGX(specColor, light, normal, halfVec, view, gloss, fresnelFactor, dotNL);
#endif
}
-512
View File
@@ -1,512 +0,0 @@
#ifdef FEATURE_BINDLESS_TEXTURES
#extension GL_ARB_bindless_texture : require
#endif
#include "shadows.sdr"
#include "lighting.sdr"
#include "gamma.sdr"
#define MAX_LIGHTS 8
#define LT_DIRECTIONAL 0
#define LT_POINT 1
#define LT_TUBE 2
struct model_light {
vec4 position;
vec3 diffuse_color;
int light_type;
vec3 spec_color;
float attenuation;
vec3 direction;
};
#ifdef FEATURE_BINDLESS_TEXTURES
layout (std140) uniform modelData {
mat4 modelViewMatrix;
mat4 modelMatrix;
mat4 viewMatrix;
mat4 projMatrix;
mat4 textureMatrix;
mat4 shadow_mv_matrix;
mat4 shadow_proj_matrix[4];
mat4 envMatrix;
vec4 color;
model_light lights[MAX_LIGHTS];
float extrudeWidth;
float fogStart;
float fogScale;
int buffer_matrix_offset;
vec4 clip_equation;
float thruster_scale;
bool use_clip_plane;
int n_lights;
float defaultGloss;
vec3 ambientFactor;
int desaturate;
vec3 diffuseFactor;
int blend_alpha;
vec3 emissionFactor;
bool overrideDiffuse;
vec3 diffuseClr;
bool overrideGlow;
vec3 glowClr;
bool overrideSpec;
vec3 specClr;
bool alphaGloss;
bool gammaSpec;
bool envGloss;
bool alpha_spec;
int effect_num;
vec4 fogColor;
vec3 base_color;
float anim_timer;
vec3 stripe_color;
float vpwidth;
float vpheight;
bool team_glow_enabled;
float znear;
float zfar;
float veryneardist;
float neardist;
float middist;
float fardist;
vec2 normalAlphaMinMax;
int sBasemapIndex;
int sGlowmapIndex;
int sSpecmapIndex;
int sNormalmapIndex;
int sAmbientmapIndex;
int sMiscmapIndex;
sampler2DArray sBasemap;
sampler2DArray sGlowmap;
sampler2DArray sSpecmap;
samplerCube sEnvmap;
sampler2DArray sNormalmap;
sampler2DArray sAmbientmap;
sampler2DArray sMiscmap;
sampler2DArray sHeightmap;
};
#else
layout (std140) uniform modelData {
mat4 modelViewMatrix;
mat4 modelMatrix;
mat4 viewMatrix;
mat4 projMatrix;
mat4 textureMatrix;
mat4 shadow_mv_matrix;
mat4 shadow_proj_matrix[4];
mat4 envMatrix;
vec4 color;
model_light lights[MAX_LIGHTS];
float extrudeWidth;
float fogStart;
float fogScale;
int buffer_matrix_offset;
vec4 clip_equation;
float thruster_scale;
bool use_clip_plane;
int n_lights;
float defaultGloss;
vec3 ambientFactor;
int desaturate;
vec3 diffuseFactor;
int blend_alpha;
vec3 emissionFactor;
bool overrideDiffuse;
vec3 diffuseClr;
bool overrideGlow;
vec3 glowClr;
bool overrideSpec;
vec3 specClr;
bool alphaGloss;
bool gammaSpec;
bool envGloss;
bool alpha_spec;
int effect_num;
vec4 fogColor;
vec3 base_color;
float anim_timer;
vec3 stripe_color;
float vpwidth;
float vpheight;
bool team_glow_enabled;
float znear;
float zfar;
float veryneardist;
float neardist;
float middist;
float fardist;
vec2 normalAlphaMinMax;
int sBasemapIndex;
int sGlowmapIndex;
int sSpecmapIndex;
int sNormalmapIndex;
int sAmbientmapIndex;
int sMiscmapIndex;
};
uniform sampler2DArray sBasemap;
uniform sampler2DArray sGlowmap;
uniform sampler2DArray sSpecmap;
uniform samplerCube sEnvmap;
uniform sampler2DArray sNormalmap;
uniform sampler2DArray sAmbientmap;
uniform sampler2DArray sMiscmap;
#endif
uniform sampler2D sFramebuffer;
uniform sampler2DArray shadow_map;
in VertexOutput {
#ifdef FLAG_ENV_MAP
vec3 envReflect;
#endif
#ifdef FLAG_NORMAL_MAP
mat3 tangentMatrix;
#endif
#ifdef FLAG_FOG
float fogDist;
#endif
#ifdef WORKAROUND_CLIPPING_PLANES
#ifdef FLAG_TRANSFORM
float notVisible;
#endif
#endif
vec4 position;
vec3 normal;
vec4 texCoord;
#ifdef FLAG_SHADOWS
vec4 shadowUV[4];
vec4 shadowPos;
#endif
} vertIn;
#ifdef FLAG_TEAMCOLOR
vec2 teamMask = vec2(0.0, 0.0);
#endif
out vec4 fragOut0;
out vec4 fragOut1;
out vec4 fragOut2;
out vec4 fragOut3;
out vec4 fragOut4;
vec3 FresnelLazarovEnv(vec3 specColor, vec3 view, vec3 normal, float gloss)
{
// Fresnel for environment lighting
// Equation referenced from Dimitar Lazarov's presentation titled Physically Based Rendering in Call of Duty: Black Ops
return specColor + (vec3(1.0) - specColor) * pow(1.0 - clamp(dot(view, normal), 0.0, 1.0), 5.0) / (4.0 - 3.0 * gloss);
}
void GetLightInfo(int i, out vec3 lightDir, out float attenuation)
{
lightDir = normalize(lights[i].position.xyz);
attenuation = 1.0;
if (lights[i].light_type != LT_DIRECTIONAL) {
// Positional light source
float dist = distance(lights[i].position.xyz, vertIn.position.xyz);
lightDir = (lights[i].position.xyz - vertIn.position.xyz);
if (lights[i].light_type == LT_TUBE) { // Tube light
float beamlength = length(lights[i].direction);
vec3 beamDir = normalize(lights[i].direction);
// Get nearest point on line
float neardist = dot(vertIn.position.xyz - lights[i].position.xyz, beamDir);
// Move back from the endpoint of the beam along the beam by the distance we calculated
vec3 nearest = lights[i].position.xyz - beamDir * abs(neardist);
lightDir = nearest - vertIn.position.xyz;
dist = length(lightDir);
}
lightDir = normalize(lightDir);
attenuation = 1.0 / (1.0 + lights[i].attenuation * dist);
}
}
vec3 CalculateLighting(vec3 normal, vec3 diffuseMaterial, vec3 specularMaterial, float gloss, float fresnel, float shadow, float aoFactor)
{
vec3 eyeDir = vec3(normalize(-vertIn.position).xyz);
vec3 lightAmbient = (emissionFactor + ambientFactor * ambientFactor) * aoFactor; // ambientFactor^2 due to legacy OpenGL compatibility behavior
vec3 lightDiffuse = vec3(0.0, 0.0, 0.0);
vec3 lightSpecular = vec3(0.0, 0.0, 0.0);
#pragma optionNV unroll all
for (int i = 0; i < n_lights; ++i) {
if(i > 0) {
shadow = 1.0;
}
vec3 lightDir;
float attenuation;
// gather light params
GetLightInfo(i, lightDir, attenuation);
vec3 halfVec = normalize(lightDir + eyeDir);
float NdotL = clamp(dot(normal, lightDir), 0.0f, 1.0f);
// Ambient, Diffuse, and Specular
lightDiffuse += (lights[i].diffuse_color.rgb * diffuseFactor * NdotL * attenuation) * shadow;
lightSpecular += lights[i].spec_color * computeLighting(specularMaterial, lightDir, normal, halfVec, eyeDir, gloss, fresnel, NdotL) * attenuation * shadow;
}
return diffuseMaterial * (lightAmbient + lightDiffuse) + lightSpecular;
}
void main()
{
#ifdef WORKAROUND_CLIPPING_PLANES
#ifdef FLAG_TRANSFORM
if(vertIn.notVisible >= 0.9) { discard; }
#endif
#endif
#ifdef FLAG_SHADOW_MAP
// need depth and depth squared for variance shadow maps
fragOut0 = vec4(vertIn.position.z, vertIn.position.z * vertIn.position.z * VARIANCE_SHADOW_SCALE_INV, 0.0, 1.0);
if (true) {
return;
}
#endif
vec3 eyeDir = vec3(normalize(-vertIn.position).xyz);
vec2 texCoord = vertIn.texCoord.xy;
vec4 baseColor = color;
vec4 specColor = vec4(0.0, 0.0, 0.0, 1.0);
vec4 emissiveColor = vec4(0.0, 0.0, 0.0, 1.0);
float fresnelFactor = 0.0;
float glossData = 0.6;
#ifdef FLAG_LIGHT
glossData = defaultGloss;
#endif
vec2 aoFactors = vec2(1.0, 1.0);
#ifdef FLAG_AMBIENT_MAP
// red channel is ambient occlusion factor which only affects ambient lighting.
// green is cavity occlusion factor which only affects diffuse and specular lighting.
aoFactors = texture(sAmbientmap, vec3(texCoord, float(sAmbientmapIndex))).xy;
#endif
vec3 unitNormal = normalize(vertIn.normal);
vec3 normal = unitNormal;
#ifdef FLAG_NORMAL_MAP
// Normal map - convert from DXT5nm
vec2 normalSample;
normal.rg = normalSample = (texture(sNormalmap, vec3(texCoord, float(sNormalmapIndex))).ag * 2.0) - 1.0;
normal.b = clamp(sqrt(1.0 - dot(normal.rg, normal.rg)), 0.0001, 1.0);
normal = vertIn.tangentMatrix * normal;
float norm = length(normal);
// prevent breaking of normal maps
if (norm > 0.0)
normal /= norm;
else
normal = unitNormal;
#endif
#ifdef FLAG_ANIMATED
vec2 distort = vec2(cos(vertIn.position.x*vertIn.position.w*0.005+anim_timer*20.0)*sin(vertIn.position.y*vertIn.position.w*0.005),sin(vertIn.position.x*vertIn.position.w*0.005+anim_timer*20.0)*cos(vertIn.position.y*vertIn.position.w*0.005))*0.03;
#endif
#ifdef FLAG_DIFFUSE_MAP
vec2 diffuseTexCoord = texCoord;
#ifdef FLAG_ANIMATED
if (effect_num == 2) {
diffuseTexCoord = texCoord + distort*(1.0-anim_timer);
}
#endif
baseColor = texture(sBasemap, vec3(diffuseTexCoord, float(sBasemapIndex)));
if ( blend_alpha == 0 && baseColor.a < 0.95 ) discard; // if alpha blending is not on, discard transparent pixels
// premultiply alpha if blend_alpha is 1. assume that our blend function is srcColor + (1-Alpha)*destColor.
// if blend_alpha is 2, assume blend func is additive and don't modify color
if(blend_alpha == 1) baseColor.rgb = baseColor.rgb * baseColor.a;
if(overrideDiffuse) baseColor.rgb = diffuseClr;
#endif
specColor = vec4(baseColor.rgb * SPEC_FACTOR_NO_SPEC_MAP, glossData);
#ifdef FLAG_HDR
baseColor.rgb = srgb_to_linear(baseColor.rgb);
#endif
#ifdef FLAG_SPEC_MAP
specColor = texture(sSpecmap, vec3(texCoord, float(sSpecmapIndex)));
if(alphaGloss) glossData = specColor.a;
if(overrideSpec) {
specColor.rgb = specClr;
fresnelFactor = 1.0;
}
if(gammaSpec) {
specColor.rgb = max(specColor.rgb, vec3(0.03f)); // hardcoded minimum specular value. read John Hable's blog post titled 'Everything Is Shiny'.
#ifdef FLAG_HDR
specColor.rgb = srgb_to_linear(specColor.rgb);
#endif
fresnelFactor = 1.0;
}
#endif
baseColor.rgb *= aoFactors.y;
specColor.rgb *= aoFactors.y;
#ifdef FLAG_MISC_MAP
#ifdef FLAG_TEAMCOLOR
vec4 teamMask = vec4(0.0, 0.0, 0.0, 0.0);
teamMask = texture(sMiscmap, vec3(texCoord, float(sMiscmapIndex)));
//For team colors applied to a diffuse or spec map, we assume that the base color of the diffuse
//at this point is vec3(0.5). To get accurate results, we subtract 0.5 from the team colors
vec3 team_color = ((base_color - vec3(0.5)) * teamMask.x) + ((stripe_color - vec3(0.5)) * teamMask.y);
vec3 team_color_glow = (base_color * teamMask.b) + (stripe_color * teamMask.a);
#ifdef FLAG_HDR
team_color = srgb_to_linear(team_color);
team_color_glow = srgb_to_linear(team_color_glow) * GLOW_MAP_SRGB_MULTIPLIER;
#endif
baseColor.rgb += team_color;
baseColor.rgb = max(baseColor.rgb, vec3(0.0)); // We need to make sure that nothing here ever goes negative
specColor.rgb += team_color;
specColor.rgb = max(specColor.rgb, vec3(0.03));
#endif
#endif
// Lights aren't applied when we are rendering to the G-buffers since that gets handled later
#ifdef FLAG_DEFERRED
#ifdef FLAG_LIGHT
// Ambient lighting still needs to be done since that counts as an "emissive" color
vec3 lightAmbient = (emissionFactor + ambientFactor * ambientFactor) * aoFactors.x; // ambientFactor^2 due to legacy OpenGL compatibility behavior
emissiveColor.rgb += baseColor.rgb * lightAmbient;
#else
#ifdef FLAG_SPEC_MAP
baseColor.rgb += pow(1.0 - clamp(dot(eyeDir, normal), 0.0, 1.0), 5.0 * clamp(glossData, 0.01, 1.0)) * specColor.rgb;
#endif
// If there is no lighting then we copy the color data so far into the
emissiveColor.rgb += baseColor.rgb;
#endif
#else
#ifdef FLAG_LIGHT
float shadow = 1.0;
#ifdef FLAG_SHADOWS
shadow = getShadowValue(shadow_map, -vertIn.position.z, vertIn.shadowPos.z, vertIn.shadowUV, fardist, middist, neardist, veryneardist);
#endif
baseColor.rgb = CalculateLighting(normal, baseColor.rgb, specColor.rgb, glossData, fresnelFactor, shadow, aoFactors.x);
#else
#ifdef FLAG_SPEC_MAP
baseColor.rgb += pow(1.0 - clamp(dot(eyeDir, normal), 0.0, 1.0), 5.0 * clamp(glossData, 0.01, 1.0)) * specColor.rgb;
#endif
#endif
#endif
#ifdef FLAG_ENV_MAP
vec3 envReflectNM = vertIn.envReflect;
#ifdef FLAG_NORMAL_MAP
envReflectNM += vec3(normalSample, 0.0);
envReflectNM = normalize(envReflectNM);
#endif
float mip = (envGloss) ? (1.0 - glossData) * 7.0 : 0.0;
vec4 envColour = textureLod(sEnvmap, envReflectNM, mip);
#ifdef FLAG_HDR
envColour.rgb = srgb_to_linear(envColour.rgb);
#endif
envColour.rgb *= (envGloss) ? 1.0 : specColor.a;
emissiveColor.rgb += envColour.rgb * FresnelLazarovEnv(specColor.rgb, eyeDir, normal, glossData);
#endif
#ifdef FLAG_GLOW_MAP
vec3 glowColor = texture(sGlowmap, vec3(texCoord, float(sGlowmapIndex))).rgb;
if(overrideGlow) glowColor = glowClr;
#ifdef FLAG_HDR
glowColor = srgb_to_linear(glowColor) * GLOW_MAP_SRGB_MULTIPLIER;
#endif
#ifdef FLAG_MISC_MAP
#ifdef FLAG_TEAMCOLOR
float glowColorLuminance = dot(glowColor, vec3(0.299, 0.587, 0.114));
glowColor = team_glow_enabled ? mix(max(team_color_glow, vec3(0.0)), glowColor, clamp(glowColorLuminance - teamMask.b - teamMask.a, 0.0, 1.0)) : glowColor;
#endif
#endif
emissiveColor.rgb += glowColor * GLOW_MAP_INTENSITY;
#endif
#ifdef FLAG_FOG
vec3 finalFogColor = fogColor.rgb;
#ifdef FLAG_HDR
finalFogColor = srgb_to_linear(finalFogColor);
#endif
#ifdef FLAG_DIFFUSE_MAP
if(blend_alpha == 1) finalFogColor *= baseColor.a;
#endif
baseColor.rgb = mix(baseColor.rgb, finalFogColor, vertIn.fogDist);
emissiveColor.rgb = mix(emissiveColor.rgb, finalFogColor, vertIn.fogDist);
specColor.rgb *= vertIn.fogDist;
#endif
#ifdef FLAG_DIFFUSE_MAP
if(desaturate == 1) {
baseColor.rgb = color.rgb * dot(vec3(1.0), baseColor.rgb) * 0.3333333;
}
#endif
#ifdef FLAG_ANIMATED
if (effect_num == 0) {
float shinefactor = 1.0/(1.0 + pow(abs((fract(abs(texCoord.x))-anim_timer) * 1000.0), 2.0)) * 1000.0;
emissiveColor.rgb += vec3(shinefactor);
baseColor.a = baseColor.a * clamp(shinefactor * (fract(abs(texCoord.x))-anim_timer) * -10000.0,0.0,1.0);
}
if (effect_num == 1) {
float shinefactor = 1.0/(1.0 + pow(abs(vertIn.position.y-anim_timer), 2.0));
emissiveColor.rgb += vec3(shinefactor);
#ifndef FLAG_LIGHT
// ATI Wireframe fix *grumble*
baseColor.a = clamp((vertIn.position.y-anim_timer) * 10000.0,0.0,1.0);
#endif
}
if (effect_num == 2) {
vec2 screenPos = gl_FragCoord.xy * vec2(vpwidth,vpheight);
baseColor.a = baseColor.a;
float cloak_interp = (sin(vertIn.position.x*vertIn.position.w*0.005+anim_timer*20.0)*sin(vertIn.position.y*vertIn.position.w*0.005)*0.5)-0.5;
#ifdef FLAG_LIGHT
baseColor.rgb = mix(texture(sFramebuffer, screenPos + distort*anim_timer + anim_timer*0.1*normal.xy).rgb,baseColor.rgb,clamp(cloak_interp+anim_timer*2.0,0.0,1.0));
#else
baseColor.rgb = mix(texture(sFramebuffer, screenPos + distort*anim_timer + anim_timer*0.1*vertIn.normal.xy).rgb,baseColor.rgb,clamp(cloak_interp+anim_timer*2.0,0.0,1.0));
#endif
}
#endif
#ifdef FLAG_NORMAL_ALPHA
float normViewOffset = dot(vec3(0.0, 0.0, 1.0), normal);
baseColor.a = smoothstep(min(normalAlphaMinMax.x, normalAlphaMinMax.y), max(normalAlphaMinMax.x, normalAlphaMinMax.y), clamp(normalAlphaMinMax.x > normalAlphaMinMax.y ? normViewOffset : 1.0 - normViewOffset, 0.0, 1.0));
#endif
#ifndef FLAG_DEFERRED
// emissive colors won't be added later when we are using forward rendering so we need to do that here
baseColor.rgb += emissiveColor.rgb;
#endif
fragOut0 = baseColor;
#ifdef FLAG_DEFERRED
fragOut1 = vec4(vertIn.position.xyz, 1.0);
fragOut2 = vec4(normal, glossData);
fragOut3 = vec4(specColor.rgb, fresnelFactor);
fragOut4 = emissiveColor;
#endif
}
-296
View File
@@ -1,296 +0,0 @@
#extension GL_ARB_gpu_shader5: enable
#ifdef FEATURE_BINDLESS_TEXTURES
#extension GL_ARB_bindless_texture : require
#endif
layout (triangles) in;
layout (triangle_strip, max_vertices = 3) out;
#ifdef GL_ARB_gpu_shader5
layout(invocations = 4) in;
#endif
#define MAX_LIGHTS 8
struct model_light {
vec4 position;
vec3 diffuse_color;
int light_type;
vec3 spec_color;
float attenuation;
vec3 direction;
};
#ifdef FEATURE_BINDLESS_TEXTURES
layout (std140) uniform modelData {
mat4 modelViewMatrix;
mat4 modelMatrix;
mat4 viewMatrix;
mat4 projMatrix;
mat4 textureMatrix;
mat4 shadow_mv_matrix;
mat4 shadow_proj_matrix[4];
mat4 envMatrix;
vec4 color;
model_light lights[MAX_LIGHTS];
float extrudeWidth;
float fogStart;
float fogScale;
int buffer_matrix_offset;
vec4 clip_equation;
float thruster_scale;
bool use_clip_plane;
int n_lights;
float defaultGloss;
vec3 ambientFactor;
int desaturate;
vec3 diffuseFactor;
int blend_alpha;
vec3 emissionFactor;
bool overrideDiffuse;
vec3 diffuseClr;
bool overrideGlow;
vec3 glowClr;
bool overrideSpec;
vec3 specClr;
bool alphaGloss;
bool gammaSpec;
bool envGloss;
bool alpha_spec;
int effect_num;
vec4 fogColor;
vec3 base_color;
float anim_timer;
vec3 stripe_color;
float vpwidth;
float vpheight;
bool team_glow_enabled;
float znear;
float zfar;
float veryneardist;
float neardist;
float middist;
float fardist;
vec2 normalAlphaMinMax;
int sBasemapIndex;
int sGlowmapIndex;
int sSpecmapIndex;
int sNormalmapIndex;
int sAmbientmapIndex;
int sMiscmapIndex;
sampler2DArray sBasemap;
sampler2DArray sGlowmap;
sampler2DArray sSpecmap;
samplerCube sEnvmap;
sampler2DArray sNormalmap;
sampler2DArray sAmbientmap;
sampler2DArray sMiscmap;
sampler2DArray sHeightmap;
};
#else
layout (std140) uniform modelData {
mat4 modelViewMatrix;
mat4 modelMatrix;
mat4 viewMatrix;
mat4 projMatrix;
mat4 textureMatrix;
mat4 shadow_mv_matrix;
mat4 shadow_proj_matrix[4];
mat4 envMatrix;
vec4 color;
model_light lights[MAX_LIGHTS];
float extrudeWidth;
float fogStart;
float fogScale;
int buffer_matrix_offset;
vec4 clip_equation;
float thruster_scale;
bool use_clip_plane;
int n_lights;
float defaultGloss;
vec3 ambientFactor;
int desaturate;
vec3 diffuseFactor;
int blend_alpha;
vec3 emissionFactor;
bool overrideDiffuse;
vec3 diffuseClr;
bool overrideGlow;
vec3 glowClr;
bool overrideSpec;
vec3 specClr;
bool alphaGloss;
bool gammaSpec;
bool envGloss;
bool alpha_spec;
int effect_num;
vec4 fogColor;
vec3 base_color;
float anim_timer;
vec3 stripe_color;
float vpwidth;
float vpheight;
bool team_glow_enabled;
float znear;
float zfar;
float veryneardist;
float neardist;
float middist;
float fardist;
vec2 normalAlphaMinMax;
int sBasemapIndex;
int sGlowmapIndex;
int sSpecmapIndex;
int sNormalmapIndex;
int sAmbientmapIndex;
int sMiscmapIndex;
};
#endif
in VertexOutput {
#ifdef FLAG_ENV_MAP
vec3 envReflect;
#endif
#ifdef FLAG_NORMAL_MAP
mat3 tangentMatrix;
#endif
#ifdef FLAG_FOG
float fogDist;
#endif
#ifdef WORKAROUND_CLIPPING_PLANES
#ifdef FLAG_TRANSFORM
float notVisible;
#endif
#endif
#ifdef FLAG_SHADOW_MAP
#if !defined(GL_ARB_gpu_shader5)
float instance;
#endif
#else
vec4 position;
#endif
vec3 normal;
vec4 texCoord;
#ifdef FLAG_SHADOWS
vec4 shadowUV[4];
vec4 shadowPos;
#endif
} vertIn[];
out VertexOutput {
#ifdef FLAG_ENV_MAP
vec3 envReflect;
#endif
#ifdef FLAG_NORMAL_MAP
mat3 tangentMatrix;
#endif
#ifdef FLAG_FOG
float fogDist;
#endif
#ifdef WORKAROUND_CLIPPING_PLANES
#ifdef FLAG_TRANSFORM
float notVisible;
#endif
#endif
vec4 position;
vec3 normal;
vec4 texCoord;
#ifdef FLAG_SHADOWS
vec4 shadowUV[4];
vec4 shadowPos;
#endif
} vertOut;
void main(void)
{
#ifdef GL_ARB_gpu_shader5
int instanceID = gl_InvocationID;
#else
int instanceID = int(vertIn[0].instance);
#endif
for(int vert = 0; vert < gl_in.length(); vert++)
{
gl_Position = shadow_proj_matrix[instanceID] * gl_in[vert].gl_Position;
if(gl_Position.z < -1.0)
gl_Position.z = -1.0;
vertOut.position = gl_in[vert].gl_Position;
vertOut.normal = vertIn[vert].normal;
vertOut.texCoord = vertIn[vert].texCoord;
gl_Layer = instanceID;
#ifdef FLAG_ENV_MAP
vertOut.envReflect = vertIn[vert].envReflect;
#endif
#ifdef FLAG_NORMAL_MAP
vertOut.tangentMatrix = vertIn[vert].tangentMatrix;
#endif
#ifdef FLAG_FOG
vertOut.fogDist = vertIn[vert].fogDist;
#endif
#ifdef FLAG_SHADOWS
vertOut.shadowUV[0] = vertIn[vert].shadowUV[0];
vertOut.shadowUV[1] = vertIn[vert].shadowUV[1];
vertOut.shadowUV[2] = vertIn[vert].shadowUV[2];
vertOut.shadowUV[3] = vertIn[vert].shadowUV[3];
vertOut.shadowPos = vertIn[vert].shadowPos;
#endif
#ifdef WORKAROUND_CLIPPING_PLANES
#ifdef FLAG_TRANSFORM
vertOut.notVisible = vertIn[vert].notVisible;
#endif
#ifdef FLAG_CLIP
gl_ClipDistance[0] = gl_in[vert].gl_ClipDistance[0];
#endif
#else
#if defined(FLAG_CLIP) || defined(FLAG_TRANSFORM)
gl_ClipDistance[0] = gl_in[vert].gl_ClipDistance[0];
#endif
#endif
EmitVertex();
}
EndPrimitive();
}
-335
View File
@@ -1,335 +0,0 @@
#extension GL_ARB_gpu_shader5: enable
#ifdef FEATURE_BINDLESS_TEXTURES
#extension GL_ARB_bindless_texture : require
#endif
#include "shadows.sdr"
in vec4 vertPosition;
in vec4 vertTexCoord;
in vec3 vertNormal;
in vec4 vertTangent;
in float vertModelID;
#define MAX_LIGHTS 8
struct model_light {
vec4 position;
vec3 diffuse_color;
int light_type;
vec3 spec_color;
float attenuation;
vec3 direction;
};
#ifdef FEATURE_BINDLESS_TEXTURES
layout (std140) uniform modelData {
mat4 modelViewMatrix;
mat4 modelMatrix;
mat4 viewMatrix;
mat4 projMatrix;
mat4 textureMatrix;
mat4 shadow_mv_matrix;
mat4 shadow_proj_matrix[4];
mat4 envMatrix;
vec4 color;
model_light lights[MAX_LIGHTS];
float extrudeWidth;
float fogStart;
float fogScale;
int buffer_matrix_offset;
vec4 clip_equation;
float thruster_scale;
bool use_clip_plane;
int n_lights;
float defaultGloss;
vec3 ambientFactor;
int desaturate;
vec3 diffuseFactor;
int blend_alpha;
vec3 emissionFactor;
bool overrideDiffuse;
vec3 diffuseClr;
bool overrideGlow;
vec3 glowClr;
bool overrideSpec;
vec3 specClr;
bool alphaGloss;
bool gammaSpec;
bool envGloss;
bool alpha_spec;
int effect_num;
vec4 fogColor;
vec3 base_color;
float anim_timer;
vec3 stripe_color;
float vpwidth;
float vpheight;
bool team_glow_enabled;
float znear;
float zfar;
float veryneardist;
float neardist;
float middist;
float fardist;
vec2 normalAlphaMinMax;
int sBasemapIndex;
int sGlowmapIndex;
int sSpecmapIndex;
int sNormalmapIndex;
int sAmbientmapIndex;
int sMiscmapIndex;
sampler2DArray sBasemap;
sampler2DArray sGlowmap;
sampler2DArray sSpecmap;
samplerCube sEnvmap;
sampler2DArray sNormalmap;
sampler2DArray sAmbientmap;
sampler2DArray sMiscmap;
sampler2DArray sHeightmap;
};
#else
layout (std140) uniform modelData {
mat4 modelViewMatrix;
mat4 modelMatrix;
mat4 viewMatrix;
mat4 projMatrix;
mat4 textureMatrix;
mat4 shadow_mv_matrix;
mat4 shadow_proj_matrix[4];
mat4 envMatrix;
vec4 color;
model_light lights[MAX_LIGHTS];
float extrudeWidth;
float fogStart;
float fogScale;
int buffer_matrix_offset;
vec4 clip_equation;
float thruster_scale;
bool use_clip_plane;
int n_lights;
float defaultGloss;
vec3 ambientFactor;
int desaturate;
vec3 diffuseFactor;
int blend_alpha;
vec3 emissionFactor;
bool overrideDiffuse;
vec3 diffuseClr;
bool overrideGlow;
vec3 glowClr;
bool overrideSpec;
vec3 specClr;
bool alphaGloss;
bool gammaSpec;
bool envGloss;
bool alpha_spec;
int effect_num;
vec4 fogColor;
vec3 base_color;
float anim_timer;
vec3 stripe_color;
float vpwidth;
float vpheight;
bool team_glow_enabled;
float znear;
float zfar;
float veryneardist;
float neardist;
float middist;
float fardist;
vec2 normalAlphaMinMax;
int sBasemapIndex;
int sGlowmapIndex;
int sSpecmapIndex;
int sNormalmapIndex;
int sAmbientmapIndex;
int sMiscmapIndex;
};
#endif
uniform samplerBuffer transform_tex;
out VertexOutput {
#ifdef FLAG_ENV_MAP
vec3 envReflect;
#endif
#ifdef FLAG_NORMAL_MAP
mat3 tangentMatrix;
#endif
#ifdef FLAG_FOG
float fogDist;
#endif
#ifdef WORKAROUND_CLIPPING_PLANES
#ifdef FLAG_TRANSFORM
float notVisible;
#endif
#endif
#ifdef FLAG_SHADOW_MAP
#if !defined(GL_ARB_gpu_shader5)
float instance;
#endif
#else
vec4 position;
#endif
vec3 normal;
vec4 texCoord;
#ifdef FLAG_SHADOWS
vec4 shadowUV[4];
vec4 shadowPos;
#endif
} vertOut;
#ifdef FLAG_TRANSFORM
#define TEXELS_PER_MATRIX 4
void getModelTransform(inout mat4 transform, out bool invisible, int id, int matrix_offset)
{
transform[0] = texelFetch(transform_tex, (matrix_offset + id) * TEXELS_PER_MATRIX);
transform[1] = texelFetch(transform_tex, (matrix_offset + id) * TEXELS_PER_MATRIX + 1);
transform[2] = texelFetch(transform_tex, (matrix_offset + id) * TEXELS_PER_MATRIX + 2);
transform[3] = texelFetch(transform_tex, (matrix_offset + id) * TEXELS_PER_MATRIX + 3);
invisible = transform[3].w >= 0.9;
transform[3].w = 1.0;
}
#endif
void main()
{
vec4 position;
vec3 normal;
vec4 texCoord;
mat4 orient = mat4(1.0);
mat4 scale = mat4(1.0);
#ifdef WORKAROUND_CLIPPING_PLANES
#ifdef FLAG_TRANSFORM
bool clipModel;
getModelTransform(orient, clipModel, int(vertModelID), buffer_matrix_offset);
vertOut.notVisible = clipModel ? 1.0 : 0.0;
#endif
#else
#ifdef FLAG_TRANSFORM
bool clipModel;
getModelTransform(orient, clipModel, int(vertModelID), buffer_matrix_offset);
#else
bool clipModel = false;
#endif
#endif
texCoord = textureMatrix * vertTexCoord;
vec4 vertex = vertPosition;
#ifdef FLAG_THRUSTER
if(vertex.z < -1.5) {
vertex.z *= thruster_scale;
}
#endif
// Transform the normal into eye space and normalize the result.
normal = normalize(mat3(modelViewMatrix) * mat3(orient) * vertNormal);
position = modelViewMatrix * orient * vertex;
#ifdef FLAG_SHADOW_MAP
gl_Position = position;
#if !defined(GL_ARB_gpu_shader5)
#ifdef APPLE
vertOut.instance = float(gl_InstanceIDARB);
#else
vertOut.instance = float(gl_InstanceID);
#endif
#endif
#else
gl_Position = projMatrix * position;
#endif
#ifdef FLAG_NORMAL_EXTRUDE
gl_Position.xy += (mat3(projMatrix) * normal.xyz).xy * gl_Position.z * extrudeWidth;
#endif
#ifdef FLAG_SHADOWS
vec4 shadowPos = shadow_mv_matrix * modelMatrix * orient * vertPosition;
vertOut.shadowPos = shadow_mv_matrix * modelMatrix * orient * vertPosition;
vertOut.shadowUV[0] = transformToShadowMap(shadow_proj_matrix[0], 0, shadowPos);
vertOut.shadowUV[1] = transformToShadowMap(shadow_proj_matrix[1], 1, shadowPos);
vertOut.shadowUV[2] = transformToShadowMap(shadow_proj_matrix[2], 2, shadowPos);
vertOut.shadowUV[3] = transformToShadowMap(shadow_proj_matrix[3], 3, shadowPos);
#endif
#ifdef FLAG_NORMAL_MAP
// Setup stuff for normal maps
vec3 t = normalize(mat3(modelViewMatrix) * mat3(orient) * vertTangent.xyz);
vec3 b = cross(normal, t) * vertTangent.w;
vertOut.tangentMatrix = mat3(t, b, normal);
#endif
#ifdef FLAG_ENV_MAP
// Environment mapping reflection vector.
vec3 envReflect = reflect(normalize(position.xyz), normal);
vertOut.envReflect = vec3(envMatrix * vec4(envReflect, 0.0));
#endif
#ifdef FLAG_FOG
vertOut.fogDist = clamp((gl_Position.z - fogStart) * 0.75 * fogScale, 0.0, 1.0);
#endif
#ifdef WORKAROUND_CLIPPING_PLANES
if(use_clip_plane) {
gl_ClipDistance[0] = dot(clip_equation, modelMatrix * orient * vertex);
} else {
gl_ClipDistance[0] = 1.0;
}
#else
#ifdef FLAG_CLIP
if (clipModel) {
gl_ClipDistance[0] = -1.0;
} else if(use_clip_plane) {
gl_ClipDistance[0] = dot(clip_equation, modelMatrix * orient * vertex);
} else {
gl_ClipDistance[0] = 1.0;
}
#elif defined(FLAG_TRANSFORM)
gl_ClipDistance[0] = clipModel ? -1.0 : 1.0;
#endif
#endif
#ifndef FLAG_SHADOW_MAP
vertOut.position = position;
vertOut.normal = normal;
vertOut.texCoord = texCoord;
#else
vertOut.normal = normal;
vertOut.texCoord = texCoord;
#endif
}
-95
View File
@@ -1,95 +0,0 @@
// Enabled at all times but the define is kept here in case this should be configurable in the future
#define EDGE_AA
layout(std140) uniform NanoVGUniformData {
mat3 scissorMat;
mat3 paintMat;
vec4 innerCol;
vec4 outerCol;
vec2 scissorExt;
vec2 scissorScale;
vec2 extent;
float radius;
float feather;
float strokeMult;
float strokeThr;
int texType;
int type;
vec2 viewSize;
int texArrayIndex;
};
uniform sampler2DArray nvg_tex;
in vec2 ftcoord;
in vec2 fpos;
out vec4 outColor;
float sdroundrect(vec2 pt, vec2 ext, float rad) {
vec2 ext2 = ext - vec2(rad,rad);
vec2 d = abs(pt) - ext2;
return min(max(d.x,d.y),0.0) + length(max(d,0.0)) - rad;
}
// Scissoring
float scissorMask(vec2 p) {
vec2 sc = (abs((scissorMat * vec3(p,1.0)).xy) - scissorExt);
sc = vec2(0.5,0.5) - sc * scissorScale;
return clamp(sc.x,0.0,1.0) * clamp(sc.y,0.0,1.0);
}
#ifdef EDGE_AA
// Stroke - from [0..1] to clipped pyramid, where the slope is 1px.
float strokeMask() {
return min(1.0, (1.0-abs(ftcoord.x*2.0-1.0))*strokeMult) * min(1.0, ftcoord.y);
}
#endif
void main(void) {
vec4 result;
float scissor = scissorMask(fpos);
#ifdef EDGE_AA
float strokeAlpha = strokeMask();
#else
float strokeAlpha = 1.0;
#endif
#ifdef EDGE_AA
if (strokeAlpha < strokeThr) {
discard;
}
#endif
if (type == 0) { // Gradient
// Calculate gradient color using box gradient
vec2 pt = (paintMat * vec3(fpos,1.0)).xy;
float d = clamp((sdroundrect(pt, extent, radius) + feather*0.5) / feather, 0.0, 1.0);
vec4 color = mix(innerCol,outerCol,d);
// Combine alpha
color *= strokeAlpha * scissor;
result = color;
} else if (type == 1) { // Image
// Calculate color fron texture
vec2 pt = (paintMat * vec3(fpos,1.0)).xy / extent;
vec4 color = texture(nvg_tex, vec3(pt, float(texArrayIndex)));
// Apply color tint and alpha.
if (texType == 1) color = vec4(color.xyz*color.w,color.w);
if (texType == 2) color = vec4(color.r);
color *= innerCol;
// Combine alpha
color *= strokeAlpha * scissor;
result = color;
} else if (type == 2) { // Stencil fill
result = vec4(1,1,1,1);
} else if (type == 3) { // Textured tris
vec4 color = texture(nvg_tex, vec3(ftcoord, float(texArrayIndex)));
if (texType == 1) color = vec4(color.xyz*color.w,color.w); if (texType == 2) color = vec4(color.x); color *= scissor;
result = color * innerCol;
}
outColor = result;
}
-37
View File
@@ -1,37 +0,0 @@
layout(std140) uniform NanoVGUniformData {
mat3 scissorMat;
mat3 paintMat;
vec4 innerCol;
vec4 outerCol;
vec2 scissorExt;
vec2 scissorScale;
vec2 extent;
float radius;
float feather;
float strokeMult;
float strokeThr;
int texType;
int type;
vec2 viewSize;
int texArrayIndex;
};
in vec2 vertPosition;
in vec2 vertTexCoord;
out vec2 ftcoord;
out vec2 fpos;
void main(void) {
ftcoord = vertTexCoord;
fpos = vertPosition;
gl_Position = vec4(2.0*vertPosition.x/viewSize.x - 1.0, 1.0 - 2.0*vertPosition.y/viewSize.y, 0, 1);
}
-12
View File
@@ -1,12 +0,0 @@
/**
* @brief Unpacks a DXT5nm encoded normal
* @param normal_sample The Alpha and Green channel of the DXT5 texture
* @return The unpacked normal
*/
vec3 unpackNormal(vec2 normal_sample) {
vec3 normal;
normal.xy = normal_sample * 2.0 - 1.0;
normal.z = sqrt(1 - normal_sample.x * normal_sample.x - normal_sample.y * normal_sample.y);
return normal;
}
@@ -1,18 +0,0 @@
#include "gamma.sdr"
in vec4 fragTexCoord;
in vec4 fragColor;
out vec4 fragOut0;
uniform sampler2D baseMap;
uniform int noTexturing;
uniform int srgb;
void main()
{
vec4 baseColor = texture(baseMap, fragTexCoord.xy);
baseColor.rgb = (srgb == 1) ? srgb_to_linear(baseColor.rgb) : baseColor.rgb;
vec4 blendColor = (srgb == 1) ? vec4(srgb_to_linear(fragColor.rgb), fragColor.a) : fragColor;
fragOut0 = mix(baseColor * blendColor, blendColor, float(noTexturing));
}
-105
View File
@@ -1,105 +0,0 @@
const float VARIANCE_SHADOW_SCALE = 1000000.0;
const float VARIANCE_SHADOW_SCALE_INV = 1.0/VARIANCE_SHADOW_SCALE;
vec2 sampleShadowMap(sampler2DArray shadow_map, vec2 uv, vec2 offset_uv, int cascade, float shadowMapSizeInv)
{
return texture(shadow_map, vec3(uv + offset_uv * shadowMapSizeInv, float(cascade))).xy;
}
float computeShadowFactor(float shadowDepth, vec2 moments, float bias)
{
float shadow = 1.0;
if((moments.x - bias) > shadowDepth)
{
// variance shadow mapping using Chebychev's Formula
float variance = moments.y * VARIANCE_SHADOW_SCALE - moments.x * moments.x;
float mD = moments.x - bias - shadowDepth;
shadow = variance / (variance + mD * mD);
shadow = clamp(shadow, 0.0, 1.0);
}
return shadow;
}
float sampleNoPCF(sampler2DArray shadow_map, float shadowDepth, int cascade, vec4 shadowUV[4])
{
return computeShadowFactor(shadowDepth, sampleShadowMap(shadow_map, shadowUV[cascade].xy, vec2(0.0, 0.0), cascade, 1.0/1024.0), 0.05);
}
float samplePoissonPCF(sampler2DArray shadow_map, float shadowDepth, int cascade, vec4 shadowUV[4])
{
if(cascade > 3 || cascade < 0) return 1.0;
vec2 poissonDisc[16];
poissonDisc[0] = vec2(-0.76275, -0.3432573);
poissonDisc[1] = vec2(-0.5226235, -0.8277544);
poissonDisc[2] = vec2(-0.3780261, 0.01528688);
poissonDisc[3] = vec2(-0.7742821, 0.4245702);
poissonDisc[4] = vec2(0.04196143, -0.02622231);
poissonDisc[5] = vec2(-0.2974772, -0.4722782);
poissonDisc[6] = vec2(-0.516093, 0.71495);
poissonDisc[7] = vec2(-0.3257416, 0.3910343);
poissonDisc[8] = vec2(0.2705966, 0.6670476);
poissonDisc[9] = vec2(0.4918377, 0.1853267);
poissonDisc[10] = vec2(0.4428544, -0.6251478);
poissonDisc[11] = vec2(-0.09204347, 0.9267113);
poissonDisc[12] = vec2(0.391505, -0.2558275);
poissonDisc[13] = vec2(0.05605913, -0.7570801);
poissonDisc[14] = vec2(0.81772, -0.02475523);
poissonDisc[15] = vec2(0.6890262, 0.5191521);
float maxUVOffset[4];
maxUVOffset[0] = 1.0/300.0;
maxUVOffset[1] = 1.0/250.0;
maxUVOffset[2] = 1.0/200.0;
maxUVOffset[3] = 1.0/200.0;
vec2 sum = sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[0], cascade, maxUVOffset[cascade])*(1.0/16.0);
sum += sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[1], cascade, maxUVOffset[cascade])*(1.0/16.0);
sum += sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[2], cascade, maxUVOffset[cascade])*(1.0/16.0);
sum += sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[3], cascade, maxUVOffset[cascade])*(1.0/16.0);
sum += sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[4], cascade, maxUVOffset[cascade])*(1.0/16.0);
sum += sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[5], cascade, maxUVOffset[cascade])*(1.0/16.0);
sum += sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[6], cascade, maxUVOffset[cascade])*(1.0/16.0);
sum += sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[7], cascade, maxUVOffset[cascade])*(1.0/16.0);
sum += sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[8], cascade, maxUVOffset[cascade])*(1.0/16.0);
sum += sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[9], cascade, maxUVOffset[cascade])*(1.0/16.0);
sum += sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[10], cascade, maxUVOffset[cascade])*(1.0/16.0);
sum += sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[11], cascade, maxUVOffset[cascade])*(1.0/16.0);
sum += sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[12], cascade, maxUVOffset[cascade])*(1.0/16.0);
sum += sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[13], cascade, maxUVOffset[cascade])*(1.0/16.0);
sum += sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[14], cascade, maxUVOffset[cascade])*(1.0/16.0);
sum += sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[15], cascade, maxUVOffset[cascade])*(1.0/16.0);
return computeShadowFactor(shadowDepth, sum, 0.1);
}
float getShadowValue(sampler2DArray shadow_map, float depth, float shadowDepth, vec4 shadowUV[4], float fardist,
float middist, float neardist, float veryneardist)
{
// Valathil's Shadows
int cascade = 4;
cascade -= int(step(depth, fardist));
cascade -= int(step(depth, middist));
cascade -= int(step(depth, neardist));
cascade -= int(step(depth, veryneardist));
float cascade_start_dist[5];
cascade_start_dist[0] = 0.0;
cascade_start_dist[1] = veryneardist;
cascade_start_dist[2] = neardist;
cascade_start_dist[3] = middist;
cascade_start_dist[4] = fardist;
if(cascade > 3 || cascade < 0) return 1.0;
float dist_threshold = (cascade_start_dist[cascade+1] - cascade_start_dist[cascade])*0.2;
if(cascade_start_dist[cascade+1] - dist_threshold > depth)
return samplePoissonPCF(shadow_map, shadowDepth, cascade, shadowUV);
return mix(samplePoissonPCF(shadow_map, shadowDepth, cascade, shadowUV), samplePoissonPCF(shadow_map, shadowDepth, cascade+1, shadowUV),
smoothstep(cascade_start_dist[cascade+1] - dist_threshold, cascade_start_dist[cascade+1], depth));
}
vec4 transformToShadowMap(mat4 shadow_proj_matrix, int i, vec4 pos)
{
vec4 shadow_proj;
shadow_proj = shadow_proj_matrix * pos;
shadow_proj += 1.0;
shadow_proj *= 0.5;
shadow_proj.w = shadow_proj.z;
shadow_proj.z = float(i);
return shadow_proj;
}
@@ -1,21 +0,0 @@
#include "gamma.sdr"
in vec4 fragImpactUV;
in float fragNormOffset;
uniform vec4 color;
uniform sampler2DArray shieldMap;
uniform int shieldMapIndex;
uniform int srgb;
out vec4 fragOut0;
#define EMISSIVE_GAIN 2.0
void main()
{
if(fragNormOffset < 0.0) discard;
if(fragImpactUV.x < 0.0 || fragImpactUV.x > 1.0 || fragImpactUV.y < 0.0 || fragImpactUV.y > 1.0) discard;
vec4 shieldColor = texture(shieldMap, vec3(fragImpactUV.xy, float(shieldMapIndex)));
shieldColor.rgb = (srgb == 1) ? srgb_to_linear(shieldColor.rgb) * EMISSIVE_GAIN : shieldColor.rgb;
vec4 blendColor = color;
blendColor.rgb = (srgb == 1) ? srgb_to_linear(blendColor.rgb) * EMISSIVE_GAIN : blendColor.rgb;
fragOut0 = shieldColor * blendColor;
}
-16
View File
@@ -1,16 +0,0 @@
in vec4 fragTexCoord;
out vec4 fragOut0;
uniform sampler2DArray ytex;
uniform sampler2DArray utex;
uniform sampler2DArray vtex;
void main()
{
float y = texture(ytex, vec3(fragTexCoord.st, 0.0)).r;
float u = texture(utex, vec3(fragTexCoord.st, 0.0)).r;
float v = texture(vtex, vec3(fragTexCoord.st, 0.0)).r;
vec3 val = vec3(y - 0.0625, u - 0.5, v - 0.5);
fragOut0.r = dot(val, vec3(1.1640625, 0.0, 1.59765625));
fragOut0.g = dot(val, vec3(1.1640625, -0.390625, -0.8125));
fragOut0.b = dot(val, vec3(1.1640625, 2.015625, 0.0));
fragOut0.a = 1.0;
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

@@ -1,2 +0,0 @@
#ControlConfigOverride
#End
-19
View File
@@ -10,7 +10,6 @@
struct def_file
{
const char* path_type;
const char* filename;
const void* contents;
const size_t size;
@@ -27,8 +26,6 @@ default_file defaults_get_file(const char *filename)
{
if (!stricmp(iter->filename, filename))
{
def.path_type = iter->path_type;
def.filename = iter->filename;
def.data = iter->contents;
def.size = iter->size;
@@ -40,19 +37,3 @@ default_file defaults_get_file(const char *filename)
Error(LOCATION, "Default table '%s' missing from executable - contact a coder.", filename);
return def;
}
SCP_vector<default_file> defaults_get_all() {
SCP_vector<default_file> files;
for (auto& file : Default_files) {
default_file def;
def.path_type = file.path_type;
def.filename = file.filename;
def.data = file.contents;
def.size = file.size;
files.push_back(def);
}
return files;
}
-34
View File
@@ -13,7 +13,6 @@
struct def_file
{
const char* path_type;
const char* filename;
const TCHAR* resource_name;
};
@@ -46,8 +45,6 @@ default_file defaults_get_file(const char *filename)
continue;
}
def.path_type = iter->path_type;
def.filename = iter->filename;
def.data = LockResource(resHandle);
def.size = SizeofResource(nullptr, resource);
@@ -62,34 +59,3 @@ default_file defaults_get_file(const char *filename)
def.data = 0;
return def;
}
SCP_vector<default_file> defaults_get_all() {
SCP_vector<default_file> files;
for (auto& file : Default_files) {
default_file def;
HRSRC resource = FindResource(nullptr, file.resource_name, RT_RCDATA);
if (resource == nullptr)
{
continue;
}
HGLOBAL resHandle = LoadResource(nullptr, resource);
if (resHandle == nullptr)
{
continue;
}
def.path_type = file.path_type;
def.filename = file.filename;
def.data = LockResource(resHandle);
def.size = SizeofResource(nullptr, resource);
files.push_back(def);
}
return files;
}
+6 -3
View File
@@ -15,8 +15,6 @@
struct default_file
{
const char* path_type;
const char* filename;
const void* data;
size_t size;
};
@@ -24,6 +22,11 @@ struct default_file
//Used to retrieve pointer to file data from def_files.cpp
default_file defaults_get_file(const char *filename);
SCP_vector<default_file> defaults_get_all();
//WMC -
//There are three parts to adding a file
//:PART 1: Add variable declaration for new file
//:PART 2: Add filename of default file to Default_files[] array, along with content variable
//:PART 3: Define the content using the variable declared in part 1.
//Do a search in def_files.cpp for the individual part labels for examples and locations.
#endif
@@ -2,12 +2,10 @@ out vec4 fragOut0;
out vec4 fragOut1;
out vec4 fragOut2;
out vec4 fragOut3;
out vec4 fragOut4;
void main()
{
fragOut0 = vec4(0.0, 0.0, 0.0, 1.0); // color
fragOut1 = vec4(0.0, 0.0, -1000000.0, 1.0); // position
fragOut2 = vec4(0.0, 0.0, 0.0, 1.0); // normal
fragOut3 = vec4(0.0, 0.0, 0.0, 0.0); // specular
fragOut4 = vec4(0.0, 0.0, 0.0, 1.0); // emissive
}
}
+96
View File
@@ -0,0 +1,96 @@
in vec3 beamVec;
in vec3 lightPosition;
out vec4 fragOut0;
uniform sampler2D ColorBuffer;
uniform sampler2D NormalBuffer;
uniform sampler2D PositionBuffer;
uniform sampler2D SpecBuffer;
uniform float specFactor;
uniform float invScreenWidth;
uniform float invScreenHeight;
uniform int lightType;
uniform float lightRadius;
uniform vec3 diffuseLightColor;
uniform vec3 specLightColor;
uniform float coneAngle;
uniform float coneInnerAngle;
uniform bool dualCone;
uniform vec3 coneDir;
#define SPEC_INTENSITY_POINT 5.3 // Point light
#define SPEC_INTENSITY_DIRECTIONAL 3.0 // Directional light
#define SPECULAR_FACTOR 1.75
#define SPECULAR_ALPHA 0.1
#define SPEC_FACTOR_NO_SPEC_MAP 0.6
#define ENV_ALPHA_FACTOR 0.3
#define GLOW_MAP_INTENSITY 1.5
#define AMBIENT_LIGHT_BOOST 1.0
vec3 FresnelSchlick(vec3 specColor, vec3 light, vec3 halfVec)
{
return specColor + (vec3(1.0) - specColor) * pow(1.0 - clamp(dot(light, halfVec), 0.0, 1.0), 5.0);
}
vec3 SpecularBlinnPhong(vec3 specColor, vec3 light, vec3 normal, vec3 halfVec, float specPower, float fresnel, float dotNL)
{
return mix(specColor, FresnelSchlick(specColor, light, halfVec), fresnel) * ((specPower + 2.0) / 8.0 ) * pow(clamp(dot(normal, halfVec), 0.0, 1.0), specPower) * dotNL;
}
vec4 SpecularLegacy(vec4 specColor, vec3 normal, vec3 halfVec, float specPower)
{
return specColor * pow(clamp(dot(normal, halfVec), 0.0, 1.0), specPower);
}
void main()
{
vec2 screenPos = gl_FragCoord.xy * vec2(invScreenWidth, invScreenHeight);
vec3 position = texture(PositionBuffer, screenPos).xyz;
if(abs(dot(position, position)) < 0.1)
discard;
vec3 lightDir = lightPosition - position.xyz;
float dist = length(lightDir);
if(dist > lightRadius && lightType != 1)
discard;
vec3 color = texture(ColorBuffer, screenPos).rgb;
vec4 normal = texture(NormalBuffer, screenPos);
vec4 specColor = texture(SpecBuffer, screenPos);
float gloss = normal.a;
float fresnel = specColor.a;
vec3 eyeDir = normalize(-position);
if(lightType == 1)
{
float beamLength = length(beamVec);
vec3 beamDir = beamVec / beamLength;
// Get nearest point on line
float neardist = clamp(dot(lightDir, beamDir), 0.0, beamLength);
// Move back from the endpoint of the beam along the beam by the distance we calculated
vec3 nearest = lightPosition - beamDir * neardist;
lightDir = nearest - position.xyz;
dist = length(lightDir);
if(dist > lightRadius)
discard;
}
float attenuation = 1.0 - clamp(dist / lightRadius, 0.0, 1.0);
if(lightType == 2)
{
float coneDot = dot(normalize(-lightDir), coneDir);
if(dualCone) {
if(abs(coneDot) < coneAngle)
discard;
else
attenuation *= smoothstep(coneAngle, coneInnerAngle, abs(coneDot));
} else {
if(coneDot < coneAngle)
discard;
else
attenuation *= smoothstep(coneAngle, coneInnerAngle, coneDot);
}
}
lightDir /= dist;
vec3 halfVec = normalize(lightDir + eyeDir);
float NdotL = clamp(dot(normal.xyz, lightDir), 0.0, 1.0);
vec4 fragmentColor = vec4(color * (diffuseLightColor * NdotL * attenuation), 1.0);
fragmentColor.rgb += SpecularBlinnPhong(specColor.rgb, lightDir, normal.xyz, halfVec, exp2(10.0 * gloss + 1.0), fresnel, NdotL).rgb * specLightColor * attenuation;
fragOut0 = max(fragmentColor, vec4(0.0));
}
+14
View File
@@ -0,0 +1,14 @@
in vec4 vertPosition;
uniform mat4 modelViewMatrix;
uniform mat4 projMatrix;
uniform vec3 scale;
uniform int lightType;
out vec3 lightPosition;
out vec3 beamVec;
void main()
{
gl_Position = projMatrix * modelViewMatrix * vec4(vertPosition.xyz * scale, 1.0);
lightPosition = modelViewMatrix[3].xyz;
if(lightType == 1)
beamVec = vec3(modelViewMatrix * vec4(0.0, 0.0, -scale.z, 0.0));
}
@@ -2,7 +2,7 @@ in vec4 fragTexCoord;
in vec4 fragColor;
in float fragOffset;
out vec4 fragOut0;
uniform sampler2DArray baseMap;
uniform sampler2D baseMap;
uniform sampler2D depthMap;
uniform float window_width;
uniform float window_height;
@@ -11,10 +11,10 @@ uniform sampler2D frameBuffer;
void main()
{
vec2 depthCoord = vec2(gl_FragCoord.x / window_width, gl_FragCoord.y / window_height);
vec4 fragmentColor = texture(baseMap, fragTexCoord.xyz) * fragColor.a;
vec4 fragmentColor = texture(baseMap, fragTexCoord.xy) * fragColor.a;
vec2 distortion = texture(distMap, fragTexCoord.xy+vec2(0.0, fragOffset)).rg;
float alpha = clamp(dot(fragmentColor.rgb,vec3(0.3333))*10.0,0.0,1.0);
distortion = ((distortion - 0.5) * 0.01) * alpha;
fragOut0 = texture(frameBuffer,depthCoord+distortion);
fragOut0.a = alpha;
}
}
@@ -12,6 +12,6 @@ void main()
{
gl_Position = projMatrix * modelViewMatrix * vertPosition;
fragOffset = vertRadius * use_offset;
fragTexCoord = vec4(vertTexCoord.xyz, 0.0);
fragTexCoord = vertTexCoord;
fragColor = vertColor;
}
}
Loaded 100 of 715 files, more files were not shown because too many files have changed in this diff. Show more